X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=perlio.c;h=e36a7308c0dbce3aec5289aab6fb2e796aa50c1d;hb=075502290ff69af888b5629ff1fecf91d588fbbd;hp=7c16e435b0cfd1cc317e93a144f4951c34a8620d;hpb=293ed4d2d77af94fb636abf7295b5e2dd98c1695;p=p5sagit%2Fp5-mst-13.2.git diff --git a/perlio.c b/perlio.c index 7c16e43..e36a730 100644 --- a/perlio.c +++ b/perlio.c @@ -1,10 +1,21 @@ /* - * perlio.c Copyright (c) 1996-2001, Nick Ing-Simmons You may distribute + * perlio.c Copyright (c) 1996-2005, 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. */ /* + * Hour after hour for nearly three weary days he had jogged up and down, + * over passes, and through long dales, and across many streams. + */ + +/* This file contains the functions needed to implement PerlIO, which + * is Perl's private replacement for the C stdio library. This is used + * by default unless you compile with -Uuseperlio or run with + * PERLIO=:stdio (but don't do this unless you know what you're doing) + */ + +/* * 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 @@ -45,6 +56,63 @@ #include "XSUB.h" +#define PERLIO_MAX_REFCOUNTABLE_FD 2048 + +#ifdef __Lynx__ +/* Missing proto on LynxOS */ +int mkstemp(char*); +#endif + +/* Call the callback or PerlIOBase, and return failure. */ +#define Perl_PerlIO_or_Base(f, callback, base, failure, args) \ + if (PerlIOValid(f)) { \ + const PerlIO_funcs * const tab = PerlIOBase(f)->tab;\ + if (tab && tab->callback) \ + return (*tab->callback) args; \ + else \ + return PerlIOBase_ ## base args; \ + } \ + else \ + SETERRNO(EBADF, SS_IVCHAN); \ + return failure + +/* Call the callback or fail, and return failure. */ +#define Perl_PerlIO_or_fail(f, callback, failure, args) \ + if (PerlIOValid(f)) { \ + const PerlIO_funcs * const tab = PerlIOBase(f)->tab;\ + if (tab && tab->callback) \ + return (*tab->callback) args; \ + SETERRNO(EINVAL, LIB_INVARG); \ + } \ + else \ + SETERRNO(EBADF, SS_IVCHAN); \ + return failure + +/* Call the callback or PerlIOBase, and be void. */ +#define Perl_PerlIO_or_Base_void(f, callback, base, args) \ + if (PerlIOValid(f)) { \ + const PerlIO_funcs * const tab = PerlIOBase(f)->tab;\ + if (tab && tab->callback) \ + (*tab->callback) args; \ + else \ + PerlIOBase_ ## base args; \ + } \ + else \ + SETERRNO(EBADF, SS_IVCHAN) + +/* Call the callback or fail, and be void. */ +#define Perl_PerlIO_or_fail_void(f, callback, args) \ + if (PerlIOValid(f)) { \ + const PerlIO_funcs * const tab = PerlIOBase(f)->tab;\ + if (tab && tab->callback) \ + (*tab->callback) args; \ + else \ + SETERRNO(EINVAL, LIB_INVARG); \ + } \ + else \ + SETERRNO(EBADF, SS_IVCHAN) + +#ifndef USE_SFIO int perlsio_binmode(FILE *fp, int iotype, int mode) { @@ -89,24 +157,29 @@ perlsio_binmode(FILE *fp, int iotype, int mode) # endif #else # if defined(USEMYBINMODE) + dTHX; if (my_binmode(fp, iotype, mode) != FALSE) return 1; else return 0; # else + PERL_UNUSED_ARG(fp); + PERL_UNUSED_ARG(iotype); + PERL_UNUSED_ARG(mode); return 1; # endif #endif } +#endif /* sfio */ #ifndef O_ACCMODE -#define O_ACCMODE 3 /* Assume traditional implementation */ +#define O_ACCMODE 3 /* Assume traditional implementation */ #endif int PerlIO_intmode2str(int rawmode, char *mode, int *writing) { - int result = rawmode & O_ACCMODE; + const int result = rawmode & O_ACCMODE; int ix = 0; int ptype; switch (result) { @@ -152,7 +225,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); @@ -171,6 +248,9 @@ int PerlIO_binmode(pTHX_ PerlIO *fp, int iotype, int mode, const char *names) { #ifdef USE_SFIO + PERL_UNUSED_ARG(iotype); + PERL_UNUSED_ARG(mode); + PERL_UNUSED_ARG(names); return 1; #else return perlsio_binmode(fp, iotype, mode); @@ -180,12 +260,23 @@ 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 +#if defined(PERL_MICRO) || defined(SYMBIAN) + 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)); + const int fd = PerlLIO_dup(PerlIO_fileno(f)); if (fd >= 0) { char mode[8]; int omode = fcntl(fd, F_GETFL); +#ifdef DJGPP + omode = djgpp_get_stream_mode(f); +#endif PerlIO_intmode2str(omode,mode,NULL); /* the r+ is a hack */ return PerlIO_fdopen(fd, mode); @@ -193,10 +284,12 @@ PerlIO_fdupopen(pTHX_ PerlIO *f, CLONE_PARAMS *param, int flags) return NULL; } else { - SETERRNO(EBADF, SS$_IVCHAN); + SETERRNO(EBADF, SS_IVCHAN); } #endif return NULL; +#endif +#endif } @@ -208,15 +301,18 @@ PerlIO * PerlIO_openn(pTHX_ const char *layers, const char *mode, int fd, int imode, int perm, PerlIO *old, int narg, SV **args) { - if (narg == 1) { + if (narg) { + if (narg > 1) { + Perl_croak(aTHX_ "More than one argument to open"); + } if (*args == &PL_sv_undef) return PerlIO_tmpfile(); else { - char *name = SvPV_nolen(*args); - if (*mode == '#') { + const char *name = SvPV_nolen_const(*args); + if (*mode == IoTYPE_NUMERIC) { fd = PerlLIO_open3(name, imode, perm); if (fd >= 0) - return PerlIO_fdopen(fd, (char *) mode + 1); + return PerlIO_fdopen(fd, mode + 1); } else if (old) { return PerlIO_reopen(name, mode, old); @@ -238,7 +334,7 @@ XS(XS_PerlIO__Layer__find) if (items < 2) Perl_croak(aTHX_ "Usage class->find(name[,load])"); else { - char *name = SvPV_nolen(ST(1)); + const char *name = SvPV_nolen_const(ST(1)); ST(0) = (strEQ(name, "crlf") || strEQ(name, "raw")) ? &PL_sv_yes : &PL_sv_undef; XSRETURN(1); @@ -275,7 +371,7 @@ PerlIO_tmpfile(void) return tmpfile(); } -#else /* PERLIO_IS_STDIO */ +#else /* PERLIO_IS_STDIO */ #ifdef USE_SFIO @@ -311,19 +407,22 @@ 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; + const int fd = fileno(stdio); + if (!mode || !*mode) { + mode = "r+"; + } + return PerlIO_fdopen(fd, mode); } FILE * PerlIO_findFILE(PerlIO *pio) { - int fd = PerlIO_fileno(pio); - FILE *f = fdopen(fd, "r+"); + const int fd = PerlIO_fileno(pio); + FILE * const f = fdopen(fd, "r+"); PerlIO_flush(pio); if (!f && errno == EINVAL) f = fdopen(fd, "w"); @@ -333,7 +432,7 @@ PerlIO_findFILE(PerlIO *pio) } -#else /* USE_SFIO */ +#else /* USE_SFIO */ /*======================================================================================*/ /* * Implement all the PerlIO interface ourselves. @@ -352,51 +451,41 @@ PerlIO_findFILE(PerlIO *pio) #include #endif - -void PerlIO_debug(const char *fmt, ...) - __attribute__ ((format(__printf__, 1, 2))); - void PerlIO_debug(const char *fmt, ...) { - static int dbg = 0; va_list ap; dSYS; va_start(ap, fmt); - if (!dbg) { - char *s = PerlEnv_getenv("PERLIO_DEBUG"); + if (!PL_perlio_debug_fd && !PL_tainting && PL_uid == PL_euid && PL_gid == PL_egid) { + const char *s = PerlEnv_getenv("PERLIO_DEBUG"); if (s && *s) - dbg = PerlLIO_open3(s, O_WRONLY | O_CREAT | O_APPEND, 0666); + PL_perlio_debug_fd = PerlLIO_open3(s, O_WRONLY | O_CREAT | O_APPEND, 0666); else - dbg = -1; + PL_perlio_debug_fd = -1; } - if (dbg > 0) { + if (PL_perlio_debug_fd > 0) { dTHX; + const char *s = CopFILE(PL_curcop); + STRLEN len; #ifdef USE_ITHREADS /* Use fixed buffer as sv_catpvf etc. needs SVs */ char buffer[1024]; - char *s; - STRLEN len; - s = CopFILE(PL_curcop); if (!s) s = "(none)"; - sprintf(buffer, "%s:%" IVdf " ", s, (IV) CopLINE(PL_curcop)); - len = strlen(buffer); + len = sprintf(buffer, "%.40s:%" IVdf " ", s, (IV) CopLINE(PL_curcop)); vsprintf(buffer+len, fmt, ap); - PerlLIO_write(dbg, buffer, strlen(buffer)); + PerlLIO_write(PL_perlio_debug_fd, buffer, strlen(buffer)); #else SV *sv = newSVpvn("", 0); - char *s; - STRLEN len; - s = CopFILE(PL_curcop); if (!s) s = "(none)"; Perl_sv_catpvf(aTHX_ sv, "%s:%" IVdf " ", s, (IV) CopLINE(PL_curcop)); Perl_sv_vcatpvf(aTHX_ sv, fmt, &ap); - s = SvPV(sv, len); - PerlLIO_write(dbg, s, len); + s = SvPV_const(sv, len); + PerlLIO_write(PL_perlio_debug_fd, s, len); SvREFCNT_dec(sv); #endif } @@ -432,7 +521,7 @@ PerlIO_allocate(pTHX) } } } - Newz('I',f,PERLIO_TABLE_SIZE,PerlIO); + Newxz(f,PERLIO_TABLE_SIZE,PerlIO); if (!f) { return NULL; } @@ -444,17 +533,19 @@ PerlIO_allocate(pTHX) PerlIO * PerlIO_fdupopen(pTHX_ PerlIO *f, CLONE_PARAMS *param, int flags) { - if (f && *f) { - PerlIO_funcs *tab = PerlIOBase(f)->tab; - PerlIO *new; - PerlIO_debug("fdupopen f=%p param=%p\n",f,param); - new = (*tab->Dup)(aTHX_ PerlIO_allocate(aTHX),f,param, flags); - return new; - } - else { - SETERRNO(EBADF, SS$_IVCHAN); - return NULL; + if (PerlIOValid(f)) { + const PerlIO_funcs * const tab = PerlIOBase(f)->tab; + PerlIO_debug("fdupopen f=%p param=%p\n",(void*)f,(void*)param); + if (tab && tab->Dup) + return (*tab->Dup)(aTHX_ PerlIO_allocate(aTHX), f, param, flags); + else { + return PerlIOBase_dup(aTHX_ PerlIO_allocate(aTHX), f, param, flags); + } } + else + SETERRNO(EBADF, SS_IVCHAN); + + return NULL; } void @@ -480,7 +571,7 @@ PerlIO_list_t * PerlIO_list_alloc(pTHX) { PerlIO_list_t *list; - Newz('L', list, 1, PerlIO_list_t); + Newxz(list, 1, PerlIO_list_t); list->refcnt = 1; return list; } @@ -512,12 +603,12 @@ PerlIO_list_push(pTHX_ PerlIO_list_t *list, PerlIO_funcs *funcs, SV *arg) if (list->array) Renew(list->array, list->len, PerlIO_pair_t); else - New('l', list->array, list->len, PerlIO_pair_t); + Newx(list->array, list->len, PerlIO_pair_t); } p = &(list->array[list->cur++]); p->funcs = funcs; if ((p->arg = arg)) { - SvREFCNT_inc(arg); + (void)SvREFCNT_inc(arg); } } @@ -559,6 +650,9 @@ PerlIO_clone(pTHX_ PerlInterpreter *proto, CLONE_PARAMS *param) f++; } } +#else + PERL_UNUSED_ARG(proto); + PERL_UNUSED_ARG(param); #endif } @@ -589,10 +683,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 @@ -600,21 +690,50 @@ PerlIO_pop(pTHX_ PerlIO *f) { PerlIOl *l = *f; if (l) { - PerlIO_debug("PerlIO_pop f=%p %s\n", f, l->tab->name); + PerlIO_debug("PerlIO_pop f=%p %s\n", (void*)f, l->tab->name); if (l->tab->Popped) { /* * If popped returns non-zero do not free its layer structure * it has either done so itself, or it is shared and still in * use */ - if ((*l->tab->Popped) (f) != 0) + if ((*l->tab->Popped) (aTHX_ f) != 0) return; } - *f = l->next;; + *f = l->next; Safefree(l); } } +/* Return as an array the stack of layers on a filehandle. Note that + * the stack is returned top-first in the array, and there are three + * times as many array elements as there are layers in the stack: the + * first element of a layer triplet is the name, the second one is the + * arguments, and the third one is the flags. */ + +AV * +PerlIO_get_layers(pTHX_ PerlIO *f) +{ + AV *av = newAV(); + + if (PerlIOValid(f)) { + PerlIOl *l = PerlIOBase(f); + + while (l) { + SV *name = l->tab && l->tab->name ? + newSVpv(l->tab->name, 0) : &PL_sv_undef; + SV *arg = l->tab && l->tab->Getarg ? + (*l->tab->Getarg)(aTHX_ &l, 0, 0) : &PL_sv_undef; + av_push(av, name); + av_push(av, arg); + av_push(av, newSViv((IV)l->flags)); + l = l->next; + } + } + + return av; +} + /*--------------------------------------------------------------------------------------*/ /* * XS Interface for perl code @@ -623,27 +742,42 @@ PerlIO_pop(pTHX_ PerlIO *f) PerlIO_funcs * PerlIO_find_layer(pTHX_ const char *name, STRLEN len, int load) { + dVAR; IV i; if ((SSize_t) len <= 0) len = strlen(name); for (i = 0; i < PL_known_layers->cur; i++) { - PerlIO_funcs *f = PL_known_layers->array[i].funcs; - if (memEQ(f->name, name, len)) { - PerlIO_debug("%.*s => %p\n", (int) len, name, f); + PerlIO_funcs * const f = PL_known_layers->array[i].funcs; + if (memEQ(f->name, name, len) && f->name[len] == 0) { + PerlIO_debug("%.*s => %p\n", (int) len, name, (void*)f); return f; } } if (load && PL_subname && PL_def_layerlist && PL_def_layerlist->cur >= 2) { - SV *pkgsv = newSVpvn("PerlIO", 6); - SV *layer = newSVpvn(name, len); - ENTER; - /* - * The two SVs are magically freed by load_module - */ - Perl_load_module(aTHX_ 0, pkgsv, Nullsv, layer, Nullsv); - LEAVE; - return PerlIO_find_layer(aTHX_ name, len, 0); + if (PL_in_load_module) { + Perl_croak(aTHX_ "Recursive call to Perl_load_module in PerlIO_find_layer"); + return NULL; + } else { + SV * const pkgsv = newSVpvn("PerlIO", 6); + SV * const layer = newSVpvn(name, len); + CV * const cv = get_cv("PerlIO::Layer::NoWarnings", FALSE); + ENTER; + SAVEINT(PL_in_load_module); + if (cv) { + SAVEGENERICSV(PL_warnhook); + (void)SvREFCNT_inc(cv); + PL_warnhook = (SV *) cv; + } + PL_in_load_module++; + /* + * The two SVs are magically freed by load_module + */ + Perl_load_module(aTHX_ 0, pkgsv, Nullsv, layer, Nullsv); + PL_in_load_module--; + LEAVE; + return PerlIO_find_layer(aTHX_ name, len, 0); + } } PerlIO_debug("Cannot find %.*s\n", (int) len, name); return NULL; @@ -692,7 +826,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 }; @@ -713,7 +847,7 @@ XS(XS_io_MODIFY_SCALAR_ATTRIBUTES) Perl_warn(aTHX_ "attrib %" SVf, sv); for (i = 2; i < items; i++) { STRLEN len; - const char *name = SvPV(ST(i), len); + const char *name = SvPV_const(ST(i), len); SV *layer = PerlIO_find_layer(aTHX_ name, len, 1); if (layer) { av_push(av, SvREFCNT_inc(layer)); @@ -727,26 +861,37 @@ 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) { - HV *stash = gv_stashpv("PerlIO::Layer", TRUE); - SV *sv = sv_bless(newRV_noinc(newSViv(PTR2IV(tab))), stash); + HV * const stash = gv_stashpv("PerlIO::Layer", TRUE); + SV * const sv = sv_bless(newRV_noinc(newSViv(PTR2IV(tab))), stash); return sv; } +XS(XS_PerlIO__Layer__NoWarnings) +{ + /* This is used as a %SIG{__WARN__} handler to supress warnings + during loading of layers. + */ + dXSARGS; + if (items) + PerlIO_debug("warning:%s\n",SvPV_nolen_const(ST(0))); + XSRETURN(0); +} + XS(XS_PerlIO__Layer__find) { dXSARGS; if (items < 2) Perl_croak(aTHX_ "Usage class->find(name[,load])"); else { - STRLEN len = 0; - char *name = SvPV(ST(1), len); - bool load = (items > 2) ? SvTRUE(ST(2)) : 0; - PerlIO_funcs *layer = PerlIO_find_layer(aTHX_ name, len, load); + STRLEN len; + const char * const name = SvPV_const(ST(1), len); + const bool load = (items > 2) ? SvTRUE(ST(2)) : 0; + PerlIO_funcs * const layer = PerlIO_find_layer(aTHX_ name, len, load); ST(0) = (layer) ? sv_2mortal(PerlIO_tab_sv(aTHX_ layer)) : &PL_sv_undef; @@ -760,7 +905,7 @@ PerlIO_define_layer(pTHX_ PerlIO_funcs *tab) if (!PL_known_layers) PL_known_layers = PerlIO_list_alloc(aTHX); PerlIO_list_push(aTHX_ PL_known_layers, tab, Nullsv); - PerlIO_debug("define %s %p\n", tab->name, tab); + PerlIO_debug("define %s %p\n", tab->name, (void*)tab); } int @@ -782,10 +927,12 @@ PerlIO_parse_layers(pTHX_ PerlIO_list_t *av, const char *names) * passed. Even though this means "foo : : bar" is * seen as an invalid separator character. */ - char q = ((*s == '\'') ? '"' : '\''); - Perl_warn(aTHX_ - "perlio: invalid separator character %c%c%c in layer specification list %s", + const char q = ((*s == '\'') ? '"' : '\''); + if (ckWARN(WARN_LAYER)) + Perl_warner(aTHX_ packWARN(WARN_LAYER), + "Invalid separator character %c%c%c in PerlIO layer specification %s", q, *s, q, s); + SETERRNO(EINVAL, LIB_INVARG); return -1; } do { @@ -818,8 +965,9 @@ PerlIO_parse_layers(pTHX_ PerlIO_list_t *av, const char *names) */ case '\0': e--; - Perl_warn(aTHX_ - "perlio: argument list not closed for layer \"%.*s\"", + if (ckWARN(WARN_LAYER)) + Perl_warner(aTHX_ packWARN(WARN_LAYER), + "Argument list not closed for PerlIO layer \"%.*s\"", (int) (e - s), s); return -1; default: @@ -831,7 +979,7 @@ PerlIO_parse_layers(pTHX_ PerlIO_list_t *av, const char *names) } } if (e > s) { - PerlIO_funcs *layer = + PerlIO_funcs * const layer = PerlIO_find_layer(aTHX_ s, llen, 1); if (layer) { PerlIO_list_push(aTHX_ av, layer, @@ -840,7 +988,8 @@ PerlIO_parse_layers(pTHX_ PerlIO_list_t *av, const char *names) &PL_sv_undef); } else { - Perl_warn(aTHX_ "perlio: unknown layer \"%.*s\"", + if (ckWARN(WARN_LAYER)) + Perl_warner(aTHX_ packWARN(WARN_LAYER), "Unknown PerlIO layer \"%.*s\"", (int) llen, s); return -1; } @@ -855,15 +1004,13 @@ PerlIO_parse_layers(pTHX_ PerlIO_list_t *av, const char *names) void PerlIO_default_buffer(pTHX_ PerlIO_list_t *av) { - PerlIO_funcs *tab = &PerlIO_perlio; - if (O_BINARY != O_TEXT) { - tab = &PerlIO_crlf; - } - else { - if (PerlIO_stdio.Set_ptrcnt) { - tab = &PerlIO_stdio; - } - } + PERLIO_FUNCS_DECL(*tab) = &PerlIO_perlio; +#ifdef PERLIO_USING_CRLF + tab = &PerlIO_crlf; +#else + if (PerlIO_stdio.Set_ptrcnt) + tab = &PerlIO_stdio; +#endif PerlIO_debug("Pushing %s\n", tab->name); PerlIO_list_push(aTHX_ av, PerlIO_find_layer(aTHX_ tab->name, 0, 0), &PL_sv_undef); @@ -888,29 +1035,75 @@ 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) +{ + PERL_UNUSED_ARG(mode); + PERL_UNUSED_ARG(arg); + PERL_UNUSED_ARG(tab); + if (PerlIOValid(f)) { + PerlIO_flush(f); + PerlIO_pop(aTHX_ f); + return 0; + } + return -1; +} + +PERLIO_FUNCS_DECL(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, + 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) { if (!PL_def_layerlist) { const char *s = (PL_tainting) ? Nullch : PerlEnv_getenv("PERLIO"); - PerlIO_funcs *osLayer = &PerlIO_unix; + PERLIO_FUNCS_DECL(*osLayer) = &PerlIO_unix; PL_def_layerlist = PerlIO_list_alloc(aTHX); - PerlIO_define_layer(aTHX_ & PerlIO_unix); -#if defined(WIN32) && !defined(UNDER_CE) - PerlIO_define_layer(aTHX_ & PerlIO_win32); + PerlIO_define_layer(aTHX_ PERLIO_FUNCS_CAST(&PerlIO_unix)); +#if defined(WIN32) + PerlIO_define_layer(aTHX_ PERLIO_FUNCS_CAST(&PerlIO_win32)); #if 0 osLayer = &PerlIO_win32; #endif #endif - PerlIO_define_layer(aTHX_ & PerlIO_raw); - PerlIO_define_layer(aTHX_ & PerlIO_perlio); - PerlIO_define_layer(aTHX_ & PerlIO_stdio); - PerlIO_define_layer(aTHX_ & PerlIO_crlf); + PerlIO_define_layer(aTHX_ PERLIO_FUNCS_CAST(&PerlIO_raw)); + PerlIO_define_layer(aTHX_ PERLIO_FUNCS_CAST(&PerlIO_perlio)); + PerlIO_define_layer(aTHX_ PERLIO_FUNCS_CAST(&PerlIO_stdio)); + PerlIO_define_layer(aTHX_ PERLIO_FUNCS_CAST(&PerlIO_crlf)); #ifdef HAS_MMAP - PerlIO_define_layer(aTHX_ & PerlIO_mmap); + PerlIO_define_layer(aTHX_ PERLIO_FUNCS_CAST(&PerlIO_mmap)); #endif - PerlIO_define_layer(aTHX_ & PerlIO_utf8); - PerlIO_define_layer(aTHX_ & PerlIO_byte); + PerlIO_define_layer(aTHX_ PERLIO_FUNCS_CAST(&PerlIO_utf8)); + PerlIO_define_layer(aTHX_ PERLIO_FUNCS_CAST(&PerlIO_remove)); + PerlIO_define_layer(aTHX_ PERLIO_FUNCS_CAST(&PerlIO_byte)); PerlIO_list_push(aTHX_ PL_def_layerlist, PerlIO_find_layer(aTHX_ osLayer->name, 0, 0), &PL_sv_undef); @@ -935,15 +1128,16 @@ Perl_boot_core_PerlIO(pTHX) __FILE__); #endif newXS("PerlIO::Layer::find", XS_PerlIO__Layer__find, __FILE__); + newXS("PerlIO::Layer::NoWarnings", XS_PerlIO__Layer__NoWarnings, __FILE__); } PerlIO_funcs * PerlIO_default_layer(pTHX_ I32 n) { - PerlIO_list_t *av = PerlIO_default_layers(aTHX); + PerlIO_list_t * const av = PerlIO_default_layers(aTHX); if (n < 0) n += av->cur; - return PerlIO_layer_fetch(aTHX_ av, n, &PerlIO_stdio); + return PerlIO_layer_fetch(aTHX_ av, n, PERLIO_FUNCS_CAST(&PerlIO_stdio)); } #define PerlIO_default_top() PerlIO_default_layer(aTHX_ -1) @@ -961,79 +1155,111 @@ PerlIO_stdstreams(pTHX) } PerlIO * -PerlIO_push(pTHX_ PerlIO *f, PerlIO_funcs *tab, const char *mode, SV *arg) +PerlIO_push(pTHX_ PerlIO *f, PERLIO_FUNCS_DECL(*tab), const char *mode, SV *arg) { - 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; - PerlIO_debug("PerlIO_push f=%p %s %s %p\n", f, tab->name, - (mode) ? mode : "(Null)", arg); - if ((*l->tab->Pushed) (f, mode, arg) != 0) { - PerlIO_pop(aTHX_ f); - return NULL; + if (tab->fsize != sizeof(PerlIO_funcs)) { + mismatch: + Perl_croak(aTHX_ "Layer does not match this perl"); + } + if (tab->size) { + PerlIOl *l; + if (tab->size < sizeof(PerlIOl)) { + goto mismatch; + } + /* Real layer with a data area */ + Newxc(l,tab->size,char,PerlIOl); + if (l && f) { + Zero(l, tab->size, char); + l->next = *f; + l->tab = (PerlIO_funcs*) 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 && + (*l->tab->Pushed) (aTHX_ f, mode, arg, (PerlIO_funcs*) 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 (tab->Pushed && + (*tab->Pushed) (aTHX_ f, mode, arg, (PerlIO_funcs*) tab) != 0) { + return NULL; } } return f; } IV -PerlIOPop_pushed(PerlIO *f, const char *mode, SV *arg) +PerlIOBase_binmode(pTHX_ PerlIO *f) { - dTHX; - 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(PerlIO *f, const char *mode, SV *arg) +PerlIORaw_pushed(pTHX_ PerlIO *f, const char *mode, SV *arg, PerlIO_funcs *tab) { - /* - * Remove the dummy layer - */ - dTHX; - PerlIO_pop(aTHX_ f); - /* - * Pop back to bottom layer - */ - if (f && *f) { + PERL_UNUSED_ARG(mode); + PERL_UNUSED_ARG(arg); + PERL_UNUSED_ARG(tab); + + if (PerlIOValid(f)) { + PerlIO *t; + const 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", 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); + PerlIO_funcs * const tab = PerlIO_layer_fetch(aTHX_ layers, n, NULL); if (tab) { if (!PerlIO_push(aTHX_ f, tab, mode, PerlIOArg)) { code = -1; @@ -1049,11 +1275,11 @@ int PerlIO_apply_layers(pTHX_ PerlIO *f, const char *mode, const char *names) { int code = 0; - if (names) { - PerlIO_list_t *layers = PerlIO_list_alloc(aTHX); + if (f && names) { + PerlIO_list_t * const 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); } @@ -1070,63 +1296,87 @@ int PerlIO_binmode(pTHX_ PerlIO *f, int iotype, int mode, const char *names) { PerlIO_debug("PerlIO_binmode f=%p %s %c %x %s\n", - f, PerlIOBase(f)->tab->name, iotype, mode, + (void*)f, PerlIOBase(f)->tab->name, iotype, mode, (names) ? names : "(Null)"); - /* Can't flush if switching encodings. */ - if (!(names && memEQ(names, ":encoding(", 10))) { - PerlIO_flush(f); - if (!names && (O_TEXT != O_BINARY && (mode & O_BINARY))) { - PerlIO *top = f; - while (*top) { - if (PerlIOBase(top)->tab == &PerlIO_crlf) { - PerlIOBase(top)->flags &= ~PERLIO_F_CRLF; - break; + if (names) { + /* Do not flush etc. if (e.g.) switching encodings. + if a pushed layer knows it needs to flush lower layers + (for example :unix which is never going to call them) + it can do the flush when it is pushed. + */ + return PerlIO_apply_layers(aTHX_ f, NULL, names) == 0 ? TRUE : FALSE; + } + else { + /* 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 + */ + if (PerlIOBase(f)->tab->kind & PERLIO_K_CANCRLF) { + if (!(PerlIOBase(f)->flags & PERLIO_F_CRLF)) { + /* Not in text mode - flush any pending stuff and flip it */ + PerlIO_flush(f); + PerlIOBase(f)->flags |= PERLIO_F_CRLF; + } + /* Only need to turn it on in one layer so we are done */ + return TRUE; } - top = PerlIONext(top); - PerlIO_flush(top); + f = PerlIONext(f); } + /* Not finding a CRLF aware layer presumably means we are binary + which is not what was requested - so we failed + We _could_ push :crlf layer but so could caller + */ + return FALSE; } +#endif + /* Legacy binmode is now _defined_ as being equivalent to pushing :raw + So code that used to be here is now in PerlIORaw_pushed(). + */ + return PerlIO_push(aTHX_ f, PERLIO_FUNCS_CAST(&PerlIO_raw), Nullch, Nullsv) ? TRUE : FALSE; } - return PerlIO_apply_layers(aTHX_ f, NULL, names) == 0 ? TRUE : FALSE; } -#undef PerlIO__close int -PerlIO__close(PerlIO *f) +PerlIO__close(pTHX_ PerlIO *f) { - if (f && *f) - return (*PerlIOBase(f)->tab->Close) (f); + if (PerlIOValid(f)) { + PerlIO_funcs * const tab = PerlIOBase(f)->tab; + if (tab && tab->Close) + return (*tab->Close)(aTHX_ f); + else + return PerlIOBase_close(aTHX_ f); + } else { - SETERRNO(EBADF, SS$_IVCHAN); + SETERRNO(EBADF, SS_IVCHAN); return -1; } } -#undef PerlIO_close int -PerlIO_close(PerlIO *f) +Perl_PerlIO_close(pTHX_ PerlIO *f) { - dTHX; - int code = -1; - if (f && *f) { - code = (*PerlIOBase(f)->tab->Close) (f); - while (*f) { - PerlIO_pop(aTHX_ f); - } + const int code = PerlIO__close(aTHX_ f); + while (PerlIOValid(f)) { + PerlIO_pop(aTHX_ f); } return code; } -#undef PerlIO_fileno int -PerlIO_fileno(PerlIO *f) +Perl_PerlIO_fileno(pTHX_ PerlIO *f) { - if (f && *f) - return (*PerlIOBase(f)->tab->Fileno) (f); - else { - SETERRNO(EBADF, SS$_IVCHAN); - return -1; - } + Perl_PerlIO_or_Base(f, Fileno, fileno, -1, (aTHX_ f)); } static const char * @@ -1140,13 +1390,13 @@ PerlIO_context_layers(pTHX_ const char *mode) SV *layers = PL_curcop->cop_io; if (layers) { STRLEN len; - type = SvPV(layers, len); + type = SvPV_const(layers, len); if (type && mode[0] != 'r') { /* * Skip to write part */ const char *s = strchr(type, 0); - if (s && (s - type) < len) { + if (s && (STRLEN)(s - type) < len) { type = s + 1; } } @@ -1162,7 +1412,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 @@ -1195,14 +1445,14 @@ PerlIO_resolve_layers(pTHX_ const char *layers, * for it */ if (SvROK(arg) && !sv_isobject(arg)) { - PerlIO_funcs *handler = PerlIO_layer_from_ref(aTHX_ SvRV(arg)); + PerlIO_funcs * const handler = PerlIO_layer_from_ref(aTHX_ SvRV(arg)); if (handler) { def = PerlIO_list_alloc(aTHX); PerlIO_list_push(aTHX_ def, handler, &PL_sv_undef); 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. */ @@ -1213,7 +1463,7 @@ PerlIO_resolve_layers(pTHX_ const char *layers, if (layers && *layers) { PerlIO_list_t *av; if (incdef) { - IV i = def->cur; + IV i; av = PerlIO_list_alloc(aTHX); for (i = 0; i < def->cur; i++) { PerlIO_list_push(aTHX_ av, def->array[i].funcs, @@ -1223,8 +1473,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) @@ -1246,10 +1501,10 @@ PerlIO_openn(pTHX_ const char *layers, const char *mode, int fd, } } else { - PerlIO_list_t *layera = NULL; + PerlIO_list_t *layera; IV n; PerlIO_funcs *tab = NULL; - if (f && *f) { + if (PerlIOValid(f)) { /* * This is "reopen" - it is not tested as perl does not use it * yet @@ -1257,22 +1512,25 @@ PerlIO_openn(pTHX_ const char *layers, const char *mode, int fd, PerlIOl *l = *f; layera = PerlIO_list_alloc(aTHX); while (l) { - SV *arg = - (l->tab->Getarg) ? (*l->tab-> - Getarg) (aTHX_ &l, NULL, 0) : &PL_sv_undef; + SV * const arg = (l->tab->Getarg) + ? (*l->tab->Getarg) (aTHX_ &l, NULL, 0) + : &PL_sv_undef; PerlIO_list_push(aTHX_ layera, l->tab, arg); l = *PerlIONext(&l); } } else { layera = PerlIO_resolve_layers(aTHX_ layers, mode, narg, args); + if (!layera) { + return NULL; + } } /* * Start at "top" of layer stack */ n = layera->cur - 1; while (n >= 0) { - PerlIO_funcs *t = PerlIO_layer_fetch(aTHX_ layera, n, NULL); + PerlIO_funcs * const t = PerlIO_layer_fetch(aTHX_ layera, n, NULL); if (t && t->Open) { tab = t; break; @@ -1283,19 +1541,28 @@ PerlIO_openn(pTHX_ const char *layers, const char *mode, int fd, /* * Found that layer 'n' can do opens - call it */ + if (narg > 1 && !(tab->kind & PERLIO_K_MULTIARG)) { + Perl_croak(aTHX_ "More than one argument to open(,':%s')",tab->name); + } PerlIO_debug("openn(%s,'%s','%s',%d,%x,%o,%p,%d,%p)\n", - tab->name, layers, mode, fd, imode, perm, f, narg, - args); - f = (*tab->Open) (aTHX_ tab, layera, n, mode, fd, imode, perm, - f, narg, args); + tab->name, layers, mode, fd, imode, perm, + (void*)f, narg, (void*)args); + if (tab->Open) + f = (*tab->Open) (aTHX_ tab, layera, n, mode, fd, imode, perm, + f, narg, args); + else { + SETERRNO(EINVAL, LIB_INVARG); + f = NULL; + } if (f) { if (n + 1 < layera->cur) { /* * 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; } } @@ -1307,111 +1574,51 @@ PerlIO_openn(pTHX_ const char *layers, const char *mode, int fd, } -#undef PerlIO_fdopen -PerlIO * -PerlIO_fdopen(int fd, const char *mode) -{ - dTHX; - return PerlIO_openn(aTHX_ Nullch, mode, fd, 0, 0, NULL, 0, NULL); -} - -#undef PerlIO_open -PerlIO * -PerlIO_open(const char *path, const char *mode) -{ - dTHX; - SV *name = sv_2mortal(newSVpvn(path, strlen(path))); - return PerlIO_openn(aTHX_ Nullch, mode, -1, 0, 0, NULL, 1, &name); -} - -#undef PerlIO_reopen -PerlIO * -PerlIO_reopen(const char *path, const char *mode, PerlIO *f) -{ - dTHX; - SV *name = sv_2mortal(newSVpvn(path, strlen(path))); - return PerlIO_openn(aTHX_ Nullch, mode, -1, 0, 0, f, 1, &name); -} - -#undef PerlIO_read SSize_t -PerlIO_read(PerlIO *f, void *vbuf, Size_t count) +Perl_PerlIO_read(pTHX_ PerlIO *f, void *vbuf, Size_t count) { - if (f && *f) - return (*PerlIOBase(f)->tab->Read) (f, vbuf, count); - else { - SETERRNO(EBADF, SS$_IVCHAN); - return -1; - } + Perl_PerlIO_or_Base(f, Read, read, -1, (aTHX_ f, vbuf, count)); } -#undef PerlIO_unread SSize_t -PerlIO_unread(PerlIO *f, const void *vbuf, Size_t count) +Perl_PerlIO_unread(pTHX_ PerlIO *f, const void *vbuf, Size_t count) { - if (f && *f) - return (*PerlIOBase(f)->tab->Unread) (f, vbuf, count); - else { - SETERRNO(EBADF, SS$_IVCHAN); - return -1; - } + Perl_PerlIO_or_Base(f, Unread, unread, -1, (aTHX_ f, vbuf, count)); } -#undef PerlIO_write SSize_t -PerlIO_write(PerlIO *f, const void *vbuf, Size_t count) +Perl_PerlIO_write(pTHX_ PerlIO *f, const void *vbuf, Size_t count) { - if (f && *f) - return (*PerlIOBase(f)->tab->Write) (f, vbuf, count); - else { - SETERRNO(EBADF, SS$_IVCHAN); - return -1; - } + Perl_PerlIO_or_fail(f, Write, -1, (aTHX_ f, vbuf, count)); } -#undef PerlIO_seek int -PerlIO_seek(PerlIO *f, Off_t offset, int whence) +Perl_PerlIO_seek(pTHX_ PerlIO *f, Off_t offset, int whence) { - if (f && *f) - return (*PerlIOBase(f)->tab->Seek) (f, offset, whence); - else { - SETERRNO(EBADF, SS$_IVCHAN); - return -1; - } + Perl_PerlIO_or_fail(f, Seek, -1, (aTHX_ f, offset, whence)); } -#undef PerlIO_tell Off_t -PerlIO_tell(PerlIO *f) +Perl_PerlIO_tell(pTHX_ PerlIO *f) { - if (f && *f) - return (*PerlIOBase(f)->tab->Tell) (f); - else { - SETERRNO(EBADF, SS$_IVCHAN); - return -1; - } + Perl_PerlIO_or_fail(f, Tell, -1, (aTHX_ f)); } -#undef PerlIO_flush int -PerlIO_flush(PerlIO *f) +Perl_PerlIO_flush(pTHX_ PerlIO *f) { if (f) { if (*f) { - PerlIO_funcs *tab = PerlIOBase(f)->tab; - if (tab && tab->Flush) { - return (*tab->Flush) (f); - } - else { - PerlIO_debug("Cannot flush f=%p :%s\n", f, tab->name); - SETERRNO(EBADF, SS$_IVCHAN); - return -1; - } + const PerlIO_funcs *tab = PerlIOBase(f)->tab; + + if (tab && tab->Flush) + return (*tab->Flush) (aTHX_ f); + else + return 0; /* If no Flush defined, silently succeed. */ } else { - PerlIO_debug("Cannot flush f=%p\n", f); - SETERRNO(EBADF, SS$_IVCHAN); + PerlIO_debug("Cannot flush f=%p\n", (void*)f); + SETERRNO(EBADF, SS_IVCHAN); return -1; } } @@ -1423,7 +1630,6 @@ PerlIO_flush(PerlIO *f) * things on fflush(NULL), but should we be bound by their design * decisions? --jhi */ - dTHX; PerlIO **table = &PL_perlio; int code = 0; while ((f = *table)) { @@ -1440,9 +1646,8 @@ PerlIO_flush(PerlIO *f) } void -PerlIOBase_flush_linebuf() +PerlIOBase_flush_linebuf(pTHX) { - dTHX; PerlIO **table = &PL_perlio; PerlIO *f; while ((f = *table)) { @@ -1459,186 +1664,159 @@ PerlIOBase_flush_linebuf() } } -#undef PerlIO_fill int -PerlIO_fill(PerlIO *f) +Perl_PerlIO_fill(pTHX_ PerlIO *f) { - if (f && *f) - return (*PerlIOBase(f)->tab->Fill) (f); - else { - SETERRNO(EBADF, SS$_IVCHAN); - return -1; - } + Perl_PerlIO_or_fail(f, Fill, -1, (aTHX_ f)); } -#undef PerlIO_isutf8 int PerlIO_isutf8(PerlIO *f) { - if (f && *f) - return (PerlIOBase(f)->flags & PERLIO_F_UTF8) != 0; - else { - SETERRNO(EBADF, SS$_IVCHAN); - return -1; - } + if (PerlIOValid(f)) + return (PerlIOBase(f)->flags & PERLIO_F_UTF8) != 0; + else + SETERRNO(EBADF, SS_IVCHAN); + + return -1; } -#undef PerlIO_eof int -PerlIO_eof(PerlIO *f) +Perl_PerlIO_eof(pTHX_ PerlIO *f) { - if (f && *f) - return (*PerlIOBase(f)->tab->Eof) (f); - else { - SETERRNO(EBADF, SS$_IVCHAN); - return -1; - } + Perl_PerlIO_or_Base(f, Eof, eof, -1, (aTHX_ f)); } -#undef PerlIO_error int -PerlIO_error(PerlIO *f) +Perl_PerlIO_error(pTHX_ PerlIO *f) { - if (f && *f) - return (*PerlIOBase(f)->tab->Error) (f); - else { - SETERRNO(EBADF, SS$_IVCHAN); - return -1; - } + Perl_PerlIO_or_Base(f, Error, error, -1, (aTHX_ f)); } -#undef PerlIO_clearerr void -PerlIO_clearerr(PerlIO *f) +Perl_PerlIO_clearerr(pTHX_ PerlIO *f) { - if (f && *f) - (*PerlIOBase(f)->tab->Clearerr) (f); - else - SETERRNO(EBADF, SS$_IVCHAN); + Perl_PerlIO_or_Base_void(f, Clearerr, clearerr, (aTHX_ f)); } -#undef PerlIO_setlinebuf void -PerlIO_setlinebuf(PerlIO *f) +Perl_PerlIO_setlinebuf(pTHX_ PerlIO *f) { - if (f && *f) - (*PerlIOBase(f)->tab->Setlinebuf) (f); - else - SETERRNO(EBADF, SS$_IVCHAN); + Perl_PerlIO_or_Base_void(f, Setlinebuf, setlinebuf, (aTHX_ f)); } -#undef PerlIO_has_base int PerlIO_has_base(PerlIO *f) { - if (f && *f) { - return (PerlIOBase(f)->tab->Get_base != NULL); - } - return 0; + if (PerlIOValid(f)) { + const PerlIO_funcs * const tab = PerlIOBase(f)->tab; + + if (tab) + return (tab->Get_base != NULL); + SETERRNO(EINVAL, LIB_INVARG); + } + else + SETERRNO(EBADF, SS_IVCHAN); + + return 0; } -#undef PerlIO_fast_gets int PerlIO_fast_gets(PerlIO *f) { - if (f && *f && (PerlIOBase(f)->flags & PERLIO_F_FASTGETS)) { - PerlIO_funcs *tab = PerlIOBase(f)->tab; - return (tab->Set_ptrcnt != NULL); + if (PerlIOValid(f) && (PerlIOBase(f)->flags & PERLIO_F_FASTGETS)) { + const PerlIO_funcs * const tab = PerlIOBase(f)->tab; + + if (tab) + return (tab->Set_ptrcnt != NULL); + SETERRNO(EINVAL, LIB_INVARG); } + else + SETERRNO(EBADF, SS_IVCHAN); + return 0; } -#undef PerlIO_has_cntptr int PerlIO_has_cntptr(PerlIO *f) { - if (f && *f) { - PerlIO_funcs *tab = PerlIOBase(f)->tab; - return (tab->Get_ptr != NULL && tab->Get_cnt != NULL); + if (PerlIOValid(f)) { + const PerlIO_funcs * const tab = PerlIOBase(f)->tab; + + if (tab) + return (tab->Get_ptr != NULL && tab->Get_cnt != NULL); + SETERRNO(EINVAL, LIB_INVARG); } + else + SETERRNO(EBADF, SS_IVCHAN); + return 0; } -#undef PerlIO_canset_cnt int PerlIO_canset_cnt(PerlIO *f) { - if (f && *f) { - PerlIOl *l = PerlIOBase(f); - return (l->tab->Set_ptrcnt != NULL); + if (PerlIOValid(f)) { + const PerlIO_funcs * const tab = PerlIOBase(f)->tab; + + if (tab) + return (tab->Set_ptrcnt != NULL); + SETERRNO(EINVAL, LIB_INVARG); } + else + SETERRNO(EBADF, SS_IVCHAN); + return 0; } -#undef PerlIO_get_base STDCHAR * -PerlIO_get_base(PerlIO *f) +Perl_PerlIO_get_base(pTHX_ PerlIO *f) { - if (f && *f) - return (*PerlIOBase(f)->tab->Get_base) (f); - return NULL; + Perl_PerlIO_or_fail(f, Get_base, NULL, (aTHX_ f)); } -#undef PerlIO_get_bufsiz int -PerlIO_get_bufsiz(PerlIO *f) +Perl_PerlIO_get_bufsiz(pTHX_ PerlIO *f) { - if (f && *f) - return (*PerlIOBase(f)->tab->Get_bufsiz) (f); - return 0; + Perl_PerlIO_or_fail(f, Get_bufsiz, -1, (aTHX_ f)); } -#undef PerlIO_get_ptr STDCHAR * -PerlIO_get_ptr(PerlIO *f) +Perl_PerlIO_get_ptr(pTHX_ PerlIO *f) { - PerlIO_funcs *tab = PerlIOBase(f)->tab; - if (tab->Get_ptr == NULL) - return NULL; - return (*tab->Get_ptr) (f); + Perl_PerlIO_or_fail(f, Get_ptr, NULL, (aTHX_ f)); } -#undef PerlIO_get_cnt int -PerlIO_get_cnt(PerlIO *f) +Perl_PerlIO_get_cnt(pTHX_ PerlIO *f) { - PerlIO_funcs *tab = PerlIOBase(f)->tab; - if (tab->Get_cnt == NULL) - return 0; - return (*tab->Get_cnt) (f); + Perl_PerlIO_or_fail(f, Get_cnt, -1, (aTHX_ f)); } -#undef PerlIO_set_cnt void -PerlIO_set_cnt(PerlIO *f, int cnt) +Perl_PerlIO_set_cnt(pTHX_ PerlIO *f, int cnt) { - (*PerlIOBase(f)->tab->Set_ptrcnt) (f, NULL, cnt); + Perl_PerlIO_or_fail_void(f, Set_ptrcnt, (aTHX_ f, NULL, cnt)); } -#undef PerlIO_set_ptrcnt void -PerlIO_set_ptrcnt(PerlIO *f, STDCHAR * ptr, int cnt) +Perl_PerlIO_set_ptrcnt(pTHX_ PerlIO *f, STDCHAR * ptr, int cnt) { - PerlIO_funcs *tab = PerlIOBase(f)->tab; - if (tab->Set_ptrcnt == NULL) { - dTHX; - Perl_croak(aTHX_ "PerlIO buffer snooping abuse"); - } - (*PerlIOBase(f)->tab->Set_ptrcnt) (f, ptr, cnt); + Perl_PerlIO_or_fail_void(f, Set_ptrcnt, (aTHX_ f, ptr, cnt)); } + /*--------------------------------------------------------------------------------------*/ /* * utf8 and raw dummy layers */ IV -PerlIOUtf8_pushed(PerlIO *f, const char *mode, SV *arg) +PerlIOUtf8_pushed(pTHX_ PerlIO *f, const char *mode, SV *arg, PerlIO_funcs *tab) { - if (PerlIONext(f)) { - dTHX; - PerlIO_funcs *tab = PerlIOBase(f)->tab; - PerlIO_pop(aTHX_ f); + PERL_UNUSED_ARG(mode); + PERL_UNUSED_ARG(arg); + if (PerlIOValid(f)) { if (tab->kind & PERLIO_K_UTF8) PerlIOBase(f)->flags |= PERLIO_F_UTF8; else @@ -1648,10 +1826,11 @@ PerlIOUtf8_pushed(PerlIO *f, const char *mode, SV *arg) return -1; } -PerlIO_funcs PerlIO_utf8 = { +PERLIO_FUNCS_DECL(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, @@ -1663,22 +1842,25 @@ PerlIO_funcs PerlIO_utf8 = { NULL, NULL, NULL, - NULL, /* flush */ - NULL, /* fill */ + 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 */ + NULL, /* get_base */ + NULL, /* get_bufsiz */ + NULL, /* get_ptr */ + NULL, /* get_cnt */ + NULL, /* set_ptrcnt */ }; -PerlIO_funcs PerlIO_byte = { +PERLIO_FUNCS_DECL(PerlIO_byte) = { + sizeof(PerlIO_funcs), "bytes", - sizeof(PerlIOl), + 0, PERLIO_K_DUMMY, PerlIOUtf8_pushed, NULL, @@ -1691,17 +1873,19 @@ PerlIO_funcs PerlIO_byte = { NULL, NULL, NULL, - NULL, /* flush */ - NULL, /* fill */ NULL, NULL, + NULL, /* flush */ + NULL, /* fill */ NULL, NULL, - NULL, /* get_base */ - NULL, /* get_bufsiz */ - NULL, /* get_ptr */ - NULL, /* get_cnt */ - NULL, /* set_ptrcnt */ + NULL, + NULL, + NULL, /* get_base */ + NULL, /* get_bufsiz */ + NULL, /* get_ptr */ + NULL, /* get_cnt */ + NULL, /* set_ptrcnt */ }; PerlIO * @@ -1709,14 +1893,19 @@ PerlIORaw_open(pTHX_ PerlIO_funcs *self, PerlIO_list_t *layers, IV n, const char *mode, int fd, int imode, int perm, PerlIO *old, int narg, SV **args) { - PerlIO_funcs *tab = PerlIO_default_btm(); - return (*tab->Open) (aTHX_ tab, layers, n - 1, mode, fd, imode, perm, - old, narg, args); + PerlIO_funcs * const tab = PerlIO_default_btm(); + PERL_UNUSED_ARG(self); + if (tab && tab->Open) + return (*tab->Open) (aTHX_ tab, layers, n - 1, mode, fd, imode, perm, + old, narg, args); + SETERRNO(EINVAL, LIB_INVARG); + return NULL; } -PerlIO_funcs PerlIO_raw = { +PERLIO_FUNCS_DECL(PerlIO_raw) = { + sizeof(PerlIO_funcs), "raw", - sizeof(PerlIOl), + 0, PERLIO_K_DUMMY, PerlIORaw_pushed, PerlIOBase_popped, @@ -1729,17 +1918,19 @@ PerlIO_funcs PerlIO_raw = { NULL, NULL, NULL, - NULL, /* flush */ - NULL, /* fill */ NULL, NULL, + NULL, /* flush */ + NULL, /* fill */ + NULL, NULL, NULL, - NULL, /* get_base */ - NULL, /* get_bufsiz */ - NULL, /* get_ptr */ - NULL, /* get_cnt */ - NULL, /* set_ptrcnt */ + NULL, + NULL, /* get_base */ + NULL, /* get_bufsiz */ + NULL, /* get_ptr */ + NULL, /* get_cnt */ + NULL, /* set_ptrcnt */ }; /*--------------------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------------------*/ @@ -1748,56 +1939,56 @@ PerlIO_funcs PerlIO_raw = { */ IV -PerlIOBase_fileno(PerlIO *f) +PerlIOBase_fileno(pTHX_ PerlIO *f) { - return PerlIO_fileno(PerlIONext(f)); + return PerlIOValid(f) ? PerlIO_fileno(PerlIONext(f)) : -1; } 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)) { + const 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++ = '+'; } - } -#if O_TEXT != O_BINARY - if (!(flags & PERLIO_F_CRLF)) - *s++ = 'b'; + 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'; #endif + } *s = '\0'; return buf; } + IV -PerlIOBase_pushed(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; + PerlIOl * const l = PerlIOBase(f); + PERL_UNUSED_ARG(arg); + l->flags &= ~(PERLIO_F_CANREAD | PERLIO_F_CANWRITE | PERLIO_F_TRUNCATE | PERLIO_F_APPEND); if (tab->Set_ptrcnt != NULL) l->flags |= PERLIO_F_FASTGETS; if (mode) { - if (*mode == '#' || *mode == 'I') + if (*mode == IoTYPE_NUMERIC || *mode == IoTYPE_IMPLICIT) mode++; switch (*mode++) { case 'r': @@ -1810,7 +2001,7 @@ PerlIOBase_pushed(PerlIO *f, const char *mode, SV *arg) l->flags |= PERLIO_F_TRUNCATE | PERLIO_F_CANWRITE; break; default: - SETERRNO(EINVAL, LIB$_INVARG); + SETERRNO(EINVAL, LIB_INVARG); return -1; } while (*mode) { @@ -1825,7 +2016,7 @@ PerlIOBase_pushed(PerlIO *f, const char *mode, SV *arg) l->flags |= PERLIO_F_CRLF; break; default: - SETERRNO(EINVAL, LIB$_INVARG); + SETERRNO(EINVAL, LIB_INVARG); return -1; } } @@ -1846,38 +2037,39 @@ PerlIOBase_pushed(PerlIO *f, const char *mode, SV *arg) } IV -PerlIOBase_popped(PerlIO *f) +PerlIOBase_popped(pTHX_ PerlIO *f) { + PERL_UNUSED_ARG(f); return 0; } SSize_t -PerlIOBase_unread(PerlIO *f, const void *vbuf, Size_t count) +PerlIOBase_unread(pTHX_ PerlIO *f, const void *vbuf, Size_t count) { - dTHX; /* * Save the position as current head considers it */ - Off_t old = PerlIO_tell(f); - SSize_t done; - PerlIO_push(aTHX_ f, &PerlIO_pending, "r", Nullsv); + const Off_t old = PerlIO_tell(f); + PerlIO_push(aTHX_ f, PERLIO_FUNCS_CAST(&PerlIO_pending), "r", Nullsv); PerlIOSelf(f, PerlIOBuf)->posn = old; - done = PerlIOBuf_unread(f, vbuf, count); - return done; + return PerlIOBuf_unread(aTHX_ f, vbuf, count); } SSize_t -PerlIOBase_read(PerlIO *f, void *vbuf, Size_t count) +PerlIOBase_read(pTHX_ PerlIO *f, void *vbuf, Size_t count) { STDCHAR *buf = (STDCHAR *) vbuf; if (f) { - if (!(PerlIOBase(f)->flags & PERLIO_F_CANREAD)) + if (!(PerlIOBase(f)->flags & PERLIO_F_CANREAD)) { + PerlIOBase(f)->flags |= PERLIO_F_ERROR; + SETERRNO(EBADF, SS_IVCHAN); return 0; + } while (count > 0) { 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); @@ -1896,64 +2088,81 @@ PerlIOBase_read(PerlIO *f, void *vbuf, Size_t count) } IV -PerlIOBase_noop_ok(PerlIO *f) +PerlIOBase_noop_ok(pTHX_ PerlIO *f) { + PERL_UNUSED_ARG(f); return 0; } IV -PerlIOBase_noop_fail(PerlIO *f) +PerlIOBase_noop_fail(pTHX_ PerlIO *f) { + PERL_UNUSED_ARG(f); return -1; } IV -PerlIOBase_close(PerlIO *f) +PerlIOBase_close(pTHX_ PerlIO *f) { - IV code = 0; - PerlIO *n = PerlIONext(f); - if (PerlIO_flush(f) != 0) - code = -1; - if (n && *n && (*PerlIOBase(n)->tab->Close) (n) != 0) - code = -1; - PerlIOBase(f)->flags &= - ~(PERLIO_F_CANREAD | PERLIO_F_CANWRITE | PERLIO_F_OPEN); + IV code = -1; + if (PerlIOValid(f)) { + PerlIO *n = PerlIONext(f); + code = PerlIO_flush(f); + PerlIOBase(f)->flags &= + ~(PERLIO_F_CANREAD | PERLIO_F_CANWRITE | PERLIO_F_OPEN); + while (PerlIOValid(n)) { + const PerlIO_funcs * const tab = PerlIOBase(n)->tab; + if (tab && tab->Close) { + if ((*tab->Close)(aTHX_ n) != 0) + code = -1; + break; + } + else { + PerlIOBase(n)->flags &= + ~(PERLIO_F_CANREAD | PERLIO_F_CANWRITE | PERLIO_F_OPEN); + } + n = PerlIONext(n); + } + } + else { + SETERRNO(EBADF, SS_IVCHAN); + } return code; } IV -PerlIOBase_eof(PerlIO *f) +PerlIOBase_eof(pTHX_ PerlIO *f) { - if (f && *f) { + if (PerlIOValid(f)) { return (PerlIOBase(f)->flags & PERLIO_F_EOF) != 0; } return 1; } IV -PerlIOBase_error(PerlIO *f) +PerlIOBase_error(pTHX_ PerlIO *f) { - if (f && *f) { + if (PerlIOValid(f)) { return (PerlIOBase(f)->flags & PERLIO_F_ERROR) != 0; } return 1; } void -PerlIOBase_clearerr(PerlIO *f) +PerlIOBase_clearerr(pTHX_ PerlIO *f) { - if (f && *f) { + if (PerlIOValid(f)) { PerlIO *n = PerlIONext(f); PerlIOBase(f)->flags &= ~(PERLIO_F_ERROR | PERLIO_F_EOF); - if (n) + if (PerlIOValid(n)) PerlIO_clearerr(n); } } void -PerlIOBase_setlinebuf(PerlIO *f) +PerlIOBase_setlinebuf(pTHX_ PerlIO *f) { - if (f) { + if (PerlIOValid(f)) { PerlIOBase(f)->flags |= PERLIO_F_LINEBUF; } } @@ -1971,6 +2180,7 @@ PerlIO_sv_dup(pTHX_ SV *arg, CLONE_PARAMS *param) return newSVsv(arg); } #else + PERL_UNUSED_ARG(param); return newSVsv(arg); #endif } @@ -1978,18 +2188,24 @@ PerlIO_sv_dup(pTHX_ SV *arg, CLONE_PARAMS *param) PerlIO * PerlIOBase_dup(pTHX_ PerlIO *f, PerlIO *o, CLONE_PARAMS *param, int flags) { - PerlIO *nexto = PerlIONext(o); - if (*nexto) { - PerlIO_funcs *tab = PerlIOBase(nexto)->tab; - f = (*tab->Dup)(aTHX_ f, nexto, param, flags); + PerlIO * const nexto = PerlIONext(o); + if (PerlIOValid(nexto)) { + const PerlIO_funcs * const tab = PerlIOBase(nexto)->tab; + if (tab && tab->Dup) + f = (*tab->Dup)(aTHX_ f, nexto, param, flags); + else + f = PerlIOBase_dup(aTHX_ f, nexto, param, flags); } if (f) { PerlIO_funcs *self = PerlIOBase(o)->tab; - SV *arg = Nullsv; + SV *arg; char buf[8]; - PerlIO_debug("PerlIOBase_dup %s f=%p o=%p param=%p\n",self->name,f,o,param); - if (self->Getarg) { - arg = (*self->Getarg)(aTHX_ o,param,flags); + PerlIO_debug("PerlIOBase_dup %s f=%p o=%p param=%p\n", + self->name, (void*)f, (void*)o, (void*)param); + if (self->Getarg) + arg = (*self->Getarg)(aTHX_ o, param, flags); + else { + arg = Nullsv; } f = PerlIO_push(aTHX_ f, self, PerlIO_modestr(o,buf), arg); if (arg) { @@ -1999,30 +2215,31 @@ PerlIOBase_dup(pTHX_ PerlIO *f, PerlIO *o, CLONE_PARAMS *param, int flags) return f; } -#define PERLIO_MAX_REFCOUNTABLE_FD 2048 #ifdef USE_THREADS perl_mutex PerlIO_mutex; #endif -int PerlIO_fd_refcnt[PERLIO_MAX_REFCOUNTABLE_FD]; + +/* PL_perlio_fd_refcnt[] is in intrpvar.h */ void PerlIO_init(pTHX) { /* Place holder for stdstreams call ??? */ #ifdef USE_THREADS - MUTEX_INIT(&PerlIO_mutex); + MUTEX_INIT(&PerlIO_mutex); #endif } void PerlIOUnix_refcnt_inc(int fd) { + dTHX; if (fd >= 0 && fd < PERLIO_MAX_REFCOUNTABLE_FD) { #ifdef USE_THREADS MUTEX_LOCK(&PerlIO_mutex); #endif - PerlIO_fd_refcnt[fd]++; - PerlIO_debug("fd %d refcnt=%d\n",fd,PerlIO_fd_refcnt[fd]); + PL_perlio_fd_refcnt[fd]++; + PerlIO_debug("fd %d refcnt=%d\n",fd,PL_perlio_fd_refcnt[fd]); #ifdef USE_THREADS MUTEX_UNLOCK(&PerlIO_mutex); #endif @@ -2032,12 +2249,13 @@ PerlIOUnix_refcnt_inc(int fd) int PerlIOUnix_refcnt_dec(int fd) { + dTHX; int cnt = 0; if (fd >= 0 && fd < PERLIO_MAX_REFCOUNTABLE_FD) { #ifdef USE_THREADS MUTEX_LOCK(&PerlIO_mutex); #endif - cnt = --PerlIO_fd_refcnt[fd]; + cnt = --PL_perlio_fd_refcnt[fd]; PerlIO_debug("fd %d refcnt=%d\n",fd,cnt); #ifdef USE_THREADS MUTEX_UNLOCK(&PerlIO_mutex); @@ -2051,7 +2269,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++) @@ -2060,6 +2280,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; + } } @@ -2070,16 +2299,16 @@ 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 PerlIOUnix_oflags(const char *mode) { int oflags = -1; - if (*mode == 'I' || *mode == '#') + if (*mode == IoTYPE_IMPLICIT || *mode == IoTYPE_NUMERIC) mode++; switch (*mode) { case 'r': @@ -2125,72 +2354,117 @@ PerlIOUnix_oflags(const char *mode) */ oflags |= O_BINARY; if (*mode || oflags == -1) { - SETERRNO(EINVAL, LIB$_INVARG); + SETERRNO(EINVAL, LIB_INVARG); oflags = -1; } return oflags; } IV -PerlIOUnix_fileno(PerlIO *f) +PerlIOUnix_fileno(pTHX_ PerlIO *f) { return PerlIOSelf(f, PerlIOUnix)->fd; } +static void +PerlIOUnix_setfd(pTHX_ PerlIO *f, int fd, int imode) +{ + PerlIOUnix * const s = PerlIOSelf(f, PerlIOUnix); +#if defined(WIN32) + Stat_t st; + if (PerlLIO_fstat(fd, &st) == 0) { + if (!S_ISREG(st.st_mode)) { + PerlIO_debug("%d is not regular file\n",fd); + PerlIOBase(f)->flags |= PERLIO_F_NOTREG; + } + else { + PerlIO_debug("%d _is_ a regular file\n",fd); + } + } +#endif + s->fd = fd; + s->oflags = imode; + PerlIOUnix_refcnt_inc(fd); +} + IV -PerlIOUnix_pushed(PerlIO *f, const char *mode, SV *arg) +PerlIOUnix_pushed(pTHX_ PerlIO *f, const char *mode, SV *arg, PerlIO_funcs *tab) { - IV code = PerlIOBase_pushed(f, mode, arg); - PerlIOUnix *s = PerlIOSelf(f, PerlIOUnix); + IV code = PerlIOBase_pushed(aTHX_ f, mode, arg, tab); if (*PerlIONext(f)) { - s->fd = PerlIO_fileno(PerlIONext(f)); + /* We never call down so do any pending stuff now */ + PerlIO_flush(PerlIONext(f)); /* * XXX could (or should) we retrieve the oflags from the open file * handle rather than believing the "mode" we are passed in? XXX * Should the value on NULL mode be 0 or -1? */ - s->oflags = mode ? PerlIOUnix_oflags(mode) : -1; + PerlIOUnix_setfd(aTHX_ f, PerlIO_fileno(PerlIONext(f)), + mode ? PerlIOUnix_oflags(mode) : -1); } PerlIOBase(f)->flags |= PERLIO_F_OPEN; + return code; } +IV +PerlIOUnix_seek(pTHX_ PerlIO *f, Off_t offset, int whence) +{ + const int fd = PerlIOSelf(f, PerlIOUnix)->fd; + Off_t new_loc; + if (PerlIOBase(f)->flags & PERLIO_F_NOTREG) { +#ifdef ESPIPE + SETERRNO(ESPIPE, LIB_INVARG); +#else + SETERRNO(EINVAL, LIB_INVARG); +#endif + return -1; + } + new_loc = PerlLIO_lseek(fd, offset, whence); + if (new_loc == (Off_t) - 1) + { + return -1; + } + PerlIOBase(f)->flags &= ~PERLIO_F_EOF; + return 0; +} + PerlIO * 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) (f); + (*PerlIOBase(f)->tab->Close)(aTHX_ f); } if (narg > 0) { - char *path = SvPV_nolen(*args); - if (*mode == '#') + if (*mode == IoTYPE_NUMERIC) mode++; else { imode = PerlIOUnix_oflags(mode); perm = 0666; } if (imode != -1) { + const char *path = SvPV_nolen_const(*args); fd = PerlLIO_open3(path, imode, perm); } } if (fd >= 0) { - PerlIOUnix *s; - if (*mode == 'I') + if (*mode == IoTYPE_IMPLICIT) mode++; if (!f) { f = PerlIO_allocate(aTHX); - s = PerlIOSelf(PerlIO_push(aTHX_ f, self, mode, PerlIOArg), - PerlIOUnix); } - else - s = PerlIOSelf(f, PerlIOUnix); - s->fd = fd; - s->oflags = imode; + if (!PerlIOValid(f)) { + if (!(f = PerlIO_push(aTHX_ f, self, mode, PerlIOArg))) { + return NULL; + } + } + PerlIOUnix_setfd(aTHX_ f, fd, imode); PerlIOBase(f)->flags |= PERLIO_F_OPEN; - PerlIOUnix_refcnt_inc(fd); + if (*mode == IoTYPE_APPEND) + PerlIOUnix_seek(aTHX_ f, 0, SEEK_END); return f; } else { @@ -2215,9 +2489,7 @@ PerlIOUnix_dup(pTHX_ PerlIO *f, PerlIO *o, CLONE_PARAMS *param, int flags) f = PerlIOBase_dup(aTHX_ f, o, param, flags); if (f) { /* If all went well overwrite fd in dup'ed lay with the dup()'ed fd */ - PerlIOUnix *s = PerlIOSelf(f, PerlIOUnix); - s->fd = fd; - PerlIOUnix_refcnt_inc(fd); + PerlIOUnix_setfd(aTHX_ f, fd, os->oflags); return f; } } @@ -2226,73 +2498,79 @@ PerlIOUnix_dup(pTHX_ PerlIO *f, PerlIO *o, CLONE_PARAMS *param, int flags) SSize_t -PerlIOUnix_read(PerlIO *f, void *vbuf, Size_t count) +PerlIOUnix_read(pTHX_ PerlIO *f, void *vbuf, Size_t count) { - dTHX; - int fd = PerlIOSelf(f, PerlIOUnix)->fd; - if (!(PerlIOBase(f)->flags & PERLIO_F_CANREAD)) + const int fd = PerlIOSelf(f, PerlIOUnix)->fd; +#ifdef PERLIO_STD_SPECIAL + if (fd == 0) + return PERLIO_STD_IN(fd, vbuf, count); +#endif + 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); + const SSize_t len = PerlLIO_read(fd, vbuf, count); if (len >= 0 || errno != EINTR) { - if (len < 0) - PerlIOBase(f)->flags |= PERLIO_F_ERROR; - else if (len == 0 && count != 0) + if (len < 0) { + if (errno != EAGAIN) { + PerlIOBase(f)->flags |= PERLIO_F_ERROR; + } + } + else if (len == 0 && count != 0) { PerlIOBase(f)->flags |= PERLIO_F_EOF; + SETERRNO(0,0); + } return len; } PERL_ASYNC_CHECK(); } + /*NOTREACHED*/ } SSize_t -PerlIOUnix_write(PerlIO *f, const void *vbuf, Size_t count) +PerlIOUnix_write(pTHX_ PerlIO *f, const void *vbuf, Size_t count) { - dTHX; - int fd = PerlIOSelf(f, PerlIOUnix)->fd; + const int fd = PerlIOSelf(f, PerlIOUnix)->fd; +#ifdef PERLIO_STD_SPECIAL + if (fd == 1 || fd == 2) + return PERLIO_STD_OUT(fd, vbuf, count); +#endif while (1) { - SSize_t len = PerlLIO_write(fd, vbuf, count); + const SSize_t len = PerlLIO_write(fd, vbuf, count); if (len >= 0 || errno != EINTR) { - if (len < 0) - PerlIOBase(f)->flags |= PERLIO_F_ERROR; + if (len < 0) { + if (errno != EAGAIN) { + PerlIOBase(f)->flags |= PERLIO_F_ERROR; + } + } return len; } PERL_ASYNC_CHECK(); } -} - -IV -PerlIOUnix_seek(PerlIO *f, Off_t offset, int whence) -{ - dSYS; - Off_t new = - PerlLIO_lseek(PerlIOSelf(f, PerlIOUnix)->fd, offset, whence); - PerlIOBase(f)->flags &= ~PERLIO_F_EOF; - return (new == (Off_t) - 1) ? -1 : 0; + /*NOTREACHED*/ } Off_t -PerlIOUnix_tell(PerlIO *f) +PerlIOUnix_tell(pTHX_ PerlIO *f) { - dSYS; return PerlLIO_lseek(PerlIOSelf(f, PerlIOUnix)->fd, 0, SEEK_CUR); } IV -PerlIOUnix_close(PerlIO *f) +PerlIOUnix_close(pTHX_ PerlIO *f) { - dTHX; - int fd = PerlIOSelf(f, PerlIOUnix)->fd; + const int fd = PerlIOSelf(f, PerlIOUnix)->fd; int code = 0; if (PerlIOBase(f)->flags & PERLIO_F_OPEN) { if (PerlIOUnix_refcnt_dec(fd) > 0) { PerlIOBase(f)->flags &= ~PERLIO_F_OPEN; return 0; - } + } } else { - SETERRNO(EBADF,SS$_IVCHAN); + SETERRNO(EBADF,SS_IVCHAN); return -1; } while (PerlLIO_close(fd) != 0) { @@ -2308,13 +2586,15 @@ PerlIOUnix_close(PerlIO *f) return code; } -PerlIO_funcs PerlIO_unix = { +PERLIO_FUNCS_DECL(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, @@ -2324,17 +2604,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 */ }; /*--------------------------------------------------------------------------------------*/ @@ -2342,65 +2622,109 @@ 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(PerlIO *f) +PerlIOStdio_fileno(pTHX_ PerlIO *f) { - dSYS; - 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 * PerlIOStdio_mode(const char *mode, char *tmode) { - char *ret = tmode; - while (*mode) { - *tmode++ = *mode++; - } - if (O_BINARY != O_TEXT) { - *tmode++ = 'b'; + char * const ret = tmode; + if (mode) { + while (*mode) { + *tmode++ = *mode++; + } } +#if defined(PERLIO_USING_CRLF) || defined(__CYGWIN__) + *tmode++ = 'b'; +#endif *tmode = '\0'; return ret; } -/* - * This isn't used yet ... - */ IV -PerlIOStdio_pushed(PerlIO *f, const char *mode, SV *arg) +PerlIOStdio_pushed(pTHX_ PerlIO *f, const char *mode, SV *arg, PerlIO_funcs *tab) { - if (*PerlIONext(f)) { - dSYS; - 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; - else - return -1; + PerlIO *n; + if (PerlIOValid(f) && PerlIOValid(n = PerlIONext(f))) { + PerlIO_funcs * const toptab = PerlIOBase(n)->tab; + if (toptab == tab) { + /* Top is already stdio - pop self (duplicate) and use original */ + PerlIO_pop(aTHX_ f); + return 0; + } else { + const 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(f, mode, arg); + return PerlIOBase_pushed(aTHX_ f, mode, arg, tab); } -#undef PerlIO_importFILE + 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. + */ + const 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_FUNCS_CAST(&PerlIO_stdio), mode, Nullsv))) { + s = PerlIOSelf(f, PerlIOStdio); + s->stdio = stdio; + } } return f; } @@ -2411,8 +2735,8 @@ PerlIOStdio_open(pTHX_ PerlIO_funcs *self, PerlIO_list_t *layers, int perm, PerlIO *f, int narg, SV **args) { char tmode[8]; - if (f) { - char *path = SvPV_nolen(*args); + if (PerlIOValid(f)) { + const char *path = SvPV_nolen_const(*args); PerlIOStdio *s = PerlIOSelf(f, PerlIOStdio); FILE *stdio; PerlIOUnix_refcnt_dec(fileno(s->stdio)); @@ -2426,30 +2750,44 @@ PerlIOStdio_open(pTHX_ PerlIO_funcs *self, PerlIO_list_t *layers, } else { if (narg > 0) { - char *path = SvPV_nolen(*args); - if (*mode == '#') { + const char *path = SvPV_nolen_const(*args); + if (*mode == IoTYPE_NUMERIC) { mode++; fd = PerlLIO_open3(path, imode, perm); } else { - FILE *stdio = PerlSIO_fopen(path, mode); + FILE *stdio; + bool appended = FALSE; +#ifdef __CYGWIN__ + /* Cygwin wants its 'b' early. */ + appended = TRUE; + mode = PerlIOStdio_mode(mode, tmode); +#endif + stdio = PerlSIO_fopen(path, mode); if (stdio) { - PerlIOStdio *s = - PerlIOSelf(PerlIO_push - (aTHX_(f = PerlIO_allocate(aTHX)), self, - (mode = PerlIOStdio_mode(mode, tmode)), - PerlIOArg), - PerlIOStdio); - s->stdio = stdio; - PerlIOUnix_refcnt_inc(fileno(s->stdio)); + PerlIOStdio *s; + if (!f) { + f = PerlIO_allocate(aTHX); + } + if (!appended) + mode = PerlIOStdio_mode(mode, tmode); + f = PerlIO_push(aTHX_ f, self, mode, PerlIOArg); + if (f) { + s = PerlIOSelf(f, PerlIOStdio); + s->stdio = stdio; + PerlIOUnix_refcnt_inc(fileno(s->stdio)); + } + return f; + } + else { + return NULL; } - return f; } } if (fd >= 0) { FILE *stdio = NULL; int init = 0; - if (*mode == 'I') { + if (*mode == IoTYPE_IMPLICIT) { init = 1; mode++; } @@ -2471,12 +2809,14 @@ 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)); + if (!f) { + f = PerlIO_allocate(aTHX); + } + if ((f = PerlIO_push(aTHX_ f, self, mode, PerlIOArg))) { + PerlIOStdio *s = PerlIOSelf(f, PerlIOStdio); + s->stdio = stdio; + PerlIOUnix_refcnt_inc(fileno(s->stdio)); + } return f; } } @@ -2492,11 +2832,13 @@ PerlIOStdio_dup(pTHX_ PerlIO *f, PerlIO *o, CLONE_PARAMS *param, int flags) */ if ((f = PerlIOBase_dup(aTHX_ f, o, param, flags))) { FILE *stdio = PerlIOSelf(o, PerlIOStdio)->stdio; + const int fd = fileno(stdio); + char mode[8]; if (flags & PERLIO_DUP_FD) { - int fd = PerlLIO_dup(fileno(stdio)); - if (fd >= 0) { - char mode[8]; - stdio = fdopen(fd, PerlIO_modestr(o,mode)); + const int dfd = PerlLIO_dup(fileno(stdio)); + if (dfd >= 0) { + stdio = PerlSIO_fdopen(dfd, PerlIO_modestr(o,mode)); + goto set_this; } else { /* FIXME: To avoid messy error recovery if dup fails @@ -2504,176 +2846,353 @@ PerlIOStdio_dup(pTHX_ PerlIO *f, PerlIO *o, CLONE_PARAMS *param, int flags) */ } } + stdio = PerlSIO_fdopen(fd, PerlIO_modestr(o,mode)); + set_this: PerlIOSelf(f, PerlIOStdio)->stdio = stdio; PerlIOUnix_refcnt_inc(fileno(stdio)); } return f; } -IV -PerlIOStdio_close(PerlIO *f) +static int +PerlIOStdio_invalidate_fileno(pTHX_ FILE *f) { - dSYS; -#ifdef SOCKS5_VERSION_NAME - int optval; - Sock_size_t optlen = sizeof(int); + /* XXX this could use PerlIO_canset_fileno() and + * PerlIO_set_fileno() support from Configure + */ +# if defined(__UCLIBC__) + /* uClibc must come before glibc because it defines __GLIBC__ as well. */ + f->__filedes = -1; + return 1; +# elif defined(__GLIBC__) + /* There may be a better way for GLIBC: + - libio.h defines a flag to not close() on cleanup + */ + f->_fileno = -1; + return 1; +# elif defined(__sun__) +# if defined(_LP64) + /* On solaris, if _LP64 is defined, the FILE structure is this: + * + * struct FILE { + * long __pad[16]; + * }; + * + * It turns out that the fd is stored in the top 32 bits of + * file->__pad[4]. The lower 32 bits contain flags. file->pad[5] appears + * to contain a pointer or offset into another structure. All the + * remaining fields are zero. + * + * We set the top bits to -1 (0xFFFFFFFF). + */ + f->__pad[4] |= 0xffffffff00000000L; + assert(fileno(f) == 0xffffffff); +# else /* !defined(_LP64) */ + /* _file is just a unsigned char :-( + Not clear why we dup() rather than using -1 + even if that would be treated as 0xFF - so will + a dup fail ... + */ + f->_file = PerlLIO_dup(fileno(f)); +# endif /* defined(_LP64) */ + return 1; +# elif defined(__hpux) + f->__fileH = 0xff; + f->__fileL = 0xff; + return 1; + /* Next one ->_file seems to be a reasonable fallback, i.e. if + your platform does not have special entry try this one. + [For OSF only have confirmation for Tru64 (alpha) + but assume other OSFs will be similar.] + */ +# elif defined(_AIX) || defined(__osf__) || defined(__irix__) + f->_file = -1; + return 1; +# elif defined(__FreeBSD__) + /* There may be a better way on FreeBSD: + - we could insert a dummy func in the _close function entry + f->_close = (int (*)(void *)) dummy_close; + */ + f->_file = -1; + return 1; +# elif defined(__OpenBSD__) + /* There may be a better way on OpenBSD: + - we could insert a dummy func in the _close function entry + f->_close = (int (*)(void *)) dummy_close; + */ + f->_file = -1; + return 1; +# elif defined(__EMX__) + /* f->_flags &= ~_IOOPEN; */ /* Will leak stream->_buffer */ + f->_handle = -1; + return 1; +# elif defined(__CYGWIN__) + /* There may be a better way on CYGWIN: + - we could insert a dummy func in the _close function entry + f->_close = (int (*)(void *)) dummy_close; + */ + f->_file = -1; + return 1; +# elif defined(WIN32) +# if defined(__BORLANDC__) + f->fd = PerlLIO_dup(fileno(f)); +# elif defined(UNDER_CE) + /* WIN_CE does not have access to FILE internals, it hardly has FILE + structure at all + */ +# else + f->_file = -1; +# endif + return 1; +# else +#if 0 + /* Sarathy's code did this - we fall back to a dup/dup2 hack + (which isn't thread safe) instead + */ +# error "Don't know how to set FILE.fileno on your platform" #endif + PERL_UNUSED_ARG(f); + return 0; +# endif +} + +IV +PerlIOStdio_close(pTHX_ PerlIO *f) +{ FILE *stdio = PerlIOSelf(f, PerlIOStdio)->stdio; - if (PerlIOUnix_refcnt_dec(fileno(stdio)) > 0) { - /* Do not close it but do flush any buffers */ - PerlIO_flush(f); - return 0; + if (!stdio) { + errno = EBADF; + return -1; } - return ( + else { + const int fd = fileno(stdio); + int socksfd = 0; + int invalidate = 0; + IV result = 0; + int saveerr = 0; + int dupfd = 0; #ifdef SOCKS5_VERSION_NAME - (getsockopt - (PerlIO_fileno(f), SOL_SOCKET, SO_TYPE, (void *) &optval, - &optlen) < - 0) ? PerlSIO_fclose(stdio) : close(PerlIO_fileno(f)) -#else - PerlSIO_fclose(stdio) + /* Socks lib overrides close() but stdio isn't linked to + that library (though we are) - so we must call close() + on sockets on stdio's behalf. + */ + int optval; + Sock_size_t optlen = sizeof(int); + if (getsockopt(fd, SOL_SOCKET, SO_TYPE, (void *) &optval, &optlen) == 0) { + socksfd = 1; + invalidate = 1; + } #endif - ); - + if (PerlIOUnix_refcnt_dec(fd) > 0) { + /* File descriptor still in use */ + invalidate = 1; + socksfd = 0; + } + if (invalidate) { + /* For STD* handles don't close the stdio at all + this is because we have shared the FILE * too + */ + if (stdio == stdin) { + /* Some stdios are buggy fflush-ing inputs */ + return 0; + } + else if (stdio == stdout || stdio == stderr) { + return PerlIO_flush(f); + } + /* Tricky - must fclose(stdio) to free memory but not close(fd) + Use Sarathy's trick from maint-5.6 to invalidate the + fileno slot of the FILE * + */ + result = PerlIO_flush(f); + saveerr = errno; + if (!(invalidate = PerlIOStdio_invalidate_fileno(aTHX_ stdio))) { + dupfd = PerlLIO_dup(fd); + } + } + result = PerlSIO_fclose(stdio); + /* We treat error from stdio as success if we invalidated + errno may NOT be expected EBADF + */ + if (invalidate && result != 0) { + errno = saveerr; + result = 0; + } + if (socksfd) { + /* in SOCKS case let close() determine return value */ + result = close(fd); + } + if (dupfd) { + PerlLIO_dup2(dupfd,fd); + PerlLIO_close(dupfd); + } + return result; + } } - - SSize_t -PerlIOStdio_read(PerlIO *f, void *vbuf, Size_t count) +PerlIOStdio_read(pTHX_ PerlIO *f, void *vbuf, Size_t count) { - dSYS; FILE *s = PerlIOSelf(f, PerlIOStdio)->stdio; SSize_t got = 0; - if (count == 1) { - STDCHAR *buf = (STDCHAR *) vbuf; - /* - * Perl is expecting PerlIO_getc() to fill the buffer Linux's - * stdio does not do that for fread() - */ - int ch = PerlSIO_fgetc(s); - if (ch != EOF) { - *buf = ch; - got = 1; + for (;;) { + if (count == 1) { + STDCHAR *buf = (STDCHAR *) vbuf; + /* + * Perl is expecting PerlIO_getc() to fill the buffer Linux's + * stdio does not do that for fread() + */ + const int ch = PerlSIO_fgetc(s); + if (ch != EOF) { + *buf = ch; + got = 1; + } } + else + got = PerlSIO_fread(vbuf, 1, count, s); + if (got == 0 && PerlSIO_ferror(s)) + got = -1; + if (got >= 0 || errno != EINTR) + break; + PERL_ASYNC_CHECK(); + SETERRNO(0,0); /* just in case */ } - else - got = PerlSIO_fread(vbuf, 1, count, s); return got; } SSize_t -PerlIOStdio_unread(PerlIO *f, const void *vbuf, Size_t count) +PerlIOStdio_unread(pTHX_ PerlIO *f, const void *vbuf, Size_t count) { - dSYS; - 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) { + const 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; } SSize_t -PerlIOStdio_write(PerlIO *f, const void *vbuf, Size_t count) +PerlIOStdio_write(pTHX_ PerlIO *f, const void *vbuf, Size_t count) { - dSYS; - return PerlSIO_fwrite(vbuf, 1, count, - PerlIOSelf(f, PerlIOStdio)->stdio); + SSize_t got; + for (;;) { + got = PerlSIO_fwrite(vbuf, 1, count, + PerlIOSelf(f, PerlIOStdio)->stdio); + if (got >= 0 || errno != EINTR) + break; + PERL_ASYNC_CHECK(); + SETERRNO(0,0); /* just in case */ + } + return got; } IV -PerlIOStdio_seek(PerlIO *f, Off_t offset, int whence) +PerlIOStdio_seek(pTHX_ PerlIO *f, Off_t offset, int whence) { - dSYS; FILE *stdio = PerlIOSelf(f, PerlIOStdio)->stdio; return PerlSIO_fseek(stdio, offset, whence); } Off_t -PerlIOStdio_tell(PerlIO *f) +PerlIOStdio_tell(pTHX_ PerlIO *f) { - dSYS; FILE *stdio = PerlIOSelf(f, PerlIOStdio)->stdio; return PerlSIO_ftell(stdio); } IV -PerlIOStdio_flush(PerlIO *f) +PerlIOStdio_flush(pTHX_ PerlIO *f) { - dSYS; FILE *stdio = PerlIOSelf(f, PerlIOStdio)->stdio; if (PerlIOBase(f)->flags & PERLIO_F_CANWRITE) { return PerlSIO_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 (PerlSIO_fseek(stdio, (Off_t) 0, SEEK_CUR) != 0) - errno = err; -#endif - } - return 0; -} - -IV -PerlIOStdio_fill(PerlIO *f) -{ - dSYS; - 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; + /* + * 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 (PerlSIO_fseek(stdio, (Off_t) 0, SEEK_CUR) != 0) + errno = err; +#endif } - c = PerlSIO_fgetc(stdio); - if (c == EOF || PerlSIO_ungetc(c, stdio) != c) - return EOF; return 0; } IV -PerlIOStdio_eof(PerlIO *f) +PerlIOStdio_eof(pTHX_ PerlIO *f) { - dSYS; return PerlSIO_feof(PerlIOSelf(f, PerlIOStdio)->stdio); } IV -PerlIOStdio_error(PerlIO *f) +PerlIOStdio_error(pTHX_ PerlIO *f) { - dSYS; return PerlSIO_ferror(PerlIOSelf(f, PerlIOStdio)->stdio); } void -PerlIOStdio_clearerr(PerlIO *f) +PerlIOStdio_clearerr(pTHX_ PerlIO *f) { - dSYS; PerlSIO_clearerr(PerlIOSelf(f, PerlIOStdio)->stdio); } void -PerlIOStdio_setlinebuf(PerlIO *f) +PerlIOStdio_setlinebuf(pTHX_ PerlIO *f) { - dSYS; #ifdef HAS_SETLINEBUF PerlSIO_setlinebuf(PerlIOSelf(f, PerlIOStdio)->stdio); #else @@ -2683,17 +3202,15 @@ PerlIOStdio_setlinebuf(PerlIO *f) #ifdef FILE_base STDCHAR * -PerlIOStdio_get_base(PerlIO *f) +PerlIOStdio_get_base(pTHX_ PerlIO *f) { - dSYS; FILE *stdio = PerlIOSelf(f, PerlIOStdio)->stdio; - return PerlSIO_get_base(stdio); + return (STDCHAR*)PerlSIO_get_base(stdio); } Size_t -PerlIOStdio_get_bufsiz(PerlIO *f) +PerlIOStdio_get_bufsiz(pTHX_ PerlIO *f) { - dSYS; FILE *stdio = PerlIOSelf(f, PerlIOStdio)->stdio; return PerlSIO_get_bufsiz(stdio); } @@ -2701,32 +3218,28 @@ PerlIOStdio_get_bufsiz(PerlIO *f) #ifdef USE_STDIO_PTR STDCHAR * -PerlIOStdio_get_ptr(PerlIO *f) +PerlIOStdio_get_ptr(pTHX_ PerlIO *f) { - dSYS; FILE *stdio = PerlIOSelf(f, PerlIOStdio)->stdio; - return PerlSIO_get_ptr(stdio); + return (STDCHAR*)PerlSIO_get_ptr(stdio); } SSize_t -PerlIOStdio_get_cnt(PerlIO *f) +PerlIOStdio_get_cnt(pTHX_ PerlIO *f) { - dSYS; FILE *stdio = PerlIOSelf(f, PerlIOStdio)->stdio; return PerlSIO_get_cnt(stdio); } void -PerlIOStdio_set_ptrcnt(PerlIO *f, STDCHAR * ptr, SSize_t cnt) +PerlIOStdio_set_ptrcnt(pTHX_ PerlIO *f, STDCHAR * ptr, SSize_t cnt) { FILE *stdio = PerlIOSelf(f, PerlIOStdio)->stdio; - dSYS; if (ptr != NULL) { #ifdef STDIO_PTR_LVALUE - PerlSIO_set_ptr(stdio, ptr); + PerlSIO_set_ptr(stdio, (void*)ptr); /* LHS STDCHAR* cast non-portable */ #ifdef STDIO_PTR_LVAL_SETS_CNT if (PerlSIO_get_cnt(stdio) != (cnt)) { - dTHX; assert(PerlSIO_get_cnt(stdio) == (cnt)); } #endif @@ -2736,35 +3249,101 @@ PerlIOStdio_set_ptrcnt(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 = { + +PERLIO_FUNCS_DECL(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, @@ -2790,36 +3369,53 @@ PerlIO_funcs PerlIO_stdio = { #ifdef USE_STDIO_PTR PerlIOStdio_get_ptr, 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 */ - NULL -#endif /* STDIO_PTR_LVALUE */ -#else /* USE_STDIO_PTR */ +# if defined(HAS_FAST_STDIO) && defined(USE_FAST_STDIO) + PerlIOStdio_set_ptrcnt, +# else + NULL, +# endif /* HAS_FAST_STDIO && USE_FAST_STDIO */ +#else NULL, NULL, - NULL -#endif /* USE_STDIO_PTR */ + NULL, +#endif /* USE_STDIO_PTR */ }; -#undef PerlIO_exportFILE +/* 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) { - FILE *stdio; - PerlIO_flush(f); - stdio = fdopen(PerlIO_fileno(f), "r+"); - if (stdio) { - dTHX; - PerlIOStdio *s = - PerlIOSelf(PerlIO_push(aTHX_ f, &PerlIO_stdio, "r+", Nullsv), - PerlIOStdio); - s->stdio = stdio; + dTHX; + 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; + PerlIO *f2; + /* De-link any lower layers so new :stdio sticks */ + *f = NULL; + if ((f2 = PerlIO_push(aTHX_ f, PERLIO_FUNCS_CAST(&PerlIO_stdio), buf, Nullsv))) { + PerlIOStdio *s = PerlIOSelf((f = f2), PerlIOStdio); + s->stdio = stdio; + /* Link previous lower layers under new one */ + *PerlIONext(f) = l; + } + else { + /* restore layers list */ + *f = l; + } + } } return stdio; } -#undef PerlIO_findFILE + FILE * PerlIO_findFILE(PerlIO *f) { @@ -2831,13 +3427,28 @@ 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); } -#undef PerlIO_releaseFILE +/* Use this to reverse PerlIO_exportFILE calls. */ void PerlIO_releaseFILE(PerlIO *p, FILE *f) { + dVAR; + 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; } /*--------------------------------------------------------------------------------------*/ @@ -2846,20 +3457,20 @@ PerlIO_releaseFILE(PerlIO *p, FILE *f) */ IV -PerlIOBuf_pushed(PerlIO *f, const char *mode, SV *arg) +PerlIOBuf_pushed(pTHX_ PerlIO *f, const char *mode, SV *arg, PerlIO_funcs *tab) { - dSYS; PerlIOBuf *b = PerlIOSelf(f, PerlIOBuf); - int fd = PerlIO_fileno(f); - Off_t posn; + const int fd = PerlIO_fileno(f); 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)) { + const Off_t posn = PerlIO_tell(PerlIONext(f)); + if (posn != (Off_t) - 1) { + b->posn = posn; + } } - return PerlIOBase_pushed(f, mode, arg); + return PerlIOBase_pushed(aTHX_ f, mode, arg, tab); } PerlIO * @@ -2867,32 +3478,34 @@ PerlIOBuf_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)) { PerlIO *next = PerlIONext(f); 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) (f, mode, PerlIOArg) != 0) { + PerlIO_layer_fetch(aTHX_ layers, n - 1, PerlIOBase(next)->tab); + if (tab && tab->Open) + 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, self) != 0) { return NULL; } } else { - PerlIO_funcs *tab = - PerlIO_layer_fetch(aTHX_ layers, n - 1, PerlIO_default_btm()); + PerlIO_funcs *tab = PerlIO_layer_fetch(aTHX_ layers, n - 1, PerlIO_default_btm()); int init = 0; - if (*mode == 'I') { + if (*mode == IoTYPE_IMPLICIT) { init = 1; /* * mode++; */ } - f = (*tab->Open) (aTHX_ tab, layers, n - 1, mode, fd, imode, perm, - NULL, narg, args); + if (tab && tab->Open) + f = (*tab->Open)(aTHX_ tab, layers, n - 1, mode, fd, imode, perm, + f, narg, args); + else + SETERRNO(EINVAL, LIB_INVARG); 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. */ @@ -2900,18 +3513,23 @@ PerlIOBuf_open(pTHX_ PerlIO_funcs *self, PerlIO_list_t *layers, return NULL; } else { fd = PerlIO_fileno(f); -#if (O_BINARY != O_TEXT) && !defined(__BEOS__) - /* - * 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(aTHX_ f, '<'/*not used*/, O_BINARY, Nullch); + else +# endif + /* + * do something about failing setmode()? --jhi + */ + PerlLIO_setmode(fd, O_BINARY); +#endif } } } @@ -2923,17 +3541,17 @@ PerlIOBuf_open(pTHX_ PerlIO_funcs *self, PerlIO_list_t *layers, * read or write state */ IV -PerlIOBuf_flush(PerlIO *f) +PerlIOBuf_flush(pTHX_ PerlIO *f) { PerlIOBuf *b = PerlIOSelf(f, PerlIOBuf); int code = 0; + PerlIO *n = PerlIONext(f); if (PerlIOBase(f)->flags & PERLIO_F_WRBUF) { /* * write() the buffer */ - STDCHAR *buf = b->buf; - STDCHAR *p = buf; - PerlIO *n = PerlIONext(f); + const STDCHAR *buf = b->buf; + const STDCHAR *p = buf; while (p < b->ptr) { SSize_t count = PerlIO_write(n, p, b->ptr - p); if (count > 0) { @@ -2954,48 +3572,59 @@ PerlIOBuf_flush(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(PerlIONext(f), b->posn, SEEK_SET) == 0) { - b->posn = PerlIO_tell(PerlIONext(f)); + 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); - /* - * FIXME: Is this right for read case ? - */ - if (PerlIO_flush(PerlIONext(f)) != 0) + /* We check for Valid because of dubious decision to make PerlIO_flush(NULL) flush all */ + if (PerlIOValid(n) && PerlIO_flush(n) != 0) code = -1; return code; } IV -PerlIOBuf_fill(PerlIO *f) +PerlIOBuf_fill(pTHX_ 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)) { } + * 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; if (PerlIOBase(f)->flags & PERLIO_F_TTY) - PerlIOBase_flush_linebuf(); + 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 + * 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_. @@ -3013,7 +3642,7 @@ PerlIOBuf_fill(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); @@ -3035,19 +3664,19 @@ PerlIOBuf_fill(PerlIO *f) } SSize_t -PerlIOBuf_read(PerlIO *f, void *vbuf, Size_t count) +PerlIOBuf_read(pTHX_ PerlIO *f, void *vbuf, Size_t count) { - PerlIOBuf *b = PerlIOSelf(f, PerlIOBuf); - if (f) { + if (PerlIOValid(f)) { + const PerlIOBuf *b = PerlIOSelf(f, PerlIOBuf); if (!b->ptr) PerlIO_get_base(f); - return PerlIOBase_read(f, vbuf, count); + return PerlIOBase_read(aTHX_ f, vbuf, count); } return 0; } SSize_t -PerlIOBuf_unread(PerlIO *f, const void *vbuf, Size_t count) +PerlIOBuf_unread(pTHX_ PerlIO *f, const void *vbuf, Size_t count) { const STDCHAR *buf = (const STDCHAR *) vbuf + count; PerlIOBuf *b = PerlIOSelf(f, PerlIOBuf); @@ -3100,45 +3729,48 @@ PerlIOBuf_unread(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; } SSize_t -PerlIOBuf_write(PerlIO *f, const void *vbuf, Size_t count) +PerlIOBuf_write(pTHX_ PerlIO *f, const void *vbuf, Size_t count) { - PerlIOBuf *b = PerlIOSelf(f, PerlIOBuf); + PerlIOBuf * const b = PerlIOSelf(f, PerlIOBuf); const STDCHAR *buf = (const STDCHAR *) vbuf; + const STDCHAR *flushptr = buf; Size_t written = 0; if (!b->buf) PerlIO_get_base(f); if (!(PerlIOBase(f)->flags & PERLIO_F_CANWRITE)) return 0; + if (PerlIOBase(f)->flags & PERLIO_F_RDBUF) { + if (PerlIO_flush(f) != 0) { + return 0; + } + } + if (PerlIOBase(f)->flags & PERLIO_F_LINEBUF) { + flushptr = buf + count; + while (flushptr > buf && *(flushptr - 1) != '\n') + --flushptr; + } while (count > 0) { SSize_t avail = b->bufsiz - (b->ptr - b->buf); if ((SSize_t) count < avail) avail = count; + if (flushptr > buf && flushptr <= buf + avail) + avail = flushptr - buf; PerlIOBase(f)->flags |= PERLIO_F_WRBUF; - if (PerlIOBase(f)->flags & PERLIO_F_LINEBUF) { - while (avail > 0) { - int ch = *buf++; - *(b->ptr)++ = ch; - count--; - avail--; - written++; - if (ch == '\n') { - PerlIO_flush(f); - break; - } - } - } - else { - if (avail) { - Copy(buf, b->ptr, avail, STDCHAR); - count -= avail; - buf += avail; - written += avail; - b->ptr += avail; - } + if (avail) { + Copy(buf, b->ptr, avail, STDCHAR); + count -= avail; + buf += avail; + written += avail; + b->ptr += avail; + if (buf == flushptr) + PerlIO_flush(f); } if (b->ptr >= (b->buf + b->bufsiz)) PerlIO_flush(f); @@ -3149,14 +3781,14 @@ PerlIOBuf_write(PerlIO *f, const void *vbuf, Size_t count) } IV -PerlIOBuf_seek(PerlIO *f, Off_t offset, int whence) +PerlIOBuf_seek(pTHX_ PerlIO *f, Off_t offset, int whence) { IV code; if ((code = PerlIO_flush(f)) == 0) { - PerlIOBuf *b = PerlIOSelf(f, PerlIOBuf); PerlIOBase(f)->flags &= ~PERLIO_F_EOF; code = PerlIO_seek(PerlIONext(f), offset, whence); if (code == 0) { + PerlIOBuf *b = PerlIOSelf(f, PerlIOBuf); b->posn = PerlIO_tell(PerlIONext(f)); } } @@ -3164,13 +3796,26 @@ PerlIOBuf_seek(PerlIO *f, Off_t offset, int whence) } Off_t -PerlIOBuf_tell(PerlIO *f) +PerlIOBuf_tell(pTHX_ PerlIO *f) { PerlIOBuf *b = PerlIOSelf(f, PerlIOBuf); /* * b->posn is file position where b->buf was read, or will be written */ Off_t posn = b->posn; + if ((PerlIOBase(f)->flags & PERLIO_F_APPEND) && + (PerlIOBase(f)->flags & PERLIO_F_WRBUF)) { +#if 1 + /* As O_APPEND files are normally shared in some sense it is better + to flush : + */ + PerlIO_flush(f); +#else + /* when file is NOT shared then this is sufficient */ + PerlIO_seek(PerlIONext(f),0, SEEK_END); +#endif + posn = b->posn = PerlIO_tell(PerlIONext(f)); + } if (b->buf) { /* * If buffer is valid adjust position by amount in buffer @@ -3181,10 +3826,24 @@ PerlIOBuf_tell(PerlIO *f) } IV -PerlIOBuf_close(PerlIO *f) +PerlIOBuf_popped(pTHX_ PerlIO *f) { - IV code = PerlIOBase_close(f); - PerlIOBuf *b = PerlIOSelf(f, PerlIOBuf); + const IV code = PerlIOBase_popped(aTHX_ f); + PerlIOBuf * const 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) +{ + const IV code = PerlIOBase_close(aTHX_ f); + PerlIOBuf * const b = PerlIOSelf(f, PerlIOBuf); if (b->buf && b->buf != (STDCHAR *) & b->oneword) { Safefree(b->buf); } @@ -3195,7 +3854,7 @@ PerlIOBuf_close(PerlIO *f) } STDCHAR * -PerlIOBuf_get_ptr(PerlIO *f) +PerlIOBuf_get_ptr(pTHX_ PerlIO *f) { PerlIOBuf *b = PerlIOSelf(f, PerlIOBuf); if (!b->buf) @@ -3204,7 +3863,7 @@ PerlIOBuf_get_ptr(PerlIO *f) } SSize_t -PerlIOBuf_get_cnt(PerlIO *f) +PerlIOBuf_get_cnt(pTHX_ PerlIO *f) { PerlIOBuf *b = PerlIOSelf(f, PerlIOBuf); if (!b->buf) @@ -3215,14 +3874,13 @@ PerlIOBuf_get_cnt(PerlIO *f) } STDCHAR * -PerlIOBuf_get_base(PerlIO *f) +PerlIOBuf_get_base(pTHX_ PerlIO *f) { PerlIOBuf *b = PerlIOSelf(f, PerlIOBuf); if (!b->buf) { if (!b->bufsiz) b->bufsiz = 4096; - b->buf = - Newz('B',b->buf,b->bufsiz, STDCHAR); + b->buf = Newxz(b->buf,b->bufsiz, STDCHAR); if (!b->buf) { b->buf = (STDCHAR *) & b->oneword; b->bufsiz = sizeof(b->oneword); @@ -3234,7 +3892,7 @@ PerlIOBuf_get_base(PerlIO *f) } Size_t -PerlIOBuf_bufsiz(PerlIO *f) +PerlIOBuf_bufsiz(pTHX_ PerlIO *f) { PerlIOBuf *b = PerlIOSelf(f, PerlIOBuf); if (!b->buf) @@ -3243,14 +3901,13 @@ PerlIOBuf_bufsiz(PerlIO *f) } void -PerlIOBuf_set_ptrcnt(PerlIO *f, STDCHAR * ptr, SSize_t cnt) +PerlIOBuf_set_ptrcnt(pTHX_ PerlIO *f, STDCHAR * ptr, SSize_t cnt) { PerlIOBuf *b = PerlIOSelf(f, PerlIOBuf); if (!b->buf) PerlIO_get_base(f); b->ptr = ptr; if (PerlIO_get_cnt(f) != cnt || b->ptr < b->buf) { - dTHX; assert(PerlIO_get_cnt(f) == cnt); assert(b->ptr >= b->buf); } @@ -3265,13 +3922,15 @@ PerlIOBuf_dup(pTHX_ PerlIO *f, PerlIO *o, CLONE_PARAMS *param, int flags) -PerlIO_funcs PerlIO_perlio = { +PERLIO_FUNCS_DECL(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, @@ -3300,7 +3959,7 @@ PerlIO_funcs PerlIO_perlio = { */ IV -PerlIOPending_fill(PerlIO *f) +PerlIOPending_fill(pTHX_ PerlIO *f) { /* * Should never happen @@ -3310,7 +3969,7 @@ PerlIOPending_fill(PerlIO *f) } IV -PerlIOPending_close(PerlIO *f) +PerlIOPending_close(pTHX_ PerlIO *f) { /* * A tad tricky - flush pops us, then we close new top @@ -3320,7 +3979,7 @@ PerlIOPending_close(PerlIO *f) } IV -PerlIOPending_seek(PerlIO *f, Off_t offset, int whence) +PerlIOPending_seek(pTHX_ PerlIO *f, Off_t offset, int whence) { /* * A tad tricky - flush pops us, then we seek new top @@ -3331,9 +3990,8 @@ PerlIOPending_seek(PerlIO *f, Off_t offset, int whence) IV -PerlIOPending_flush(PerlIO *f) +PerlIOPending_flush(pTHX_ PerlIO *f) { - dTHX; PerlIOBuf *b = PerlIOSelf(f, PerlIOBuf); if (b->buf && b->buf != (STDCHAR *) & b->oneword) { Safefree(b->buf); @@ -3344,20 +4002,20 @@ PerlIOPending_flush(PerlIO *f) } void -PerlIOPending_set_ptrcnt(PerlIO *f, STDCHAR * ptr, SSize_t cnt) +PerlIOPending_set_ptrcnt(pTHX_ PerlIO *f, STDCHAR * ptr, SSize_t cnt) { if (cnt <= 0) { PerlIO_flush(f); } else { - PerlIOBuf_set_ptrcnt(f, ptr, cnt); + PerlIOBuf_set_ptrcnt(aTHX_ f, ptr, cnt); } } IV -PerlIOPending_pushed(PerlIO *f, const char *mode, SV *arg) +PerlIOPending_pushed(pTHX_ PerlIO *f, const char *mode, SV *arg, PerlIO_funcs *tab) { - IV code = PerlIOBase_pushed(f, mode, arg); + const 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() @@ -3370,16 +4028,16 @@ PerlIOPending_pushed(PerlIO *f, const char *mode, SV *arg) } SSize_t -PerlIOPending_read(PerlIO *f, void *vbuf, Size_t count) +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(f, vbuf, avail); - if (got >= 0 && got < count) { - SSize_t more = + got = PerlIOBuf_read(aTHX_ f, vbuf, avail); + if (got >= 0 && got < (SSize_t)count) { + const SSize_t more = PerlIO_read(f, ((STDCHAR *) vbuf) + got, count - got); if (more >= 0 || got == 0) got += more; @@ -3387,13 +4045,15 @@ PerlIOPending_read(PerlIO *f, void *vbuf, Size_t count) return got; } -PerlIO_funcs PerlIO_pending = { +PERLIO_FUNCS_DECL(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, @@ -3426,28 +4086,45 @@ 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(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(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)", PerlIOBase(f)->flags); #endif + { + /* Enable the first CRLF capable layer you can find, but if none + * found, the one we just pushed is fine. This results in at + * any given moment at most one CRLF-capable layer being enabled + * in the whole layer stack. */ + PerlIO *g = PerlIONext(f); + while (g && *g) { + PerlIOl *b = PerlIOBase(g); + if (b && b->tab == &PerlIO_crlf) { + if (!(b->flags & PERLIO_F_CRLF)) + b->flags |= PERLIO_F_CRLF; + PerlIO_pop(aTHX_ f); + return code; + } + g = PerlIONext(g); + } + } return code; } SSize_t -PerlIOCrlf_unread(PerlIO *f, const void *vbuf, Size_t count) +PerlIOCrlf_unread(pTHX_ PerlIO *f, const void *vbuf, Size_t count) { PerlIOCrlf *c = PerlIOSelf(f, PerlIOCrlf); if (c->nl) { @@ -3455,7 +4132,7 @@ PerlIOCrlf_unread(PerlIO *f, const void *vbuf, Size_t count) c->nl = NULL; } if (!(PerlIOBase(f)->flags & PERLIO_F_CRLF)) - return PerlIOBuf_unread(f, vbuf, count); + return PerlIOBuf_unread(aTHX_ f, vbuf, count); else { const STDCHAR *buf = (const STDCHAR *) vbuf + count; PerlIOBuf *b = PerlIOSelf(f, PerlIOBuf); @@ -3496,15 +4173,15 @@ PerlIOCrlf_unread(PerlIO *f, const void *vbuf, Size_t count) } SSize_t -PerlIOCrlf_get_cnt(PerlIO *f) +PerlIOCrlf_get_cnt(pTHX_ PerlIO *f) { PerlIOBuf *b = PerlIOSelf(f, PerlIOBuf); if (!b->buf) 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++; @@ -3527,31 +4204,37 @@ PerlIOCrlf_get_cnt(PerlIO *f) /* * Blast - found CR as last char in buffer */ + if (b->ptr < nl) { /* * They may not care, defer work as long as * possible */ + c->nl = nl; return (nl - b->ptr); } 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 */ + /* Note as we have moved buf up flush's + posn += ptr-buf + will naturally make posn point at CR + */ + 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 */ + *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 */ + /* Should we clear EOF though ??? */ } } } @@ -3562,43 +4245,44 @@ PerlIOCrlf_get_cnt(PerlIO *f) } void -PerlIOCrlf_set_ptrcnt(PerlIO *f, STDCHAR * ptr, SSize_t cnt) +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) + if (c->nl) { ptr = c->nl + 1; + if (ptr == b->end && *c->nl == 0xd) { + /* Defered CR at end of buffer case - we lied about count */ + ptr--; + } + } else { ptr = b->end; - if ((flags & PERLIO_F_CRLF) && ptr > b->buf && ptr[-1] == 0xd) - ptr--; } ptr -= cnt; } else { +#if 0 /* * Test code - delete when it works ... */ - STDCHAR *chk; - if (c->nl) - chk = c->nl + 1; - else { - chk = b->end; - if ((flags & PERLIO_F_CRLF) && chk > b->buf && chk[-1] == 0xd) - chk--; + 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) { + /* Defered CR at end of buffer case - we lied about count */ + chk--; } chk -= cnt; - if (ptr != chk) { - dTHX; + if (ptr != chk ) { 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) { @@ -3615,10 +4299,10 @@ PerlIOCrlf_set_ptrcnt(PerlIO *f, STDCHAR * ptr, SSize_t cnt) } SSize_t -PerlIOCrlf_write(PerlIO *f, const void *vbuf, Size_t count) +PerlIOCrlf_write(pTHX_ PerlIO *f, const void *vbuf, Size_t count) { if (!(PerlIOBase(f)->flags & PERLIO_F_CRLF)) - return PerlIOBuf_write(f, vbuf, count); + return PerlIOBuf_write(aTHX_ f, vbuf, count); else { PerlIOBuf *b = PerlIOSelf(f, PerlIOBuf); const STDCHAR *buf = (const STDCHAR *) vbuf; @@ -3640,8 +4324,8 @@ PerlIOCrlf_write(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); @@ -3666,30 +4350,47 @@ PerlIOCrlf_write(PerlIO *f, const void *vbuf, Size_t count) } IV -PerlIOCrlf_flush(PerlIO *f) +PerlIOCrlf_flush(pTHX_ PerlIO *f) { PerlIOCrlf *c = PerlIOSelf(f, PerlIOCrlf); if (c->nl) { *(c->nl) = 0xd; c->nl = NULL; } - return PerlIOBuf_flush(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 = { +PERLIO_FUNCS_DECL(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 - * ... */ - PerlIOCrlf_unread, /* Put CR,LF in buffer for each '\n' */ - PerlIOCrlf_write, /* Put CR,LF in buffer for each '\n' */ + 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' */ PerlIOBuf_seek, PerlIOBuf_tell, PerlIOBuf_close, @@ -3713,69 +4414,33 @@ 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; - IV -PerlIOMmap_map(PerlIO *f) +PerlIOMmap_map(pTHX_ PerlIO *f) { - dTHX; - PerlIOMmap *m = PerlIOSelf(f, PerlIOMmap); - IV flags = PerlIOBase(f)->flags; + dVAR; + PerlIOMmap * const m = PerlIOSelf(f, PerlIOMmap); + const IV flags = PerlIOBase(f)->flags; IV code = 0; if (m->len) abort(); if (flags & PERLIO_F_CANREAD) { PerlIOBuf *b = PerlIOSelf(f, PerlIOBuf); - int fd = PerlIO_fileno(f); + const int fd = PerlIO_fileno(f); Stat_t st; code = Fstat(fd, &st); if (code == 0 && S_ISREG(st.st_mode)) { SSize_t len = st.st_size - b->posn; if (len > 0) { Off_t posn; - if (!page_size) { -#if defined(HAS_SYSCONF) && (defined(_SC_PAGESIZE) || defined(_SC_PAGE_SIZE)) - { - SETERRNO(0, SS$_NORMAL); -# ifdef _SC_PAGESIZE - page_size = sysconf(_SC_PAGESIZE); -# else - page_size = sysconf(_SC_PAGE_SIZE); -# endif - if ((long) page_size < 0) { - if (errno) { - SV *error = ERRSV; - char *msg; - STRLEN n_a; - (void) SvUPGRADE(error, SVt_PV); - msg = SvPVx(error, n_a); - Perl_croak(aTHX_ "panic: sysconf: %s", - msg); - } - else - Perl_croak(aTHX_ - "panic: sysconf: pagesize unknown"); - } - } -#else -# ifdef HAS_GETPAGESIZE - page_size = getpagesize(); -# else -# if defined(I_SYS_PARAM) && defined(PAGESIZE) - page_size = PAGESIZE; /* compiletime, bad */ -# endif -# endif -#endif - if ((IV) page_size <= 0) - Perl_croak(aTHX_ "panic: bad pagesize %" IVdf, - (IV) page_size); - } + if (PL_mmap_page_size <= 0) + Perl_croak(aTHX_ "panic: bad pagesize %" IVdf, + PL_mmap_page_size); if (b->posn < 0) { /* * This is a hack - should never happen - open should @@ -3783,7 +4448,7 @@ PerlIOMmap_map(PerlIO *f) */ b->posn = PerlIO_tell(PerlIONext(f)); } - posn = (b->posn / page_size) * page_size; + posn = (b->posn / PL_mmap_page_size) * PL_mmap_page_size; len = st.st_size - posn; m->mptr = mmap(NULL, len, PROT_READ, MAP_SHARED, fd, posn); if (m->mptr && m->mptr != (Mmap_t) - 1) { @@ -3817,7 +4482,7 @@ PerlIOMmap_map(PerlIO *f) } IV -PerlIOMmap_unmap(PerlIO *f) +PerlIOMmap_unmap(pTHX_ PerlIO *f) { PerlIOMmap *m = PerlIOSelf(f, PerlIOMmap); PerlIOBuf *b = &m->base; @@ -3838,7 +4503,7 @@ PerlIOMmap_unmap(PerlIO *f) } STDCHAR * -PerlIOMmap_get_base(PerlIO *f) +PerlIOMmap_get_base(pTHX_ PerlIO *f) { PerlIOMmap *m = PerlIOSelf(f, PerlIOMmap); PerlIOBuf *b = &m->base; @@ -3852,11 +4517,11 @@ PerlIOMmap_get_base(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(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 @@ -3867,11 +4532,11 @@ PerlIOMmap_get_base(PerlIO *f) b->ptr = b->end = b->buf; if (b->buf) return b->buf; - return PerlIOBuf_get_base(f); + return PerlIOBuf_get_base(aTHX_ f); } SSize_t -PerlIOMmap_unread(PerlIO *f, const void *vbuf, Size_t count) +PerlIOMmap_unread(pTHX_ PerlIO *f, const void *vbuf, Size_t count) { PerlIOMmap *m = PerlIOSelf(f, PerlIOMmap); PerlIOBuf *b = &m->base; @@ -3894,24 +4559,25 @@ PerlIOMmap_unread(PerlIO *f, const void *vbuf, Size_t count) if (!b->buf && m->bbuf) b->buf = m->bbuf; if (!b->buf) { - PerlIOBuf_get_base(f); + PerlIOBuf_get_base(aTHX_ f); m->bbuf = b->buf; } } - return PerlIOBuf_unread(f, vbuf, count); + return PerlIOBuf_unread(aTHX_ f, vbuf, count); } SSize_t -PerlIOMmap_write(PerlIO *f, const void *vbuf, Size_t count) +PerlIOMmap_write(pTHX_ PerlIO *f, const void *vbuf, Size_t count) { - PerlIOMmap *m = PerlIOSelf(f, PerlIOMmap); - PerlIOBuf *b = &m->base; + PerlIOMmap * const m = PerlIOSelf(f, PerlIOMmap); + PerlIOBuf * const b = &m->base; + if (!b->buf || !(PerlIOBase(f)->flags & PERLIO_F_WRBUF)) { /* * No, or wrong sort of, buffer */ if (m->len) { - if (PerlIOMmap_unmap(f) != 0) + if (PerlIOMmap_unmap(aTHX_ f) != 0) return 0; } /* @@ -3920,19 +4586,19 @@ PerlIOMmap_write(PerlIO *f, const void *vbuf, Size_t count) if (!b->buf && m->bbuf) b->buf = m->bbuf; if (!b->buf) { - PerlIOBuf_get_base(f); + PerlIOBuf_get_base(aTHX_ f); m->bbuf = b->buf; } } - return PerlIOBuf_write(f, vbuf, count); + return PerlIOBuf_write(aTHX_ f, vbuf, count); } IV -PerlIOMmap_flush(PerlIO *f) +PerlIOMmap_flush(pTHX_ PerlIO *f) { PerlIOMmap *m = PerlIOSelf(f, PerlIOMmap); PerlIOBuf *b = &m->base; - IV code = PerlIOBuf_flush(f); + IV code = PerlIOBuf_flush(aTHX_ f); /* * Now we are "synced" at PerlIOBuf level */ @@ -3941,7 +4607,7 @@ PerlIOMmap_flush(PerlIO *f) /* * Unmap the buffer */ - if (PerlIOMmap_unmap(f) != 0) + if (PerlIOMmap_unmap(aTHX_ f) != 0) code = -1; } else { @@ -3956,21 +4622,21 @@ PerlIOMmap_flush(PerlIO *f) } IV -PerlIOMmap_fill(PerlIO *f) +PerlIOMmap_fill(pTHX_ PerlIO *f) { PerlIOBuf *b = PerlIOSelf(f, PerlIOBuf); IV code = PerlIO_flush(f); if (code == 0 && !b->buf) { - code = PerlIOMmap_map(f); + code = PerlIOMmap_map(aTHX_ f); } if (code == 0 && !(PerlIOBase(f)->flags & PERLIO_F_RDBUF)) { - code = PerlIOBuf_fill(f); + code = PerlIOBuf_fill(aTHX_ f); } return code; } IV -PerlIOMmap_close(PerlIO *f) +PerlIOMmap_close(pTHX_ PerlIO *f) { PerlIOMmap *m = PerlIOSelf(f, PerlIOMmap); PerlIOBuf *b = &m->base; @@ -3980,7 +4646,7 @@ PerlIOMmap_close(PerlIO *f) m->bbuf = NULL; b->ptr = b->end = b->buf; } - if (PerlIOBuf_close(f) != 0) + if (PerlIOBuf_close(aTHX_ f) != 0) code = -1; return code; } @@ -3992,13 +4658,15 @@ PerlIOMmap_dup(pTHX_ PerlIO *f, PerlIO *o, CLONE_PARAMS *param, int flags) } -PerlIO_funcs PerlIO_mmap = { +PERLIO_FUNCS_DECL(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, @@ -4021,35 +4689,29 @@ PerlIO_funcs PerlIO_mmap = { PerlIOBuf_set_ptrcnt, }; -#endif /* HAS_MMAP */ +#endif /* HAS_MMAP */ -#undef PerlIO_stdin PerlIO * -PerlIO_stdin(void) +Perl_PerlIO_stdin(pTHX) { - dTHX; if (!PL_perlio) { PerlIO_stdstreams(aTHX); } return &PL_perlio[1]; } -#undef PerlIO_stdout PerlIO * -PerlIO_stdout(void) +Perl_PerlIO_stdout(pTHX) { - dTHX; if (!PL_perlio) { PerlIO_stdstreams(aTHX); } return &PL_perlio[2]; } -#undef PerlIO_stderr PerlIO * -PerlIO_stderr(void) +Perl_PerlIO_stderr(pTHX) { - dTHX; if (!PL_perlio) { PerlIO_stdstreams(aTHX); } @@ -4058,20 +4720,29 @@ PerlIO_stderr(void) /*--------------------------------------------------------------------------------------*/ -#undef PerlIO_getname char * PerlIO_getname(PerlIO *f, char *buf) { dTHX; - char *name = NULL; #ifdef VMS + char *name = NULL; + bool exported = FALSE; FILE *stdio = PerlIOSelf(f, PerlIOStdio)->stdio; - if (stdio) + if (!stdio) { + stdio = PerlIO_exportFILE(f,0); + exported = TRUE; + } + if (stdio) { name = fgetname(stdio, buf); + if (exported) PerlIO_releaseFILE(f,stdio); + } + return name; #else + PERL_UNUSED_ARG(f); + PERL_UNUSED_ARG(buf); Perl_croak(aTHX_ "Don't know how to get file name"); + return Nullch; #endif - return name; } @@ -4081,13 +4752,39 @@ PerlIO_getname(PerlIO *f, char *buf) * terms of above */ +#undef PerlIO_fdopen +PerlIO * +PerlIO_fdopen(int fd, const char *mode) +{ + dTHX; + return PerlIO_openn(aTHX_ Nullch, mode, fd, 0, 0, NULL, 0, NULL); +} + +#undef PerlIO_open +PerlIO * +PerlIO_open(const char *path, const char *mode) +{ + dTHX; + SV *name = sv_2mortal(newSVpvn(path, strlen(path))); + return PerlIO_openn(aTHX_ Nullch, mode, -1, 0, 0, NULL, 1, &name); +} + +#undef Perlio_reopen +PerlIO * +PerlIO_reopen(const char *path, const char *mode, PerlIO *f) +{ + dTHX; + SV *name = sv_2mortal(newSVpvn(path, strlen(path))); + return PerlIO_openn(aTHX_ Nullch, mode, -1, 0, 0, f, 1, &name); +} + #undef PerlIO_getc int PerlIO_getc(PerlIO *f) { + dTHX; STDCHAR buf[1]; - SSize_t count = PerlIO_read(f, buf, 1); - if (count == 1) { + if ( 1 == PerlIO_read(f, buf, 1) ) { return (unsigned char) buf[0]; } return EOF; @@ -4097,6 +4794,7 @@ PerlIO_getc(PerlIO *f) int PerlIO_ungetc(PerlIO *f, int ch) { + dTHX; if (ch != EOF) { STDCHAR buf = ch; if (PerlIO_unread(f, &buf, 1) == 1) @@ -4109,6 +4807,7 @@ PerlIO_ungetc(PerlIO *f, int ch) int PerlIO_putc(PerlIO *f, int ch) { + dTHX; STDCHAR buf = ch; return PerlIO_write(f, &buf, 1); } @@ -4117,6 +4816,7 @@ PerlIO_putc(PerlIO *f, int ch) int PerlIO_puts(PerlIO *f, const char *s) { + dTHX; STRLEN len = strlen(s); return PerlIO_write(f, s, len); } @@ -4125,6 +4825,7 @@ PerlIO_puts(PerlIO *f, const char *s) void PerlIO_rewind(PerlIO *f) { + dTHX; PerlIO_seek(f, (Off_t) 0, SEEK_SET); PerlIO_clearerr(f); } @@ -4135,7 +4836,7 @@ PerlIO_vprintf(PerlIO *f, const char *fmt, va_list ap) { dTHX; SV *sv = newSVpvn("", 0); - char *s; + const char *s; STRLEN len; SSize_t wrote; #ifdef NEED_VA_COPY @@ -4145,7 +4846,7 @@ PerlIO_vprintf(PerlIO *f, const char *fmt, va_list ap) #else sv_vcatpvf(sv, fmt, &ap); #endif - s = SvPV(sv, len); + s = SvPV_const(sv, len); wrote = PerlIO_write(f, s, len); SvREFCNT_dec(sv); return wrote; @@ -4167,6 +4868,7 @@ PerlIO_printf(PerlIO *f, const char *fmt, ...) int PerlIO_stdoutf(const char *fmt, ...) { + dTHX; va_list ap; int result; va_start(ap, fmt); @@ -4179,43 +4881,49 @@ PerlIO_stdoutf(const char *fmt, ...) PerlIO * PerlIO_tmpfile(void) { - /* - * I have no idea how portable mkstemp() is ... - */ -#if defined(WIN32) || !defined(HAVE_MKSTEMP) - dTHX; - 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; - } - return f; -#else - dTHX; - 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) { - PerlIOBase(f)->flags |= PERLIO_F_TEMP; - } - PerlLIO_unlink(SvPVX(sv)); - SvREFCNT_dec(sv); - } - return f; -#endif + dTHX; + PerlIO *f = NULL; +#ifdef WIN32 + const int fd = win32_tmpfd(); + if (fd >= 0) + f = PerlIO_fdopen(fd, "w+b"); +#else /* WIN32 */ +# if defined(HAS_MKSTEMP) && ! defined(VMS) && ! defined(OS2) + SV *sv = newSVpv("/tmp/PerlIO_XXXXXX", 0); + /* + * I have no idea how portable mkstemp() is ... NI-S + */ + const int fd = mkstemp(SvPVX(sv)); + if (fd >= 0) { + f = PerlIO_fdopen(fd, "w+"); + if (f) + PerlIOBase(f)->flags |= PERLIO_F_TEMP; + PerlLIO_unlink(SvPVX_const(sv)); + SvREFCNT_dec(sv); + } +# else /* !HAS_MKSTEMP, fallback to stdio tmpfile(). */ + FILE *stdio = PerlSIO_tmpfile(); + + if (stdio) { + if ((f = PerlIO_push(aTHX_(PerlIO_allocate(aTHX)), + PERLIO_FUNCS_CAST(&PerlIO_stdio), + "w+", Nullsv))) { + PerlIOStdio *s = PerlIOSelf(f, PerlIOStdio); + + if (s) + s->stdio = stdio; + } + } +# endif /* else HAS_MKSTEMP */ +#endif /* else WIN32 */ + return f; } #undef HAS_FSETPOS #undef HAS_FGETPOS -#endif /* USE_SFIO */ -#endif /* PERLIO_IS_STDIO */ +#endif /* USE_SFIO */ +#endif /* PERLIO_IS_STDIO */ /*======================================================================================*/ /* @@ -4235,7 +4943,7 @@ PerlIO_setpos(PerlIO *f, SV *pos) if (f && len == sizeof(Off_t)) return PerlIO_seek(f, *posn, SEEK_SET); } - SETERRNO(EINVAL, SS$_IVCHAN); + SETERRNO(EINVAL, SS_IVCHAN); return -1; } #else @@ -4255,7 +4963,7 @@ PerlIO_setpos(PerlIO *f, SV *pos) #endif } } - SETERRNO(EINVAL, SS$_IVCHAN); + SETERRNO(EINVAL, SS_IVCHAN); return -1; } #endif @@ -4294,7 +5002,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 */ } @@ -4302,7 +5010,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 */ } @@ -4312,7 +5020,8 @@ vfprintf(FILE *fd, char *pat, char *args) int PerlIO_vsprintf(char *s, int n, const char *fmt, va_list ap) { - int val = vsprintf(s, fmt, ap); + dVAR; + const int val = vsprintf(s, fmt, ap); if (n >= 0) { if (strlen(s) >= (STRLEN) n) { dTHX; @@ -4338,7 +5047,12 @@ PerlIO_sprintf(char *s, int n, const char *fmt, ...) } #endif - - - - +/* + * Local variables: + * c-indentation-style: bsd + * c-basic-offset: 4 + * indent-tabs-mode: t + * End: + * + * ex: set ts=8 sts=4 sw=4 noet: + */