X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=pp_sys.c;h=0d2c970ff177ab961f7067e0c7efaa1636968ac4;hb=0598b5ab3697b872539de6ed6dc1522b873602e1;hp=1659888abe77a3b81f2219d6fd8223fd175798d3;hpb=d4ac975eac140a6fda54f99664f15120fd97e7be;p=p5sagit%2Fp5-mst-13.2.git diff --git a/pp_sys.c b/pp_sys.c index 1659888..0d2c970 100644 --- a/pp_sys.c +++ b/pp_sys.c @@ -1,7 +1,7 @@ /* pp_sys.c * - * Copyright (C) 1995, 1996, 1997, 1998, 1999, - * 2000, 2001, 2002, 2003, 2004, 2005, 2006, by Larry Wall and others + * Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, + * 2004, 2005, 2006, 2007, 2008 by Larry Wall and others * * You may distribute under the terms of either the GNU General Public * License or the Artistic License, as specified in the README file. @@ -13,6 +13,8 @@ * cloven by a great fissure, out of which the red glare came, now leaping * up, now dying down into darkness; and all the while far below there was * a rumour and a trouble as of great engines throbbing and labouring. + * + * [p.945 of _The Lord of the Rings_, VI/iii: "Mount Doom"] */ /* This file contains system pp ("push/pop") functions that @@ -27,6 +29,10 @@ #include "EXTERN.h" #define PERL_IN_PP_SYS_C #include "perl.h" +#ifndef PERL_MICRO +# include "time64.h" +# include "time64.c" +#endif #ifdef I_SHADOW /* Shadow password support for solaris - pdo@cs.umd.edu @@ -199,15 +205,6 @@ void endservent(void); #undef PERL_EFF_ACCESS /* EFFective uid/gid ACCESS */ -/* AIX 5.2 and below use mktime for localtime, and defines the edge case - * for time 0x7fffffff to be valid only in UTC. AIX 5.3 provides localtime64 - * available in the 32bit environment, which could warrant Configure - * checks in the future. - */ -#ifdef _AIX -#define LOCALTIME_EDGECASE_BROKEN -#endif - /* F_OK unused: if stat() cannot find it... */ #if !defined(PERL_EFF_ACCESS) && defined(HAS_ACCESS) && defined(EFF_ONLY_OK) && !defined(NO_EFF_ONLY_OK) @@ -297,22 +294,7 @@ S_emulate_eaccess(pTHX_ const char* path, Mode_t mode) return res; } -# define PERL_EFF_ACCESS(p,f) (emulate_eaccess((p), (f))) -#endif - -#if !defined(PERL_EFF_ACCESS) -/* With it or without it: anyway you get a warning: either that - it is unused, or it is declared static and never defined. - */ -STATIC int -S_emulate_eaccess(pTHX_ const char* path, Mode_t mode) -{ - (void)path; - (void)mode; - Perl_croak(aTHX_ "switching effective uid is not implemented"); - /*NOTREACHED*/ - return -1; -} +# define PERL_EFF_ACCESS(p,f) (S_emulate_eaccess(aTHX_ (p), (f))) #endif PP(pp_backtick) @@ -330,22 +312,22 @@ PP(pp_backtick) mode = "rt"; fp = PerlProc_popen(tmps, mode); if (fp) { - const char * const type = PL_curcop->cop_io ? SvPV_nolen_const(PL_curcop->cop_io) : NULL; + const char * const type = Perl_PerlIO_context_layers(aTHX_ NULL); if (type && *type) PerlIO_apply_layers(aTHX_ fp,mode,type); if (gimme == G_VOID) { char tmpbuf[256]; while (PerlIO_read(fp, tmpbuf, sizeof tmpbuf) > 0) - ; + NOOP; } else if (gimme == G_SCALAR) { ENTER; SAVESPTR(PL_rs); PL_rs = &PL_sv_undef; - sv_setpvn(TARG, "", 0); /* note that this preserves previous buffer */ + sv_setpvs(TARG, ""); /* note that this preserves previous buffer */ while (sv_gets(TARG, fp, SvCUR(TARG)) != NULL) - ; + NOOP; LEAVE; XPUSHs(TARG); SvTAINTED_on(TARG); @@ -357,7 +339,7 @@ PP(pp_backtick) SvREFCNT_dec(sv); break; } - XPUSHs(sv_2mortal(sv)); + mXPUSHs(sv); if (SvLEN(sv) - SvCUR(sv) > 20) { SvPV_shrink_to_cur(sv); } @@ -400,10 +382,10 @@ PP(pp_glob) #endif /* !VMS */ SAVESPTR(PL_last_in_gv); /* We don't want this to be permanent. */ - PL_last_in_gv = (GV*)*PL_stack_sp--; + PL_last_in_gv = MUTABLE_GV(*PL_stack_sp--); SAVESPTR(PL_rs); /* This is not permanent, either. */ - PL_rs = sv_2mortal(newSVpvs("\000")); + PL_rs = newSVpvs_flags("\000", SVs_TEMP); #ifndef DOSISH #ifndef CSH *SvPVX(PL_rs) = '\n'; @@ -437,6 +419,7 @@ PP(pp_warn) else if (SP == MARK) { tmpsv = &PL_sv_no; EXTEND(SP, 1); + SP = MARK + 1; } else { tmpsv = TOPs; @@ -451,9 +434,9 @@ PP(pp_warn) tmps = SvPV_const(tmpsv, len); } if (!tmps || !len) - tmpsv = sv_2mortal(newSVpvs("Warning: something's wrong")); + tmpsv = newSVpvs_flags("Warning: something's wrong", SVs_TEMP); - Perl_warn(aTHX_ "%"SVf, tmpsv); + Perl_warn(aTHX_ "%"SVf, SVfARG(tmpsv)); RETSETYES; } @@ -477,7 +460,7 @@ PP(pp_die) } else { tmpsv = TOPs; - tmps = SvROK(tmpsv) ? NULL : SvPV_const(tmpsv, len); + tmps = SvROK(tmpsv) ? (const char *)NULL : SvPV_const(tmpsv, len); } if (!tmps || !len) { SV * const error = ERRSV; @@ -497,7 +480,7 @@ PP(pp_die) PUSHs(file); PUSHs(line); PUTBACK; - call_sv((SV*)GvCV(gv), + call_sv(MUTABLE_SV(GvCV(gv)), G_SCALAR|G_EVAL|G_KEEPERR); sv_setsv(error,*PL_stack_sp--); } @@ -515,9 +498,9 @@ PP(pp_die) } } if (!tmps || !len) - tmpsv = sv_2mortal(newSVpvs("Died")); + tmpsv = newSVpvs_flags("Died", SVs_TEMP); - DIE(aTHX_ "%"SVf, tmpsv); + DIE(aTHX_ "%"SVf, SVfARG(tmpsv)); } /* I/O. */ @@ -533,19 +516,24 @@ PP(pp_open) STRLEN len; bool ok; - GV * const gv = (GV *)*++MARK; + GV * const gv = MUTABLE_GV(*++MARK); if (!isGV(gv)) DIE(aTHX_ PL_no_usym, "filehandle"); - if ((io = GvIOp(gv))) + + if ((io = GvIOp(gv))) { + MAGIC *mg; IoFLAGS(GvIOp(gv)) &= ~IOf_UNTAINT; - if (io) { - MAGIC * const mg = SvTIED_mg((SV*)io, PERL_MAGIC_tiedscalar); + if (IoDIRP(io) && ckWARN2(WARN_IO, WARN_DEPRECATED)) + Perl_warner(aTHX_ packWARN2(WARN_IO, WARN_DEPRECATED), + "Opening dirhandle %s also as a file", GvENAME(gv)); + + mg = SvTIED_mg((const SV *)io, PERL_MAGIC_tiedscalar); if (mg) { /* Method's args are same as ours ... */ /* ... except handle is replaced by the object */ - *MARK-- = SvTIED_obj((SV*)io, mg); + *MARK-- = SvTIED_obj(MUTABLE_SV(io), mg); PUSHMARK(MARK); PUTBACK; ENTER; @@ -564,7 +552,7 @@ PP(pp_open) } tmps = SvPV_const(sv, len); - ok = do_openn(gv, tmps, len, FALSE, O_RDONLY, 0, Nullfp, MARK+1, (SP-MARK)); + ok = do_openn(gv, tmps, len, FALSE, O_RDONLY, 0, NULL, MARK+1, (SP-MARK)); SP = ORIGMARK; if (ok) PUSHi( (I32)PL_forkprocess ); @@ -578,21 +566,23 @@ PP(pp_open) PP(pp_close) { dVAR; dSP; - IO *io; - MAGIC *mg; - GV * const gv = (MAXARG == 0) ? PL_defoutgv : (GV*)POPs; + GV * const gv = (MAXARG == 0) ? PL_defoutgv : MUTABLE_GV(POPs); - if (gv && (io = GvIO(gv)) - && (mg = SvTIED_mg((SV*)io, PERL_MAGIC_tiedscalar))) - { - PUSHMARK(SP); - XPUSHs(SvTIED_obj((SV*)io, mg)); - PUTBACK; - ENTER; - call_method("CLOSE", G_SCALAR); - LEAVE; - SPAGAIN; - RETURN; + if (gv) { + IO * const io = GvIO(gv); + if (io) { + MAGIC * const mg = SvTIED_mg((const SV *)io, PERL_MAGIC_tiedscalar); + if (mg) { + PUSHMARK(SP); + XPUSHs(SvTIED_obj(MUTABLE_SV(io), mg)); + PUTBACK; + ENTER; + call_method("CLOSE", G_SCALAR); + LEAVE; + SPAGAIN; + RETURN; + } + } } EXTEND(SP, 1); PUSHs(boolSV(do_close(gv, TRUE))); @@ -608,13 +598,13 @@ PP(pp_pipe_op) register IO *wstio; int fd[2]; - GV * const wgv = (GV*)POPs; - GV * const rgv = (GV*)POPs; + GV * const wgv = MUTABLE_GV(POPs); + GV * const rgv = MUTABLE_GV(POPs); if (!rgv || !wgv) goto badexit; - if (SvTYPE(rgv) != SVt_PVGV || SvTYPE(wgv) != SVt_PVGV) + if (!isGV_with_GP(rgv) || !isGV_with_GP(wgv)) DIE(aTHX_ PL_no_usym, "filehandle"); rstio = GvIOn(rgv); wstio = GvIOn(wgv); @@ -635,10 +625,14 @@ PP(pp_pipe_op) IoTYPE(wstio) = IoTYPE_WRONLY; if (!IoIFP(rstio) || !IoOFP(wstio)) { - if (IoIFP(rstio)) PerlIO_close(IoIFP(rstio)); - else PerlLIO_close(fd[0]); - if (IoOFP(wstio)) PerlIO_close(IoOFP(wstio)); - else PerlLIO_close(fd[1]); + if (IoIFP(rstio)) + PerlIO_close(IoIFP(rstio)); + else + PerlLIO_close(fd[0]); + if (IoOFP(wstio)) + PerlIO_close(IoOFP(wstio)); + else + PerlLIO_close(fd[1]); goto badexit; } #if defined(HAS_FCNTL) && defined(F_SETFD) @@ -664,13 +658,13 @@ PP(pp_fileno) if (MAXARG < 1) RETPUSHUNDEF; - gv = (GV*)POPs; + gv = MUTABLE_GV(POPs); if (gv && (io = GvIO(gv)) - && (mg = SvTIED_mg((SV*)io, PERL_MAGIC_tiedscalar))) + && (mg = SvTIED_mg((const SV *)io, PERL_MAGIC_tiedscalar))) { PUSHMARK(SP); - XPUSHs(SvTIED_obj((SV*)io, mg)); + XPUSHs(SvTIED_obj(MUTABLE_SV(io), mg)); PUTBACK; ENTER; call_method("FILENO", G_SCALAR); @@ -701,8 +695,12 @@ PP(pp_umask) Mode_t anum; if (MAXARG < 1) { - anum = PerlLIO_umask(0); - (void)PerlLIO_umask(anum); + anum = PerlLIO_umask(022); + /* setting it to 022 between the two calls to umask avoids + * to have a window where the umask is set to 0 -- meaning + * that another thread could create world-writeable files. */ + if (anum != 022) + (void)PerlLIO_umask(anum); } else anum = PerlLIO_umask(POPi); @@ -725,7 +723,6 @@ PP(pp_binmode) GV *gv; IO *io; PerlIO *fp; - MAGIC *mg; SV *discp = NULL; if (MAXARG < 1) @@ -734,21 +731,22 @@ PP(pp_binmode) discp = POPs; } - gv = (GV*)POPs; + gv = MUTABLE_GV(POPs); - if (gv && (io = GvIO(gv)) - && (mg = SvTIED_mg((SV*)io, PERL_MAGIC_tiedscalar))) - { - PUSHMARK(SP); - XPUSHs(SvTIED_obj((SV*)io, mg)); - if (discp) - XPUSHs(discp); - PUTBACK; - ENTER; - call_method("BINMODE", G_SCALAR); - LEAVE; - SPAGAIN; - RETURN; + if (gv && (io = GvIO(gv))) { + MAGIC * const mg = SvTIED_mg((const SV *)io, PERL_MAGIC_tiedscalar); + if (mg) { + PUSHMARK(SP); + XPUSHs(SvTIED_obj(MUTABLE_SV(io), mg)); + if (discp) + XPUSHs(discp); + PUTBACK; + ENTER; + call_method("BINMODE", G_SCALAR); + LEAVE; + SPAGAIN; + RETURN; + } } EXTEND(SP, 1); @@ -760,22 +758,27 @@ PP(pp_binmode) } PUTBACK; - if (PerlIO_binmode(aTHX_ fp,IoTYPE(io),mode_from_discipline(discp), - (discp) ? SvPV_nolen_const(discp) : NULL)) { - if (IoOFP(io) && IoOFP(io) != IoIFP(io)) { - if (!PerlIO_binmode(aTHX_ IoOFP(io),IoTYPE(io), - mode_from_discipline(discp), - (discp) ? SvPV_nolen_const(discp) : NULL)) { - SPAGAIN; - RETPUSHUNDEF; - } + { + STRLEN len = 0; + const char *d = NULL; + int mode; + if (discp) + d = SvPV_const(discp, len); + mode = mode_from_discipline(d, len); + if (PerlIO_binmode(aTHX_ fp, IoTYPE(io), mode, d)) { + if (IoOFP(io) && IoOFP(io) != IoIFP(io)) { + if (!PerlIO_binmode(aTHX_ IoOFP(io), IoTYPE(io), mode, d)) { + SPAGAIN; + RETPUSHUNDEF; + } + } + SPAGAIN; + RETPUSHYES; + } + else { + SPAGAIN; + RETPUSHUNDEF; } - SPAGAIN; - RETPUSHYES; - } - else { - SPAGAIN; - RETPUSHUNDEF; } } @@ -794,32 +797,35 @@ PP(pp_tie) switch(SvTYPE(varsv)) { case SVt_PVHV: methname = "TIEHASH"; - HvEITER_set((HV *)varsv, 0); + HvEITER_set(MUTABLE_HV(varsv), 0); break; case SVt_PVAV: methname = "TIEARRAY"; break; case SVt_PVGV: + if (isGV_with_GP(varsv)) { #ifdef GV_UNIQUE_CHECK - if (GvUNIQUE((GV*)varsv)) { - Perl_croak(aTHX_ "Attempt to tie unique GV"); - } + if (GvUNIQUE((const GV *)varsv)) { + Perl_croak(aTHX_ "Attempt to tie unique GV"); + } #endif - methname = "TIEHANDLE"; - how = PERL_MAGIC_tiedscalar; - /* For tied filehandles, we apply tiedscalar magic to the IO - slot of the GP rather than the GV itself. AMS 20010812 */ - if (!GvIOp(varsv)) - GvIOp(varsv) = newIO(); - varsv = (SV *)GvIOp(varsv); - break; + methname = "TIEHANDLE"; + how = PERL_MAGIC_tiedscalar; + /* For tied filehandles, we apply tiedscalar magic to the IO + slot of the GP rather than the GV itself. AMS 20010812 */ + if (!GvIOp(varsv)) + GvIOp(varsv) = newIO(); + varsv = MUTABLE_SV(GvIOp(varsv)); + break; + } + /* FALL THROUGH */ default: methname = "TIESCALAR"; how = PERL_MAGIC_tiedscalar; break; } items = SP - MARK++; - if (sv_isobject(*MARK)) { + if (sv_isobject(*MARK)) { /* Calls GET magic. */ ENTER; PUSHSTACKi(PERLSI_MAGIC); PUSHMARK(SP); @@ -833,10 +839,12 @@ PP(pp_tie) /* Not clear why we don't call call_method here too. * perhaps to get different error message ? */ - stash = gv_stashsv(*MARK, FALSE); + STRLEN len; + const char *name = SvPV_nomg_const(*MARK, len); + stash = gv_stashpvn(name, len, 0); if (!stash || !(gv = gv_fetchmethod(stash, methname))) { DIE(aTHX_ "Can't locate object method \"%s\" via package \"%"SVf"\"", - methname, *MARK); + methname, SVfARG(SvOK(*MARK) ? *MARK : &PL_sv_no)); } ENTER; PUSHSTACKi(PERLSI_MAGIC); @@ -845,7 +853,7 @@ PP(pp_tie) while (items--) PUSHs(*MARK++); PUTBACK; - call_sv((SV*)GvCV(gv), G_SCALAR); + call_sv(MUTABLE_SV(GvCV(gv)), G_SCALAR); } SPAGAIN; @@ -875,7 +883,7 @@ PP(pp_untie) const char how = (SvTYPE(sv) == SVt_PVHV || SvTYPE(sv) == SVt_PVAV) ? PERL_MAGIC_tied : PERL_MAGIC_tiedscalar; - if (SvTYPE(sv) == SVt_PVGV && !(sv = (SV *)GvIOp(sv))) + if (isGV_with_GP(sv) && !(sv = MUTABLE_SV(GvIOp(sv)))) RETPUSHYES; if ((mg = SvTIED_mg(sv, how))) { @@ -885,11 +893,11 @@ PP(pp_untie) CV *cv; if (gv && isGV(gv) && (cv = GvCV(gv))) { PUSHMARK(SP); - XPUSHs(SvTIED_obj((SV*)gv, mg)); - XPUSHs(sv_2mortal(newSViv(SvREFCNT(obj)-1))); + XPUSHs(SvTIED_obj(MUTABLE_SV(gv), mg)); + mXPUSHi(SvREFCNT(obj) - 1); PUTBACK; ENTER; - call_sv((SV *)cv, G_VOID); + call_sv(MUTABLE_SV(cv), G_VOID); LEAVE; SPAGAIN; } @@ -913,7 +921,7 @@ PP(pp_tied) const char how = (SvTYPE(sv) == SVt_PVHV || SvTYPE(sv) == SVt_PVAV) ? PERL_MAGIC_tied : PERL_MAGIC_tiedscalar; - if (SvTYPE(sv) == SVt_PVGV && !(sv = (SV *)GvIOp(sv))) + if (isGV_with_GP(sv) && !(sv = MUTABLE_SV(GvIOp(sv)))) RETPUSHUNDEF; if ((mg = SvTIED_mg(sv, how))) { @@ -933,16 +941,14 @@ PP(pp_dbmopen) HV* stash; GV *gv; - HV * const hv = (HV*)POPs; - SV * const sv = sv_mortalcopy(&PL_sv_no); - - sv_setpv(sv, "AnyDBM_File"); - stash = gv_stashsv(sv, FALSE); + HV * const hv = MUTABLE_HV(POPs); + SV * const sv = newSVpvs_flags("AnyDBM_File", SVs_TEMP); + stash = gv_stashsv(sv, 0); if (!stash || !(gv = gv_fetchmethod(stash, "TIEHASH"))) { PUTBACK; require_pv("AnyDBM_File.pm"); SPAGAIN; - if (!(gv = gv_fetchmethod(stash, "TIEHASH"))) + if (!stash || !(gv = gv_fetchmethod(stash, "TIEHASH"))) DIE(aTHX_ "No dbm on this machine"); } @@ -953,12 +959,12 @@ PP(pp_dbmopen) PUSHs(sv); PUSHs(left); if (SvIV(right)) - PUSHs(sv_2mortal(newSVuv(O_RDWR|O_CREAT))); + mPUSHu(O_RDWR|O_CREAT); else - PUSHs(sv_2mortal(newSVuv(O_RDWR))); + mPUSHu(O_RDWR); PUSHs(right); PUTBACK; - call_sv((SV*)GvCV(gv), G_SCALAR); + call_sv(MUTABLE_SV(GvCV(gv)), G_SCALAR); SPAGAIN; if (!sv_isobject(TOPs)) { @@ -966,16 +972,16 @@ PP(pp_dbmopen) PUSHMARK(SP); PUSHs(sv); PUSHs(left); - PUSHs(sv_2mortal(newSVuv(O_RDONLY))); + mPUSHu(O_RDONLY); PUSHs(right); PUTBACK; - call_sv((SV*)GvCV(gv), G_SCALAR); + call_sv(MUTABLE_SV(GvCV(gv)), G_SCALAR); SPAGAIN; } if (sv_isobject(TOPs)) { - sv_unmagic((SV *) hv, PERL_MAGIC_tied); - sv_magic((SV*)hv, TOPs, PERL_MAGIC_tied, NULL, 0); + sv_unmagic(MUTABLE_SV(hv), PERL_MAGIC_tied); + sv_magic(MUTABLE_SV(hv), TOPs, PERL_MAGIC_tied, NULL, 0); } LEAVE; RETURN; @@ -1018,7 +1024,7 @@ PP(pp_sselect) if (SvIsCOW(sv)) sv_force_normal_flags(sv, 0); if (SvREADONLY(sv) && !(SvPOK(sv) && SvCUR(sv) == 0)) - DIE(aTHX_ PL_no_modify); + DIE(aTHX_ "%s", PL_no_modify); } if (!SvPOK(sv)) { if (ckWARN(WARN_MISC)) @@ -1070,7 +1076,7 @@ PP(pp_sselect) timebuf.tv_usec = (long)(value * 1000000.0); } else - tbuf = Null(struct timeval*); + tbuf = NULL; for (i = 1; i <= 3; i++) { sv = SP[i]; @@ -1137,8 +1143,7 @@ PP(pp_sselect) if (GIMME == G_ARRAY && tbuf) { value = (NV)(timebuf.tv_sec) + (NV)(timebuf.tv_usec) / 1000000.0; - PUSHs(sv = sv_mortalcopy(&PL_sv_no)); - sv_setnv(sv, value); + mPUSHn(value); } RETURN; #else @@ -1146,12 +1151,22 @@ PP(pp_sselect) #endif } +/* +=for apidoc setdefout + +Sets PL_defoutgv, the default file handle for output, to the passed in +typeglob. As PL_defoutgv "owns" a reference on its typeglob, the reference +count of the passed in typeglob is increased by one, and the reference count +of the typeglob that PL_defoutgv points to is decreased by one. + +=cut +*/ + void Perl_setdefout(pTHX_ GV *gv) { dVAR; - if (gv) - (void)SvREFCNT_inc(gv); + SvREFCNT_inc_simple_void(gv); if (PL_defoutgv) SvREFCNT_dec(PL_defoutgv); PL_defoutgv = gv; @@ -1161,7 +1176,7 @@ PP(pp_select) { dVAR; dSP; dTARGET; HV *hv; - GV * const newdefout = (PL_op->op_private > 0) ? ((GV *) POPs) : (GV *) NULL; + GV * const newdefout = (PL_op->op_private > 0) ? (MUTABLE_GV(POPs)) : NULL; GV * egv = GvEGV(PL_defoutgv); if (!egv) @@ -1176,7 +1191,7 @@ PP(pp_select) XPUSHTARG; } else { - XPUSHs(sv_2mortal(newRV((SV*)egv))); + mXPUSHs(newRV(MUTABLE_SV(egv))); } } @@ -1193,23 +1208,23 @@ PP(pp_getc) { dVAR; dSP; dTARGET; IO *io = NULL; - MAGIC *mg; - GV * const gv = (MAXARG==0) ? PL_stdingv : (GV*)POPs; + GV * const gv = (MAXARG==0) ? PL_stdingv : MUTABLE_GV(POPs); - if (gv && (io = GvIO(gv)) - && (mg = SvTIED_mg((SV*)io, PERL_MAGIC_tiedscalar))) - { - const I32 gimme = GIMME_V; - PUSHMARK(SP); - XPUSHs(SvTIED_obj((SV*)io, mg)); - PUTBACK; - ENTER; - call_method("GETC", gimme); - LEAVE; - SPAGAIN; - if (gimme == G_SCALAR) - SvSetMagicSV_nosteal(TARG, TOPs); - RETURN; + if (gv && (io = GvIO(gv))) { + MAGIC * const mg = SvTIED_mg((const SV *)io, PERL_MAGIC_tiedscalar); + if (mg) { + const I32 gimme = GIMME_V; + PUSHMARK(SP); + XPUSHs(SvTIED_obj(MUTABLE_SV(io), mg)); + PUTBACK; + ENTER; + call_method("GETC", gimme); + LEAVE; + SPAGAIN; + if (gimme == G_SCALAR) + SvSetMagicSV_nosteal(TARG, TOPs); + RETURN; + } } if (!gv || do_eof(gv)) { /* make sure we have fp with something */ if ((!io || (!IoIFP(io) && IoTYPE(io) != IoTYPE_WRONLY)) @@ -1219,7 +1234,7 @@ PP(pp_getc) RETPUSHUNDEF; } TAINT; - sv_setpvn(TARG, " ", 1); + sv_setpvs(TARG, " "); *SvPVX(TARG) = PerlIO_getc(IoIFP(GvIOp(gv))); /* should never be EOF */ if (PerlIO_isutf8(IoIFP(GvIOp(gv)))) { /* Find out how many bytes the char needs */ @@ -1242,12 +1257,13 @@ S_doform(pTHX_ CV *cv, GV *gv, OP *retop) register PERL_CONTEXT *cx; const I32 gimme = GIMME_V; + PERL_ARGS_ASSERT_DOFORM; + ENTER; SAVETMPS; PUSHBLOCK(cx, CXt_FORMAT, PL_stack_sp); - PUSHFORMAT(cx); - cx->blk_sub.retop = retop; + PUSHFORMAT(cx, retop); SAVECOMPPAD(); PAD_SET_CUR_NOSAVE(CvPADLIST(cv), 1); @@ -1263,11 +1279,12 @@ PP(pp_enterwrite) register IO *io; GV *fgv; CV *cv; + SV * tmpsv = NULL; if (MAXARG == 0) gv = PL_defoutgv; else { - gv = (GV*)POPs; + gv = MUTABLE_GV(POPs); if (!gv) gv = PL_defoutgv; } @@ -1281,20 +1298,23 @@ PP(pp_enterwrite) else fgv = gv; + if (!fgv) + goto not_a_format_reference; + cv = GvFORM(fgv); if (!cv) { - if (fgv) { - SV * const tmpsv = sv_newmortal(); - const char *name; - gv_efullname4(tmpsv, fgv, NULL, FALSE); - name = SvPV_nolen_const(tmpsv); - if (name && *name) - DIE(aTHX_ "Undefined format \"%s\" called", name); - } + const char *name; + tmpsv = sv_newmortal(); + gv_efullname4(tmpsv, fgv, NULL, FALSE); + name = SvPV_nolen_const(tmpsv); + if (name && *name) + DIE(aTHX_ "Undefined format \"%s\" called", name); + + not_a_format_reference: DIE(aTHX_ "Not a format reference"); } if (CvCLONE(cv)) - cv = (CV*)sv_2mortal((SV*)cv_clone(cv)); + cv = MUTABLE_CV(sv_2mortal(MUTABLE_SV(cv_clone(cv)))); IoFLAGS(io) &= ~IOf_DIDTOP; return doform(cv,gv,PL_op->op_next); @@ -1303,18 +1323,20 @@ PP(pp_enterwrite) PP(pp_leavewrite) { dVAR; dSP; - GV * const gv = cxstack[cxstack_ix].blk_sub.gv; + GV * const gv = cxstack[cxstack_ix].blk_format.gv; register IO * const io = GvIOp(gv); - PerlIO * const ofp = IoOFP(io); + PerlIO *ofp; PerlIO *fp; SV **newsp; I32 gimme; register PERL_CONTEXT *cx; + if (!io || !(ofp = IoOFP(io))) + goto forget_top; + DEBUG_f(PerlIO_printf(Perl_debug_log, "left=%ld, todo=%ld\n", (long)IoLINES_LEFT(io), (long)FmLINES(PL_formtarget))); - if (!io || !ofp) - goto forget_top; + if (IoLINES_LEFT(io) < FmLINES(PL_formtarget) && PL_formtarget != PL_toptarget) { @@ -1378,15 +1400,13 @@ PP(pp_leavewrite) gv_efullname4(sv, fgv, NULL, FALSE); name = SvPV_nolen_const(sv); if (name && *name) - DIE(aTHX_ "Undefined top format \"%s\" called",name); + DIE(aTHX_ "Undefined top format \"%s\" called", name); + else + DIE(aTHX_ "Undefined top format called"); } - /* why no: - else - DIE(aTHX_ "Undefined top format called"); - ?*/ - if (CvCLONE(cv)) - cv = (CV*)sv_2mortal((SV*)cv_clone(cv)); - return doform(cv,gv,PL_op); + if (cv && CvCLONE(cv)) + cv = MUTABLE_CV(sv_2mortal(MUTABLE_SV(cv_clone(cv)))); + return doform(cv, gv, PL_op); } forget_top: @@ -1434,30 +1454,31 @@ PP(pp_prtf) IO *io; PerlIO *fp; SV *sv; - MAGIC *mg; - GV * const gv = (PL_op->op_flags & OPf_STACKED) ? (GV*)*++MARK : PL_defoutgv; + GV * const gv + = (PL_op->op_flags & OPf_STACKED) ? MUTABLE_GV(*++MARK) : PL_defoutgv; - if (gv && (io = GvIO(gv)) - && (mg = SvTIED_mg((SV*)io, PERL_MAGIC_tiedscalar))) - { - if (MARK == ORIGMARK) { - MEXTEND(SP, 1); - ++MARK; - Move(MARK, MARK + 1, (SP - MARK) + 1, SV*); - ++SP; + if (gv && (io = GvIO(gv))) { + MAGIC * const mg = SvTIED_mg((const SV *)io, PERL_MAGIC_tiedscalar); + if (mg) { + if (MARK == ORIGMARK) { + MEXTEND(SP, 1); + ++MARK; + Move(MARK, MARK + 1, (SP - MARK) + 1, SV*); + ++SP; + } + PUSHMARK(MARK - 1); + *MARK = SvTIED_obj(MUTABLE_SV(io), mg); + PUTBACK; + ENTER; + call_method("PRINTF", G_SCALAR); + LEAVE; + SPAGAIN; + MARK = ORIGMARK + 1; + *MARK = *SP; + SP = MARK; + RETURN; } - PUSHMARK(MARK - 1); - *MARK = SvTIED_obj((SV*)io, mg); - PUTBACK; - ENTER; - call_method("PRINTF", G_SCALAR); - LEAVE; - SPAGAIN; - MARK = ORIGMARK + 1; - *MARK = *SP; - SP = MARK; - RETURN; } sv = newSV(0); @@ -1478,6 +1499,8 @@ PP(pp_prtf) goto just_say_no; } else { + if (SvTAINTED(MARK[1])) + TAINT_PROPER("printf"); do_sprintf(sv, SP - MARK, MARK + 1); if (!do_print(sv, fp)) goto just_say_no; @@ -1505,13 +1528,13 @@ PP(pp_sysopen) const int perm = (MAXARG > 3) ? POPi : 0666; const int mode = POPi; SV * const sv = POPs; - GV * const gv = (GV *)POPs; + GV * const gv = MUTABLE_GV(POPs); STRLEN len; /* Need TIEHANDLE method ? */ const char * const tmps = SvPV_const(sv, len); /* FIXME? do_open should do const */ - if (do_open(gv, tmps, len, TRUE, mode, perm, Nullfp)) { + if (do_open(gv, tmps, len, TRUE, mode, perm, NULL)) { IoLINES(GvIOp(gv)) = 0; PUSHs(&PL_sv_yes); } @@ -1541,15 +1564,15 @@ PP(pp_sysread) STRLEN charskip = 0; STRLEN skip = 0; - GV * const gv = (GV*)*++MARK; + GV * const gv = MUTABLE_GV(*++MARK); if ((PL_op->op_type == OP_READ || PL_op->op_type == OP_SYSREAD) && gv && (io = GvIO(gv)) ) { - const MAGIC * mg = SvTIED_mg((SV*)io, PERL_MAGIC_tiedscalar); + const MAGIC * mg = SvTIED_mg((const SV *)io, PERL_MAGIC_tiedscalar); if (mg) { SV *sv; PUSHMARK(MARK-1); - *MARK = SvTIED_obj((SV*)io, mg); + *MARK = SvTIED_obj(MUTABLE_SV(io), mg); ENTER; call_method("READ", G_SCALAR); LEAVE; @@ -1565,7 +1588,7 @@ PP(pp_sysread) goto say_undef; bufsv = *++MARK; if (! SvOK(bufsv)) - sv_setpvn(bufsv, "", 0); + sv_setpvs(bufsv, ""); length = SvIVx(*++MARK); SETERRNO(0,0); if (MARK < SP) @@ -1612,7 +1635,7 @@ PP(pp_sysread) buffer = SvGROW(bufsv, (STRLEN)(length+1)); /* 'offset' means 'flags' here */ count = PerlSock_recvfrom(PerlIO_fileno(IoIFP(io)), buffer, length, offset, - (struct sockaddr *)namebuf, &bufsize); + (struct sockaddr *)namebuf, &bufsize); if (count < 0) RETPUSHUNDEF; #ifdef EPOC @@ -1780,102 +1803,163 @@ PP(pp_send) IO *io; SV *bufsv; const char *buffer; - Size_t length = 0; SSize_t retval; STRLEN blen; - MAGIC *mg; + STRLEN orig_blen_bytes; const int op_type = PL_op->op_type; + bool doing_utf8; + U8 *tmpbuf = NULL; - GV *const gv = (GV*)*++MARK; + GV *const gv = MUTABLE_GV(*++MARK); if (PL_op->op_type == OP_SYSWRITE - && gv && (io = GvIO(gv)) - && (mg = SvTIED_mg((SV*)io, PERL_MAGIC_tiedscalar))) - { - SV *sv; + && gv && (io = GvIO(gv))) { + MAGIC * const mg = SvTIED_mg((const SV *)io, PERL_MAGIC_tiedscalar); + if (mg) { + SV *sv; + + if (MARK == SP - 1) { + EXTEND(SP, 1000); + sv = sv_2mortal(newSViv(sv_len(*SP))); + PUSHs(sv); + PUTBACK; + } - if (MARK == SP - 1) { - EXTEND(SP, 1000); - sv = sv_2mortal(newSViv(sv_len(*SP))); + PUSHMARK(ORIGMARK); + *(ORIGMARK+1) = SvTIED_obj(MUTABLE_SV(io), mg); + ENTER; + call_method("WRITE", G_SCALAR); + LEAVE; + SPAGAIN; + sv = POPs; + SP = ORIGMARK; PUSHs(sv); - PUTBACK; + RETURN; } - - PUSHMARK(ORIGMARK); - *(ORIGMARK+1) = SvTIED_obj((SV*)io, mg); - ENTER; - call_method("WRITE", G_SCALAR); - LEAVE; - SPAGAIN; - sv = POPs; - SP = ORIGMARK; - PUSHs(sv); - RETURN; } if (!gv) goto say_undef; bufsv = *++MARK; - if (op_type == OP_SYSWRITE) { - if (MARK >= SP) { - length = (Size_t) sv_len(bufsv); - } else { -#if Size_t_size > IVSIZE - length = (Size_t)SvNVx(*++MARK); -#else - length = (Size_t)SvIVx(*++MARK); -#endif - if ((SSize_t)length < 0) - DIE(aTHX_ "Negative length"); - } - } SETERRNO(0,0); io = GvIO(gv); - if (!io || !IoIFP(io)) { + if (!io || !IoIFP(io) || IoTYPE(io) == IoTYPE_RDONLY) { retval = -1; - if (ckWARN(WARN_CLOSED)) - report_evil_fh(gv, io, PL_op->op_type); + if (ckWARN2(WARN_UNOPENED,WARN_CLOSED)) { + if (io && IoIFP(io)) + report_evil_fh(gv, io, OP_phoney_INPUT_ONLY); + else + report_evil_fh(gv, io, PL_op->op_type); + } SETERRNO(EBADF,RMS_IFI); goto say_undef; } + /* Do this first to trigger any overloading. */ + buffer = SvPV_const(bufsv, blen); + orig_blen_bytes = blen; + doing_utf8 = DO_UTF8(bufsv); + if (PerlIO_isutf8(IoIFP(io))) { if (!SvUTF8(bufsv)) { - bufsv = sv_2mortal(newSVsv(bufsv)); - buffer = sv_2pvutf8(bufsv, &blen); - } else - buffer = SvPV_const(bufsv, blen); + /* We don't modify the original scalar. */ + tmpbuf = bytes_to_utf8((const U8*) buffer, &blen); + buffer = (char *) tmpbuf; + doing_utf8 = TRUE; + } } - else { - if (DO_UTF8(bufsv)) { - /* Not modifying source SV, so making a temporary copy. */ - bufsv = sv_2mortal(newSVsv(bufsv)); - sv_utf8_downgrade(bufsv, FALSE); - } - buffer = SvPV_const(bufsv, blen); + else if (doing_utf8) { + STRLEN tmplen = blen; + U8 * const result = bytes_from_utf8((const U8*) buffer, &tmplen, &doing_utf8); + if (!doing_utf8) { + tmpbuf = result; + buffer = (char *) tmpbuf; + blen = tmplen; + } + else { + assert((char *)result == buffer); + Perl_croak(aTHX_ "Wide character in %s", OP_DESC(PL_op)); + } } if (op_type == OP_SYSWRITE) { + Size_t length = 0; /* This length is in characters. */ + STRLEN blen_chars; IV offset; - if (DO_UTF8(bufsv)) { - /* length and offset are in chars */ - blen = sv_len_utf8(bufsv); + + if (doing_utf8) { + if (tmpbuf) { + /* The SV is bytes, and we've had to upgrade it. */ + blen_chars = orig_blen_bytes; + } else { + /* The SV really is UTF-8. */ + if (SvGMAGICAL(bufsv) || SvAMAGIC(bufsv)) { + /* Don't call sv_len_utf8 again because it will call magic + or overloading a second time, and we might get back a + different result. */ + blen_chars = utf8_length((U8*)buffer, (U8*)buffer + blen); + } else { + /* It's safe, and it may well be cached. */ + blen_chars = sv_len_utf8(bufsv); + } + } + } else { + blen_chars = blen; } + + if (MARK >= SP) { + length = blen_chars; + } else { +#if Size_t_size > IVSIZE + length = (Size_t)SvNVx(*++MARK); +#else + length = (Size_t)SvIVx(*++MARK); +#endif + if ((SSize_t)length < 0) { + Safefree(tmpbuf); + DIE(aTHX_ "Negative length"); + } + } + if (MARK < SP) { offset = SvIVx(*++MARK); if (offset < 0) { - if (-offset > (IV)blen) + if (-offset > (IV)blen_chars) { + Safefree(tmpbuf); DIE(aTHX_ "Offset outside string"); - offset += blen; - } else if (offset >= (IV)blen && blen > 0) + } + offset += blen_chars; + } else if (offset >= (IV)blen_chars && blen_chars > 0) { + Safefree(tmpbuf); DIE(aTHX_ "Offset outside string"); + } } else offset = 0; - if (length > blen - offset) - length = blen - offset; - if (DO_UTF8(bufsv)) { - buffer = (const char*)utf8_hop((const U8 *)buffer, offset); - length = utf8_hop((U8 *)buffer, length) - (U8 *)buffer; + if (length > blen_chars - offset) + length = blen_chars - offset; + if (doing_utf8) { + /* Here we convert length from characters to bytes. */ + if (tmpbuf || SvGMAGICAL(bufsv) || SvAMAGIC(bufsv)) { + /* Either we had to convert the SV, or the SV is magical, or + the SV has overloading, in which case we can't or mustn't + or mustn't call it again. */ + + buffer = (const char*)utf8_hop((const U8 *)buffer, offset); + length = utf8_hop((U8 *)buffer, length) - (U8 *)buffer; + } else { + /* It's a real UTF-8 SV, and it's not going to change under + us. Take advantage of any cache. */ + I32 start = offset; + I32 len_I32 = length; + + /* Convert the start and end character positions to bytes. + Remember that the second argument to sv_pos_u2b is relative + to the first. */ + sv_pos_u2b(bufsv, &start, &len_I32); + + buffer += start; + length = len_I32; + } } else { buffer = buffer+offset; @@ -1911,11 +1995,14 @@ PP(pp_send) else DIE(aTHX_ PL_no_sock_func, "send"); #endif + if (retval < 0) goto say_undef; SP = ORIGMARK; - if (DO_UTF8(bufsv)) + if (doing_utf8) retval = utf8_length((U8*)buffer, (U8*)buffer + retval); + + Safefree(tmpbuf); #if Size_t_size > IVSIZE PUSHn(retval); #else @@ -1924,6 +2011,7 @@ PP(pp_send) RETURN; say_undef: + Safefree(tmpbuf); SP = ORIGMARK; RETPUSHUNDEF; } @@ -1932,46 +2020,60 @@ PP(pp_eof) { dVAR; dSP; GV *gv; + IO *io; + MAGIC *mg; - if (MAXARG == 0) { - if (PL_op->op_flags & OPf_SPECIAL) { /* eof() */ - IO *io; - gv = PL_last_in_gv = GvEGV(PL_argvgv); - io = GvIO(gv); - if (io && !IoIFP(io)) { - if ((IoFLAGS(io) & IOf_START) && av_len(GvAVn(gv)) < 0) { - IoLINES(io) = 0; - IoFLAGS(io) &= ~IOf_START; - do_open(gv, "-", 1, FALSE, O_RDONLY, 0, Nullfp); - sv_setpvn(GvSV(gv), "-", 1); - SvSETMAGIC(GvSV(gv)); - } - else if (!nextargv(gv)) - RETPUSHYES; - } - } + if (MAXARG) + gv = PL_last_in_gv = MUTABLE_GV(POPs); /* eof(FH) */ + else if (PL_op->op_flags & OPf_SPECIAL) + gv = PL_last_in_gv = GvEGV(PL_argvgv); /* eof() - ARGV magic */ + else + gv = PL_last_in_gv; /* eof */ + + if (!gv) + RETPUSHNO; + + if ((io = GvIO(gv)) && (mg = SvTIED_mg((const SV *)io, PERL_MAGIC_tiedscalar))) { + PUSHMARK(SP); + XPUSHs(SvTIED_obj(MUTABLE_SV(io), mg)); + /* + * in Perl 5.12 and later, the additional paramter is a bitmask: + * 0 = eof + * 1 = eof(FH) + * 2 = eof() <- ARGV magic + */ + if (MAXARG) + mPUSHi(1); /* 1 = eof(FH) - simple, explicit FH */ + else if (PL_op->op_flags & OPf_SPECIAL) + mPUSHi(2); /* 2 = eof() - ARGV magic */ else - gv = PL_last_in_gv; /* eof */ + mPUSHi(0); /* 0 = eof - simple, implicit FH */ + PUTBACK; + ENTER; + call_method("EOF", G_SCALAR); + LEAVE; + SPAGAIN; + RETURN; } - else - gv = PL_last_in_gv = (GV*)POPs; /* eof(FH) */ - if (gv) { - IO * const io = GvIO(gv); - MAGIC * mg; - if (io && (mg = SvTIED_mg((SV*)io, PERL_MAGIC_tiedscalar))) { - PUSHMARK(SP); - XPUSHs(SvTIED_obj((SV*)io, mg)); - PUTBACK; - ENTER; - call_method("EOF", G_SCALAR); - LEAVE; - SPAGAIN; - RETURN; + if (!MAXARG && (PL_op->op_flags & OPf_SPECIAL)) { /* eof() */ + if (io && !IoIFP(io)) { + if ((IoFLAGS(io) & IOf_START) && av_len(GvAVn(gv)) < 0) { + IoLINES(io) = 0; + IoFLAGS(io) &= ~IOf_START; + do_open(gv, "-", 1, FALSE, O_RDONLY, 0, NULL); + if (GvSV(gv)) + sv_setpvs(GvSV(gv), "-"); + else + GvSV(gv) = newSVpvs("-"); + SvSETMAGIC(GvSV(gv)); + } + else if (!nextargv(gv)) + RETPUSHYES; } } - PUSHs(boolSV(!gv || do_eof(gv))); + PUSHs(boolSV(do_eof(gv))); RETURN; } @@ -1980,23 +2082,23 @@ PP(pp_tell) dVAR; dSP; dTARGET; GV *gv; IO *io; - MAGIC *mg; if (MAXARG != 0) - PL_last_in_gv = (GV*)POPs; + PL_last_in_gv = MUTABLE_GV(POPs); gv = PL_last_in_gv; - if (gv && (io = GvIO(gv)) - && (mg = SvTIED_mg((SV*)io, PERL_MAGIC_tiedscalar))) - { - PUSHMARK(SP); - XPUSHs(SvTIED_obj((SV*)io, mg)); - PUTBACK; - ENTER; - call_method("TELL", G_SCALAR); - LEAVE; - SPAGAIN; - RETURN; + if (gv && (io = GvIO(gv))) { + MAGIC * const mg = SvTIED_mg((const SV *)io, PERL_MAGIC_tiedscalar); + if (mg) { + PUSHMARK(SP); + XPUSHs(SvTIED_obj(MUTABLE_SV(io), mg)); + PUTBACK; + ENTER; + call_method("TELL", G_SCALAR); + LEAVE; + SPAGAIN; + RETURN; + } } #if LSEEKSIZE > IVSIZE @@ -2010,34 +2112,34 @@ PP(pp_tell) PP(pp_sysseek) { dVAR; dSP; - IO *io; const int whence = POPi; #if LSEEKSIZE > IVSIZE const Off_t offset = (Off_t)SvNVx(POPs); #else const Off_t offset = (Off_t)SvIVx(POPs); #endif - MAGIC *mg; - GV * const gv = PL_last_in_gv = (GV*)POPs; + GV * const gv = PL_last_in_gv = MUTABLE_GV(POPs); + IO *io; - if (gv && (io = GvIO(gv)) - && (mg = SvTIED_mg((SV*)io, PERL_MAGIC_tiedscalar))) - { - PUSHMARK(SP); - XPUSHs(SvTIED_obj((SV*)io, mg)); + if (gv && (io = GvIO(gv))) { + MAGIC * const mg = SvTIED_mg((const SV *)io, PERL_MAGIC_tiedscalar); + if (mg) { + PUSHMARK(SP); + XPUSHs(SvTIED_obj(MUTABLE_SV(io), mg)); #if LSEEKSIZE > IVSIZE - XPUSHs(sv_2mortal(newSVnv((NV) offset))); + mXPUSHn((NV) offset); #else - XPUSHs(sv_2mortal(newSViv(offset))); + mXPUSHi(offset); #endif - XPUSHs(sv_2mortal(newSViv(whence))); - PUTBACK; - ENTER; - call_method("SEEK", G_SCALAR); - LEAVE; - SPAGAIN; - RETURN; + mXPUSHi(whence); + PUTBACK; + ENTER; + call_method("SEEK", G_SCALAR); + LEAVE; + SPAGAIN; + RETURN; + } } if (PL_op->op_type == OP_SEEK) @@ -2054,7 +2156,7 @@ PP(pp_sysseek) newSViv(sought) #endif : newSVpvn(zero_but_true, ZBTLEN); - PUSHs(sv_2mortal(sv)); + mPUSHs(sv); } } RETURN; @@ -2114,16 +2216,16 @@ PP(pp_truncate) SV * const sv = POPs; const char *name; - if (SvTYPE(sv) == SVt_PVGV) { - tmpgv = (GV*)sv; /* *main::FRED for example */ + if (isGV_with_GP(sv)) { + tmpgv = MUTABLE_GV(sv); /* *main::FRED for example */ goto do_ftruncate_gv; } - else if (SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PVGV) { - tmpgv = (GV*) SvRV(sv); /* \*main::FRED for example */ + else if (SvROK(sv) && isGV_with_GP(SvRV(sv))) { + tmpgv = MUTABLE_GV(SvRV(sv)); /* \*main::FRED for example */ goto do_ftruncate_gv; } else if (SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PVIO) { - io = (IO*) SvRV(sv); /* *main::FRED{IO} for example */ + io = MUTABLE_IO(SvRV(sv)); /* *main::FRED{IO} for example */ goto do_ftruncate_io; } @@ -2161,8 +2263,8 @@ PP(pp_ioctl) SV * const argsv = POPs; const unsigned int func = POPu; const int optype = PL_op->op_type; - GV * const gv = (GV*)POPs; - IO * const io = gv ? GvIOn(gv) : Null(IO*); + GV * const gv = MUTABLE_GV(POPs); + IO * const io = gv ? GvIOn(gv) : NULL; char *s; IV retval; @@ -2238,12 +2340,12 @@ PP(pp_flock) IO *io = NULL; PerlIO *fp; const int argtype = POPi; - GV * const gv = (MAXARG == 0) ? PL_last_in_gv : (GV*)POPs; + GV * const gv = (MAXARG == 0) ? PL_last_in_gv : MUTABLE_GV(POPs); if (gv && (io = GvIO(gv))) fp = IoIFP(io); else { - fp = Nullfp; + fp = NULL; io = NULL; } /* XXX Looks to me like io is always NULL at this point */ @@ -2273,14 +2375,14 @@ PP(pp_socket) const int protocol = POPi; const int type = POPi; const int domain = POPi; - GV * const gv = (GV*)POPs; + GV * const gv = MUTABLE_GV(POPs); register IO * const io = gv ? GvIOn(gv) : NULL; int fd; if (!gv || !io) { if (ckWARN2(WARN_UNOPENED,WARN_CLOSED)) report_evil_fh(gv, io, PL_op->op_type); - if (IoIFP(io)) + if (io && IoIFP(io)) do_close(gv, FALSE); SETERRNO(EBADF,LIB_INVARG); RETPUSHUNDEF; @@ -2323,8 +2425,8 @@ PP(pp_sockpair) const int protocol = POPi; const int type = POPi; const int domain = POPi; - GV * const gv2 = (GV*)POPs; - GV * const gv1 = (GV*)POPs; + GV * const gv2 = MUTABLE_GV(POPs); + GV * const gv1 = MUTABLE_GV(POPs); register IO * const io1 = gv1 ? GvIOn(gv1) : NULL; register IO * const io2 = gv2 ? GvIOn(gv2) : NULL; int fd[2]; @@ -2336,9 +2438,9 @@ PP(pp_sockpair) if (!gv2 || !io2) report_evil_fh(gv1, io2, PL_op->op_type); } - if (IoIFP(io1)) + if (io1 && IoIFP(io1)) do_close(gv1, FALSE); - if (IoIFP(io2)) + if (io2 && IoIFP(io2)) do_close(gv2, FALSE); RETPUSHUNDEF; } @@ -2384,22 +2486,16 @@ PP(pp_bind) SV * const addrsv = POPs; /* OK, so on what platform does bind modify addr? */ const char *addr; - GV * const gv = (GV*)POPs; + GV * const gv = MUTABLE_GV(POPs); register IO * const io = GvIOn(gv); STRLEN len; - int bind_ok = 0; if (!io || !IoIFP(io)) goto nuts; addr = SvPV_const(addrsv, len); TAINT_PROPER("bind"); - if (PerlSock_bind(PerlIO_fileno(IoIFP(io)), - (struct sockaddr *)addr, len) >= 0) - bind_ok = 1; - - - if (bind_ok) + if (PerlSock_bind(PerlIO_fileno(IoIFP(io)), (struct sockaddr *)addr, len) >= 0) RETPUSHYES; else RETPUSHUNDEF; @@ -2419,7 +2515,7 @@ PP(pp_connect) #ifdef HAS_SOCKET dVAR; dSP; SV * const addrsv = POPs; - GV * const gv = (GV*)POPs; + GV * const gv = MUTABLE_GV(POPs); register IO * const io = GvIOn(gv); const char *addr; STRLEN len; @@ -2449,7 +2545,7 @@ PP(pp_listen) #ifdef HAS_SOCKET dVAR; dSP; const int backlog = POPi; - GV * const gv = (GV*)POPs; + GV * const gv = MUTABLE_GV(POPs); register IO * const io = gv ? GvIOn(gv) : NULL; if (!gv || !io || !IoIFP(io)) @@ -2482,8 +2578,8 @@ PP(pp_accept) #else Sock_size_t len = sizeof namebuf; #endif - GV * const ggv = (GV*)POPs; - GV * const ngv = (GV*)POPs; + GV * const ggv = MUTABLE_GV(POPs); + GV * const ngv = MUTABLE_GV(POPs); int fd; if (!ngv) @@ -2497,6 +2593,17 @@ PP(pp_accept) nstio = GvIOn(ngv); fd = PerlSock_accept(PerlIO_fileno(IoIFP(gstio)), (struct sockaddr *) namebuf, &len); +#if defined(OEMVS) + if (len == 0) { + /* Some platforms indicate zero length when an AF_UNIX client is + * not bound. Simulate a non-zero-length sockaddr structure in + * this case. */ + namebuf[0] = 0; /* sun_len */ + namebuf[1] = AF_UNIX; /* sun_family */ + len = 2; + } +#endif + if (fd < 0) goto badexit; if (IoIFP(nstio)) @@ -2543,7 +2650,7 @@ PP(pp_shutdown) #ifdef HAS_SOCKET dVAR; dSP; dTARGET; const int how = POPi; - GV * const gv = (GV*)POPs; + GV * const gv = MUTABLE_GV(POPs); register IO * const io = GvIOn(gv); if (!io || !IoIFP(io)) @@ -2570,7 +2677,7 @@ PP(pp_ssockopt) SV * const sv = (optype == OP_GSOCKOPT) ? sv_2mortal(newSV(257)) : POPs; const unsigned int optname = (unsigned int) POPi; const unsigned int lvl = (unsigned int) POPi; - GV * const gv = (GV*)POPs; + GV * const gv = MUTABLE_GV(POPs); register IO * const io = GvIOn(gv); int fd; Sock_size_t len; @@ -2644,7 +2751,7 @@ PP(pp_getpeername) #ifdef HAS_SOCKET dVAR; dSP; const int optype = PL_op->op_type; - GV * const gv = (GV*)POPs; + GV * const gv = MUTABLE_GV(POPs); register IO * const io = GvIOn(gv); Sock_size_t len; SV *sv; @@ -2709,7 +2816,8 @@ PP(pp_stat) { dVAR; dSP; - GV *gv; + GV *gv = NULL; + IO *io; I32 gimme; I32 max = 13; @@ -2720,7 +2828,7 @@ PP(pp_stat) do_fstat_warning_check: if (ckWARN(WARN_IO)) Perl_warner(aTHX_ packWARN(WARN_IO), - "lstat() on filehandle %s", GvENAME(gv)); + "lstat() on filehandle %s", gv ? GvENAME(gv) : ""); } else if (PL_laststype != OP_LSTAT) Perl_croak(aTHX_ "The stat preceding lstat() wasn't an lstat"); } @@ -2729,10 +2837,24 @@ PP(pp_stat) if (gv != PL_defgv) { PL_laststype = OP_STAT; PL_statgv = gv; - sv_setpvn(PL_statname, "", 0); - PL_laststatval = (GvIO(gv) && IoIFP(GvIOp(gv)) - ? PerlLIO_fstat(PerlIO_fileno(IoIFP(GvIOn(gv))), &PL_statcache) : -1); - } + sv_setpvs(PL_statname, ""); + if(gv) { + io = GvIO(gv); + do_fstat_have_io: + if (io) { + if (IoIFP(io)) { + PL_laststatval = + PerlLIO_fstat(PerlIO_fileno(IoIFP(io)), &PL_statcache); + } else if (IoDIRP(io)) { + PL_laststatval = + PerlLIO_fstat(my_dirfd(IoDIRP(io)), &PL_statcache); + } else { + PL_laststatval = -1; + } + } + } + } + if (PL_laststatval < 0) { if (ckWARN2(WARN_UNOPENED,WARN_CLOSED)) report_evil_fh(gv, GvIO(gv), PL_op->op_type); @@ -2741,16 +2863,21 @@ PP(pp_stat) } else { SV* const sv = POPs; - if (SvTYPE(sv) == SVt_PVGV) { - gv = (GV*)sv; + if (isGV_with_GP(sv)) { + gv = MUTABLE_GV(sv); goto do_fstat; - } - else if (SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PVGV) { - gv = (GV*)SvRV(sv); - if (PL_op->op_type == OP_LSTAT) - goto do_fstat_warning_check; - goto do_fstat; - } + } else if(SvROK(sv) && isGV_with_GP(SvRV(sv))) { + gv = MUTABLE_GV(SvRV(sv)); + if (PL_op->op_type == OP_LSTAT) + goto do_fstat_warning_check; + goto do_fstat; + } else if (SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PVIO) { + io = MUTABLE_IO(SvRV(sv)); + if (PL_op->op_type == OP_LSTAT) + goto do_fstat_warning_check; + goto do_fstat_have_io; + } + sv_setpv(PL_statname, SvPV_nolen_const(sv)); PL_statgv = NULL; PL_laststype = PL_op->op_type; @@ -2774,53 +2901,53 @@ PP(pp_stat) if (max) { EXTEND(SP, max); EXTEND_MORTAL(max); - PUSHs(sv_2mortal(newSViv(PL_statcache.st_dev))); - PUSHs(sv_2mortal(newSViv(PL_statcache.st_ino))); - PUSHs(sv_2mortal(newSVuv(PL_statcache.st_mode))); - PUSHs(sv_2mortal(newSVuv(PL_statcache.st_nlink))); + mPUSHi(PL_statcache.st_dev); + mPUSHi(PL_statcache.st_ino); + mPUSHu(PL_statcache.st_mode); + mPUSHu(PL_statcache.st_nlink); #if Uid_t_size > IVSIZE - PUSHs(sv_2mortal(newSVnv(PL_statcache.st_uid))); + mPUSHn(PL_statcache.st_uid); #else # if Uid_t_sign <= 0 - PUSHs(sv_2mortal(newSViv(PL_statcache.st_uid))); + mPUSHi(PL_statcache.st_uid); # else - PUSHs(sv_2mortal(newSVuv(PL_statcache.st_uid))); + mPUSHu(PL_statcache.st_uid); # endif #endif #if Gid_t_size > IVSIZE - PUSHs(sv_2mortal(newSVnv(PL_statcache.st_gid))); + mPUSHn(PL_statcache.st_gid); #else # if Gid_t_sign <= 0 - PUSHs(sv_2mortal(newSViv(PL_statcache.st_gid))); + mPUSHi(PL_statcache.st_gid); # else - PUSHs(sv_2mortal(newSVuv(PL_statcache.st_gid))); + mPUSHu(PL_statcache.st_gid); # endif #endif #ifdef USE_STAT_RDEV - PUSHs(sv_2mortal(newSViv(PL_statcache.st_rdev))); + mPUSHi(PL_statcache.st_rdev); #else - PUSHs(sv_2mortal(newSVpvs(""))); + PUSHs(newSVpvs_flags("", SVs_TEMP)); #endif #if Off_t_size > IVSIZE - PUSHs(sv_2mortal(newSVnv((NV)PL_statcache.st_size))); + mPUSHn(PL_statcache.st_size); #else - PUSHs(sv_2mortal(newSViv(PL_statcache.st_size))); + mPUSHi(PL_statcache.st_size); #endif #ifdef BIG_TIME - PUSHs(sv_2mortal(newSVnv(PL_statcache.st_atime))); - PUSHs(sv_2mortal(newSVnv(PL_statcache.st_mtime))); - PUSHs(sv_2mortal(newSVnv(PL_statcache.st_ctime))); + mPUSHn(PL_statcache.st_atime); + mPUSHn(PL_statcache.st_mtime); + mPUSHn(PL_statcache.st_ctime); #else - PUSHs(sv_2mortal(newSViv(PL_statcache.st_atime))); - PUSHs(sv_2mortal(newSViv(PL_statcache.st_mtime))); - PUSHs(sv_2mortal(newSViv(PL_statcache.st_ctime))); + mPUSHi(PL_statcache.st_atime); + mPUSHi(PL_statcache.st_mtime); + mPUSHi(PL_statcache.st_ctime); #endif #ifdef USE_STAT_BLOCKS - PUSHs(sv_2mortal(newSVuv(PL_statcache.st_blksize))); - PUSHs(sv_2mortal(newSVuv(PL_statcache.st_blocks))); + mPUSHu(PL_statcache.st_blksize); + mPUSHu(PL_statcache.st_blocks); #else - PUSHs(sv_2mortal(newSVpvs(""))); - PUSHs(sv_2mortal(newSVpvs(""))); + PUSHs(newSVpvs_flags("", SVs_TEMP)); + PUSHs(newSVpvs_flags("", SVs_TEMP)); #endif } RETURN; @@ -2831,7 +2958,7 @@ PP(pp_stat) * Else, discard it from the stack and continue. --rgs */ #define STACKED_FTEST_CHECK if (PL_op->op_private & OPpFT_STACKED) { \ - if (TOPs == &PL_sv_no || TOPs == &PL_sv_undef) { RETURN; } \ + if (!SvTRUE(TOPs)) { RETURN; } \ else { (void)POPs; PUTBACK; } \ } @@ -2900,10 +3027,9 @@ PP(pp_ftrread) effective = TRUE; break; - case OP_FTEEXEC: #ifdef PERL_EFF_ACCESS - access_mode = W_OK; + access_mode = X_OK; #else use_access = 0; #endif @@ -2914,7 +3040,7 @@ PP(pp_ftrread) if (use_access) { #if defined(HAS_ACCESS) || defined (PERL_EFF_ACCESS) - const char *const name = POPpx; + const char *name = POPpx; if (effective) { # ifdef PERL_EFF_ACCESS result = PERL_EFF_ACCESS(name, access_mode); @@ -3096,9 +3222,9 @@ PP(pp_fttty) if (PL_op->op_flags & OPf_REF) gv = cGVOP_gv; else if (isGV(TOPs)) - gv = (GV*)POPs; + gv = MUTABLE_GV(POPs); else if (SvROK(TOPs) && isGV(SvRV(TOPs))) - gv = (GV*)SvRV(POPs); + gv = MUTABLE_GV(SvRV(POPs)); else gv = gv_fetchsv(tmpsv = POPs, 0, SVt_PVIO); @@ -3145,9 +3271,9 @@ PP(pp_fttext) if (PL_op->op_flags & OPf_REF) gv = cGVOP_gv; else if (isGV(TOPs)) - gv = (GV*)POPs; + gv = MUTABLE_GV(POPs); else if (SvROK(TOPs) && isGV(SvRV(TOPs))) - gv = (GV*)SvRV(POPs); + gv = MUTABLE_GV(SvRV(POPs)); else gv = NULL; @@ -3164,7 +3290,7 @@ PP(pp_fttext) else { PL_statgv = gv; PL_laststatval = -1; - sv_setpvn(PL_statname, "", 0); + sv_setpvs(PL_statname, ""); io = GvIO(PL_statgv); } if (io && IoIFP(io)) { @@ -3234,7 +3360,7 @@ PP(pp_fttext) #if defined(DOSISH) || defined(USEMYBINMODE) /* ignore trailing ^Z on short files */ - if (len && len < sizeof(tbuf) && tbuf[len-1] == 26) + if (len && len < (I32)sizeof(tbuf) && tbuf[len-1] == 26) --len; #endif @@ -3296,14 +3422,14 @@ PP(pp_chdir) if (PL_op->op_flags & OPf_SPECIAL) { gv = gv_fetchsv(sv, 0, SVt_PVIO); } - else if (SvTYPE(sv) == SVt_PVGV) { - gv = (GV*)sv; + else if (isGV_with_GP(sv)) { + gv = MUTABLE_GV(sv); } - else if (SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PVGV) { - gv = (GV*)SvRV(sv); + else if (SvROK(sv) && isGV_with_GP(SvRV(sv))) { + gv = MUTABLE_GV(SvRV(sv)); } else { - tmps = SvPVx_nolen_const(sv); + tmps = SvPV_nolen_const(sv); } } @@ -3334,21 +3460,22 @@ PP(pp_chdir) #ifdef HAS_FCHDIR IO* const io = GvIO(gv); if (io) { - if (IoIFP(io)) { - PUSHi(fchdir(PerlIO_fileno(IoIFP(io))) >= 0); - } - else if (IoDIRP(io)) { -#ifdef HAS_DIRFD - PUSHi(fchdir(dirfd(IoDIRP(io))) >= 0); -#else - DIE(aTHX_ PL_no_func, "dirfd"); -#endif + if (IoDIRP(io)) { + PUSHi(fchdir(my_dirfd(IoDIRP(io))) >= 0); + } else if (IoIFP(io)) { + PUSHi(fchdir(PerlIO_fileno(IoIFP(io))) >= 0); } else { + if (ckWARN2(WARN_UNOPENED,WARN_CLOSED)) + report_evil_fh(gv, io, PL_op->op_type); + SETERRNO(EBADF, RMS_IFI); PUSHi(0); } } else { + if (ckWARN2(WARN_UNOPENED,WARN_CLOSED)) + report_evil_fh(gv, io, PL_op->op_type); + SETERRNO(EBADF,RMS_IFI); PUSHi(0); } #else @@ -3497,15 +3624,19 @@ S_dooneliner(pTHX_ const char *cmd, const char *filename) char *s; PerlIO *myfp; int anum = 1; + Size_t size = strlen(cmd) + (strlen(filename) * 2) + 10; + + PERL_ARGS_ASSERT_DOONELINER; - Newx(cmdline, strlen(cmd) + (strlen(filename) * 2) + 10, char); - strcpy(cmdline, cmd); - strcat(cmdline, " "); + Newx(cmdline, size, char); + my_strlcpy(cmdline, cmd, size); + my_strlcat(cmdline, " ", size); for (s = cmdline + strlen(cmdline); *filename; ) { *s++ = '\\'; *s++ = *filename++; } - strcpy(s, " 2>&1"); + if (s - cmdline < size) + my_strlcpy(s, " 2>&1", size - (s - cmdline)); myfp = PerlProc_popen(cmdline, "r"); Safefree(cmdline); @@ -3648,12 +3779,15 @@ PP(pp_open_dir) #if defined(Direntry_t) && defined(HAS_READDIR) dVAR; dSP; const char * const dirname = POPpconstx; - GV * const gv = (GV*)POPs; + GV * const gv = MUTABLE_GV(POPs); register IO * const io = GvIOn(gv); if (!io) goto nope; + if ((IoIFP(io) || IoOFP(io)) && ckWARN2(WARN_IO, WARN_DEPRECATED)) + Perl_warner(aTHX_ packWARN2(WARN_IO, WARN_DEPRECATED), + "Opening filehandle %s also as a directory", GvENAME(gv)); if (IoDIRP(io)) PerlDir_close(IoDIRP(io)); if (!(IoDIRP(io) = PerlDir_open(dirname))) @@ -3682,7 +3816,7 @@ PP(pp_readdir) SV *sv; const I32 gimme = GIMME; - GV * const gv = (GV *)POPs; + GV * const gv = MUTABLE_GV(POPs); register const Direntry_t *dp; register IO * const io = GvIOn(gv); @@ -3707,9 +3841,8 @@ PP(pp_readdir) if (!(IoFLAGS(io) & IOf_UNTAINT)) SvTAINTED_on(sv); #endif - XPUSHs(sv_2mortal(sv)); - } - while (gimme == G_ARRAY); + mXPUSHs(sv); + } while (gimme == G_ARRAY); if (!dp && gimme != G_ARRAY) goto nope; @@ -3737,7 +3870,7 @@ PP(pp_telldir) # if !defined(HAS_TELLDIR_PROTO) || defined(NEED_TELLDIR_PROTO) long telldir (DIR *); # endif - GV * const gv = (GV*)POPs; + GV * const gv = MUTABLE_GV(POPs); register IO * const io = GvIOn(gv); if (!io || !IoDIRP(io)) { @@ -3764,7 +3897,7 @@ PP(pp_seekdir) #if defined(HAS_SEEKDIR) || defined(seekdir) dVAR; dSP; const long along = POPl; - GV * const gv = (GV*)POPs; + GV * const gv = MUTABLE_GV(POPs); register IO * const io = GvIOn(gv); if (!io || !IoDIRP(io)) { @@ -3790,7 +3923,7 @@ PP(pp_rewinddir) { #if defined(HAS_REWINDDIR) || defined(rewinddir) dVAR; dSP; - GV * const gv = (GV*)POPs; + GV * const gv = MUTABLE_GV(POPs); register IO * const io = GvIOn(gv); if (!io || !IoDIRP(io)) { @@ -3815,7 +3948,7 @@ PP(pp_closedir) { #if defined(Direntry_t) && defined(HAS_READDIR) dVAR; dSP; - GV * const gv = (GV*)POPs; + GV * const gv = MUTABLE_GV(POPs); register IO * const io = GvIOn(gv); if (!io || !IoDIRP(io)) { @@ -3894,7 +4027,7 @@ PP(pp_fork) PP(pp_wait) { -#if (!defined(DOSISH) || defined(OS2) || defined(WIN32)) && !defined(MACOS_TRADITIONAL) +#if (!defined(DOSISH) || defined(OS2) || defined(WIN32)) && !defined(MACOS_TRADITIONAL) && !defined(__LIBCATAMOUNT__) dVAR; dSP; dTARGET; Pid_t childpid; int argflags; @@ -3922,7 +4055,7 @@ PP(pp_wait) PP(pp_waitpid) { -#if (!defined(DOSISH) || defined(OS2) || defined(WIN32)) && !defined(MACOS_TRADITIONAL) +#if (!defined(DOSISH) || defined(OS2) || defined(WIN32)) && !defined(MACOS_TRADITIONAL) && !defined(__LIBCATAMOUNT__) dVAR; dSP; dTARGET; const int optype = POPi; const Pid_t pid = TOPi; @@ -3953,6 +4086,11 @@ PP(pp_waitpid) PP(pp_system) { dVAR; dSP; dMARK; dORIGMARK; dTARGET; +#if defined(__LIBCATAMOUNT__) + PL_statusvalue = -1; + SP = ORIGMARK; + XPUSHi(-1); +#else I32 value; int result; @@ -4010,7 +4148,8 @@ PP(pp_system) SP = ORIGMARK; if (did_pipes) { int errkid; - int n = 0, n1; + unsigned n = 0; + SSize_t n1; while (n < sizeof(int)) { n1 = PerlLIO_read(pp[0], @@ -4053,14 +4192,14 @@ PP(pp_system) result = 0; if (PL_op->op_flags & OPf_STACKED) { SV * const really = *++MARK; -# if defined(WIN32) || defined(OS2) || defined(__SYMBIAN32__) +# if defined(WIN32) || defined(OS2) || defined(__SYMBIAN32__) || defined(__VMS) value = (I32)do_aspawn(really, MARK, SP); # else value = (I32)do_aspawn(really, (void **)MARK, (void **)SP); # endif } else if (SP - MARK != 1) { -# if defined(WIN32) || defined(OS2) || defined(__SYMBIAN32__) +# if defined(WIN32) || defined(OS2) || defined(__SYMBIAN32__) || defined(__VMS) value = (I32)do_aspawn(NULL, MARK, SP); # else value = (I32)do_aspawn(NULL, (void **)MARK, (void **)SP); @@ -4075,7 +4214,8 @@ PP(pp_system) do_execfree(); SP = ORIGMARK; XPUSHi(result ? value : STATUS_CURRENT); -#endif /* !FORK or VMS */ +#endif /* !FORK or VMS or OS/2 */ +#endif RETURN; } @@ -4178,6 +4318,7 @@ PP(pp_setpgrp) if (MAXARG < 2) { pgrp = 0; pid = 0; + XPUSHi(-1); } else { pgrp = POPi; @@ -4235,9 +4376,9 @@ PP(pp_time) { dVAR; dSP; dTARGET; #ifdef BIG_TIME - XPUSHn( time(Null(Time_t*)) ); + XPUSHn( time(NULL) ); #else - XPUSHi( time(Null(Time_t*)) ); + XPUSHi( time(NULL) ); #endif RETURN; } @@ -4256,22 +4397,22 @@ PP(pp_tms) /* is returned. */ #endif - PUSHs(sv_2mortal(newSVnv(((NV)PL_timesbuf.tms_utime)/(NV)PL_clocktick))); + mPUSHn(((NV)PL_timesbuf.tms_utime)/(NV)PL_clocktick); if (GIMME == G_ARRAY) { - PUSHs(sv_2mortal(newSVnv(((NV)PL_timesbuf.tms_stime)/(NV)PL_clocktick))); - PUSHs(sv_2mortal(newSVnv(((NV)PL_timesbuf.tms_cutime)/(NV)PL_clocktick))); - PUSHs(sv_2mortal(newSVnv(((NV)PL_timesbuf.tms_cstime)/(NV)PL_clocktick))); + mPUSHn(((NV)PL_timesbuf.tms_stime)/(NV)PL_clocktick); + mPUSHn(((NV)PL_timesbuf.tms_cutime)/(NV)PL_clocktick); + mPUSHn(((NV)PL_timesbuf.tms_cstime)/(NV)PL_clocktick); } RETURN; #else # ifdef PERL_MICRO dSP; - PUSHs(sv_2mortal(newSVnv((NV)0.0))); + mPUSHn(0.0); EXTEND(SP, 4); if (GIMME == G_ARRAY) { - PUSHs(sv_2mortal(newSVnv((NV)0.0))); - PUSHs(sv_2mortal(newSVnv((NV)0.0))); - PUSHs(sv_2mortal(newSVnv((NV)0.0))); + mPUSHn(0.0); + mPUSHn(0.0); + mPUSHn(0.0); } RETURN; # else @@ -4280,104 +4421,105 @@ PP(pp_tms) #endif /* HAS_TIMES */ } -#ifdef LOCALTIME_EDGECASE_BROKEN -static struct tm *S_my_localtime (pTHX_ Time_t *tp) -{ - auto time_t T; - auto struct tm *P; - - /* No workarounds in the valid range */ - if (!tp || *tp < 0x7fff573f || *tp >= 0x80000000) - return (localtime (tp)); - - /* This edge case is to workaround the undefined behaviour, where the - * TIMEZONE makes the time go beyond the defined range. - * gmtime (0x7fffffff) => 2038-01-19 03:14:07 - * If there is a negative offset in TZ, like MET-1METDST, some broken - * implementations of localtime () (like AIX 5.2) barf with bogus - * return values: - * 0x7fffffff gmtime 2038-01-19 03:14:07 - * 0x7fffffff localtime 1901-12-13 21:45:51 - * 0x7fffffff mylocaltime 2038-01-19 04:14:07 - * 0x3c19137f gmtime 2001-12-13 20:45:51 - * 0x3c19137f localtime 2001-12-13 21:45:51 - * 0x3c19137f mylocaltime 2001-12-13 21:45:51 - * Given that legal timezones are typically between GMT-12 and GMT+12 - * we turn back the clock 23 hours before calling the localtime - * function, and add those to the return value. This will never cause - * day wrapping problems, since the edge case is Tue Jan *19* - */ - T = *tp - 82800; /* 23 hour. allows up to GMT-23 */ - P = localtime (&T); - P->tm_hour += 23; - if (P->tm_hour >= 24) { - P->tm_hour -= 24; - P->tm_mday++; /* 18 -> 19 */ - P->tm_wday++; /* Mon -> Tue */ - P->tm_yday++; /* 18 -> 19 */ - } - return (P); -} /* S_my_localtime */ -#endif - PP(pp_gmtime) { dVAR; dSP; +#ifdef PERL_MICRO Time_t when; - const struct tm *tmbuf; + const struct tm *err; + struct tm tmbuf; +#else + Time64_T when; + struct TM tmbuf; + struct TM *err; +#endif + const char *opname = PL_op->op_type == OP_LOCALTIME ? "localtime" : "gmtime"; static const char * const dayname[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; static const char * const monname[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; +#ifdef PERL_MICRO if (MAXARG < 1) (void)time(&when); else -#ifdef BIG_TIME - when = (Time_t)SvNVx(POPs); -#else when = (Time_t)SvIVx(POPs); -#endif if (PL_op->op_type == OP_LOCALTIME) -#ifdef LOCALTIME_EDGECASE_BROKEN - tmbuf = S_my_localtime(aTHX_ &when); + err = localtime(&when); + else + err = gmtime(&when); + + if (!err) + tmbuf = *err; #else - tmbuf = localtime(&when); -#endif + if (MAXARG < 1) { + time_t now; + (void)time(&now); + when = (Time64_T)now; + } + else { + /* XXX POPq uses an SvIV so it won't work with 32 bit integer scalars + using a double causes an unfortunate loss of accuracy on high numbers. + What we really need is an SvQV. + */ + double input = POPn; + when = (Time64_T)input; + if( when != input ) { + Perl_warner(aTHX_ packWARN(WARN_OVERFLOW), + "%s(%.0f) too large", opname, input); + } + } + + if (PL_op->op_type == OP_LOCALTIME) + err = localtime64_r(&when, &tmbuf); else - tmbuf = gmtime(&when); + err = gmtime64_r(&when, &tmbuf); +#endif - if (GIMME != G_ARRAY) { + if( err == NULL ) { + /* XXX %lld broken for quads */ + Perl_warner(aTHX_ packWARN(WARN_OVERFLOW), + "%s(%.0f) failed", opname, (double)when); + } + + if (GIMME != G_ARRAY) { /* scalar context */ SV *tsv; + /* XXX newSVpvf()'s %lld type is broken, so cheat with a double */ + double year = (double)tmbuf.tm_year + 1900; + EXTEND(SP, 1); EXTEND_MORTAL(1); - if (!tmbuf) + if (err == NULL) RETPUSHUNDEF; - tsv = Perl_newSVpvf(aTHX_ "%s %s %2d %02d:%02d:%02d %d", - dayname[tmbuf->tm_wday], - monname[tmbuf->tm_mon], - tmbuf->tm_mday, - tmbuf->tm_hour, - tmbuf->tm_min, - tmbuf->tm_sec, - tmbuf->tm_year + 1900); - PUSHs(sv_2mortal(tsv)); - } - else if (tmbuf) { + + tsv = Perl_newSVpvf(aTHX_ "%s %s %2d %02d:%02d:%02d %.0f", + dayname[tmbuf.tm_wday], + monname[tmbuf.tm_mon], + tmbuf.tm_mday, + tmbuf.tm_hour, + tmbuf.tm_min, + tmbuf.tm_sec, + year); + mPUSHs(tsv); + } + else { /* list context */ + if ( err == NULL ) + RETURN; + EXTEND(SP, 9); EXTEND_MORTAL(9); - PUSHs(sv_2mortal(newSViv(tmbuf->tm_sec))); - PUSHs(sv_2mortal(newSViv(tmbuf->tm_min))); - PUSHs(sv_2mortal(newSViv(tmbuf->tm_hour))); - PUSHs(sv_2mortal(newSViv(tmbuf->tm_mday))); - PUSHs(sv_2mortal(newSViv(tmbuf->tm_mon))); - PUSHs(sv_2mortal(newSViv(tmbuf->tm_year))); - PUSHs(sv_2mortal(newSViv(tmbuf->tm_wday))); - PUSHs(sv_2mortal(newSViv(tmbuf->tm_yday))); - PUSHs(sv_2mortal(newSViv(tmbuf->tm_isdst))); + mPUSHi(tmbuf.tm_sec); + mPUSHi(tmbuf.tm_min); + mPUSHi(tmbuf.tm_hour); + mPUSHi(tmbuf.tm_mday); + mPUSHi(tmbuf.tm_mon); + mPUSHn(tmbuf.tm_year); + mPUSHi(tmbuf.tm_wday); + mPUSHi(tmbuf.tm_yday); + mPUSHi(tmbuf.tm_isdst); } RETURN; } @@ -4488,6 +4630,29 @@ PP(pp_semctl) #endif } +/* I can't const this further without getting warnings about the types of + various arrays passed in from structures. */ +static SV * +S_space_join_names_mortal(pTHX_ char *const *array) +{ + SV *target; + + PERL_ARGS_ASSERT_SPACE_JOIN_NAMES_MORTAL; + + if (array && *array) { + target = newSVpvs_flags("", SVs_TEMP); + while (1) { + sv_catpv(target, *array); + if (!*++array) + break; + sv_catpvs(target, " "); + } + } else { + target = sv_mortalcopy(&PL_sv_no); + } + return target; +} + /* Get system info. */ PP(pp_ghostent) @@ -4519,7 +4684,7 @@ PP(pp_ghostent) const int addrtype = POPi; SV * const addrsv = POPs; STRLEN addrlen; - Netdb_host_t addr = (Netdb_host_t) SvPVbyte(addrsv, addrlen); + const char *addr = (char *)SvPVbyte(addrsv, addrlen); hent = PerlSock_gethostbyaddr(addr, (Netdb_hlen_t) addrlen, addrtype); #else @@ -4558,28 +4723,20 @@ PP(pp_ghostent) } if (hent) { - PUSHs(sv = sv_mortalcopy(&PL_sv_no)); - sv_setpv(sv, (char*)hent->h_name); - PUSHs(sv = sv_mortalcopy(&PL_sv_no)); - for (elem = hent->h_aliases; elem && *elem; elem++) { - sv_catpv(sv, *elem); - if (elem[1]) - sv_catpvs(sv, " "); - } - PUSHs(sv = sv_mortalcopy(&PL_sv_no)); - sv_setiv(sv, (IV)hent->h_addrtype); - PUSHs(sv = sv_mortalcopy(&PL_sv_no)); + mPUSHs(newSVpv((char*)hent->h_name, 0)); + PUSHs(space_join_names_mortal(hent->h_aliases)); + mPUSHi(hent->h_addrtype); len = hent->h_length; - sv_setiv(sv, (IV)len); + mPUSHi(len); #ifdef h_addr for (elem = hent->h_addr_list; elem && *elem; elem++) { - XPUSHs(sv = sv_mortalcopy(&PL_sv_no)); - sv_setpvn(sv, *elem, len); + mXPUSHp(*elem, len); } #else - PUSHs(sv = sv_mortalcopy(&PL_sv_no)); if (hent->h_addr) - sv_setpvn(sv, hent->h_addr, len); + mPUSHp(hent->h_addr, len); + else + PUSHs(sv_mortalcopy(&PL_sv_no)); #endif /* h_addr */ } RETURN; @@ -4593,7 +4750,6 @@ PP(pp_gnetent) #if defined(HAS_GETNETBYNAME) || defined(HAS_GETNETBYADDR) || defined(HAS_GETNETENT) dVAR; dSP; I32 which = PL_op->op_type; - register char **elem; register SV *sv; #ifndef HAS_GETNET_PROTOS /* XXX Do we need individual probes? */ struct netent *getnetbyaddr(Netdb_net_t, int); @@ -4650,18 +4806,10 @@ PP(pp_gnetent) } if (nent) { - PUSHs(sv = sv_mortalcopy(&PL_sv_no)); - sv_setpv(sv, nent->n_name); - PUSHs(sv = sv_mortalcopy(&PL_sv_no)); - for (elem = nent->n_aliases; elem && *elem; elem++) { - sv_catpv(sv, *elem); - if (elem[1]) - sv_catpvs(sv, " "); - } - PUSHs(sv = sv_mortalcopy(&PL_sv_no)); - sv_setiv(sv, (IV)nent->n_addrtype); - PUSHs(sv = sv_mortalcopy(&PL_sv_no)); - sv_setiv(sv, (IV)nent->n_net); + mPUSHs(newSVpv(nent->n_name, 0)); + PUSHs(space_join_names_mortal(nent->n_aliases)); + mPUSHi(nent->n_addrtype); + mPUSHi(nent->n_net); } RETURN; @@ -4675,7 +4823,6 @@ PP(pp_gprotoent) #if defined(HAS_GETPROTOBYNAME) || defined(HAS_GETPROTOBYNUMBER) || defined(HAS_GETPROTOENT) dVAR; dSP; I32 which = PL_op->op_type; - register char **elem; register SV *sv; #ifndef HAS_GETPROTO_PROTOS /* XXX Do we need individual probes? */ struct protoent *getprotobyname(Netdb_name_t); @@ -4720,16 +4867,9 @@ PP(pp_gprotoent) } if (pent) { - PUSHs(sv = sv_mortalcopy(&PL_sv_no)); - sv_setpv(sv, pent->p_name); - PUSHs(sv = sv_mortalcopy(&PL_sv_no)); - for (elem = pent->p_aliases; elem && *elem; elem++) { - sv_catpv(sv, *elem); - if (elem[1]) - sv_catpvs(sv, " "); - } - PUSHs(sv = sv_mortalcopy(&PL_sv_no)); - sv_setiv(sv, (IV)pent->p_proto); + mPUSHs(newSVpv(pent->p_name, 0)); + PUSHs(space_join_names_mortal(pent->p_aliases)); + mPUSHi(pent->p_proto); } RETURN; @@ -4743,7 +4883,6 @@ PP(pp_gservent) #if defined(HAS_GETSERVBYNAME) || defined(HAS_GETSERVBYPORT) || defined(HAS_GETSERVENT) dVAR; dSP; I32 which = PL_op->op_type; - register char **elem; register SV *sv; #ifndef HAS_GETSERV_PROTOS /* XXX Do we need individual probes? */ struct servent *getservbyname(Netdb_name_t, Netdb_name_t); @@ -4798,22 +4937,14 @@ PP(pp_gservent) } if (sent) { - PUSHs(sv = sv_mortalcopy(&PL_sv_no)); - sv_setpv(sv, sent->s_name); - PUSHs(sv = sv_mortalcopy(&PL_sv_no)); - for (elem = sent->s_aliases; elem && *elem; elem++) { - sv_catpv(sv, *elem); - if (elem[1]) - sv_catpvs(sv, " "); - } - PUSHs(sv = sv_mortalcopy(&PL_sv_no)); + mPUSHs(newSVpv(sent->s_name, 0)); + PUSHs(space_join_names_mortal(sent->s_aliases)); #ifdef HAS_NTOHS - sv_setiv(sv, (IV)PerlSock_ntohs(sent->s_port)); + mPUSHi(PerlSock_ntohs(sent->s_port)); #else - sv_setiv(sv, (IV)(sent->s_port)); + mPUSHi(sent->s_port); #endif - PUSHs(sv = sv_mortalcopy(&PL_sv_no)); - sv_setpv(sv, sent->s_proto); + mPUSHs(newSVpv(sent->s_proto, 0)); } RETURN; @@ -4837,7 +4968,7 @@ PP(pp_snetent) { #ifdef HAS_SETNETENT dVAR; dSP; - PerlSock_setnetent(TOPi); + (void)PerlSock_setnetent(TOPi); RETSETYES; #else DIE(aTHX_ PL_no_sock_func, "setnetent"); @@ -4848,7 +4979,7 @@ PP(pp_sprotoent) { #ifdef HAS_SETPROTOENT dVAR; dSP; - PerlSock_setprotoent(TOPi); + (void)PerlSock_setprotoent(TOPi); RETSETYES; #else DIE(aTHX_ PL_no_sock_func, "setprotoent"); @@ -4859,7 +4990,7 @@ PP(pp_sservent) { #ifdef HAS_SETSERVENT dVAR; dSP; - PerlSock_setservent(TOPi); + (void)PerlSock_setservent(TOPi); RETSETYES; #else DIE(aTHX_ PL_no_sock_func, "setservent"); @@ -5029,11 +5160,10 @@ PP(pp_gpwent) } if (pwent) { - PUSHs(sv = sv_mortalcopy(&PL_sv_no)); - sv_setpv(sv, pwent->pw_name); + mPUSHs(newSVpv(pwent->pw_name, 0)); - PUSHs(sv = sv_mortalcopy(&PL_sv_no)); - SvPOK_off(sv); + sv = newSViv(0); + mPUSHs(sv); /* If we have getspnam(), we try to dig up the shadow * password. If we are underprivileged, the shadow * interface will set the errno to EACCES or similar, @@ -5054,13 +5184,13 @@ PP(pp_gpwent) * has a different API than the Solaris/IRIX one. */ # if defined(HAS_GETSPNAM) && !defined(_AIX) { - const int saverrno = errno; + dSAVE_ERRNO; const struct spwd * const spwent = getspnam(pwent->pw_name); /* Save and restore errno so that * underprivileged attempts seem * to have never made the unsccessful * attempt to retrieve the shadow password. */ - errno = saverrno; + RESTORE_ERRNO; if (spwent && spwent->sp_pwdp) sv_setpv(sv, spwent->sp_pwdp); } @@ -5076,70 +5206,70 @@ PP(pp_gpwent) SvTAINTED_on(sv); # endif - PUSHs(sv = sv_mortalcopy(&PL_sv_no)); # if Uid_t_sign <= 0 - sv_setiv(sv, (IV)pwent->pw_uid); + mPUSHi(pwent->pw_uid); # else - sv_setuv(sv, (UV)pwent->pw_uid); + mPUSHu(pwent->pw_uid); # endif - PUSHs(sv = sv_mortalcopy(&PL_sv_no)); # if Uid_t_sign <= 0 - sv_setiv(sv, (IV)pwent->pw_gid); + mPUSHi(pwent->pw_gid); # else - sv_setuv(sv, (UV)pwent->pw_gid); + mPUSHu(pwent->pw_gid); # endif /* pw_change, pw_quota, and pw_age are mutually exclusive-- * because of the poor interface of the Perl getpw*(), * not because there's some standard/convention saying so. * A better interface would have been to return a hash, * but we are accursed by our history, alas. --jhi. */ - PUSHs(sv = sv_mortalcopy(&PL_sv_no)); # ifdef PWCHANGE - sv_setiv(sv, (IV)pwent->pw_change); + mPUSHi(pwent->pw_change); # else # ifdef PWQUOTA - sv_setiv(sv, (IV)pwent->pw_quota); + mPUSHi(pwent->pw_quota); # else # ifdef PWAGE - sv_setpv(sv, pwent->pw_age); + mPUSHs(newSVpv(pwent->pw_age, 0)); +# else + /* I think that you can never get this compiled, but just in case. */ + PUSHs(sv_mortalcopy(&PL_sv_no)); # endif # endif # endif /* pw_class and pw_comment are mutually exclusive--. * see the above note for pw_change, pw_quota, and pw_age. */ - PUSHs(sv = sv_mortalcopy(&PL_sv_no)); # ifdef PWCLASS - sv_setpv(sv, pwent->pw_class); + mPUSHs(newSVpv(pwent->pw_class, 0)); # else # ifdef PWCOMMENT - sv_setpv(sv, pwent->pw_comment); + mPUSHs(newSVpv(pwent->pw_comment, 0)); +# else + /* I think that you can never get this compiled, but just in case. */ + PUSHs(sv_mortalcopy(&PL_sv_no)); # endif # endif - PUSHs(sv = sv_mortalcopy(&PL_sv_no)); # ifdef PWGECOS - sv_setpv(sv, pwent->pw_gecos); + PUSHs(sv = sv_2mortal(newSVpv(pwent->pw_gecos, 0))); +# else + PUSHs(sv = sv_mortalcopy(&PL_sv_no)); # endif # ifndef INCOMPLETE_TAINTS /* pw_gecos is tainted because user himself can diddle with it. */ SvTAINTED_on(sv); # endif - PUSHs(sv = sv_mortalcopy(&PL_sv_no)); - sv_setpv(sv, pwent->pw_dir); + mPUSHs(newSVpv(pwent->pw_dir, 0)); - PUSHs(sv = sv_mortalcopy(&PL_sv_no)); - sv_setpv(sv, pwent->pw_shell); + PUSHs(sv = sv_2mortal(newSVpv(pwent->pw_shell, 0))); # ifndef INCOMPLETE_TAINTS /* pw_shell is tainted because user himself can diddle with it. */ SvTAINTED_on(sv); # endif # ifdef PWEXPIRE - PUSHs(sv = sv_mortalcopy(&PL_sv_no)); - sv_setiv(sv, (IV)pwent->pw_expire); + mPUSHi(pwent->pw_expire); # endif } RETURN; @@ -5207,21 +5337,17 @@ PP(pp_ggrent) } if (grent) { - SV *sv; - char **elem; - PUSHs(sv = sv_mortalcopy(&PL_sv_no)); - sv_setpv(sv, grent->gr_name); + mPUSHs(newSVpv(grent->gr_name, 0)); - PUSHs(sv = sv_mortalcopy(&PL_sv_no)); #ifdef GRPASSWD - sv_setpv(sv, grent->gr_passwd); + mPUSHs(newSVpv(grent->gr_passwd, 0)); +#else + PUSHs(sv_mortalcopy(&PL_sv_no)); #endif - PUSHs(sv = sv_mortalcopy(&PL_sv_no)); - sv_setiv(sv, (IV)grent->gr_gid); + mPUSHi(grent->gr_gid); #if !(defined(_CRAYMPP) && defined(USE_REENTRANT_API)) - PUSHs(sv = sv_mortalcopy(&PL_sv_no)); /* In UNICOS/mk (_CRAYMPP) the multithreading * versions (getgrnam_r, getgrgid_r) * seem to return an illegal pointer @@ -5230,11 +5356,7 @@ PP(pp_ggrent) * but the gr_mem is poisonous anyway. * So yes, you cannot get the list of group * members if building multithreaded in UNICOS/mk. */ - for (elem = grent->gr_mem; elem && *elem; elem++) { - sv_catpv(sv, *elem); - if (elem[1]) - sv_catpvs(sv, " "); - } + PUSHs(space_join_names_mortal(grent->gr_mem)); #endif } @@ -5446,15 +5568,15 @@ static int lockf_emulate_flock(int fd, int operation) { int i; - const int save_errno = errno; Off_t pos; + dSAVE_ERRNO; /* flock locks entire file so for lockf we need to do the same */ pos = PerlLIO_lseek(fd, (Off_t)0, SEEK_CUR); /* get pos to restore later */ if (pos > 0) /* is seekable and needs to be repositioned */ if (PerlLIO_lseek(fd, (Off_t)0, SEEK_SET) < 0) pos = -1; /* seek failed, so don't seek back afterwards */ - errno = save_errno; + RESTORE_ERRNO; switch (operation) {