This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
added patch, tweaked PERL_OBJECT things
[perl5.git] / pp.c
diff --git a/pp.c b/pp.c
index 3934984..8625a39 100644 (file)
--- a/pp.c
+++ b/pp.c
@@ -24,7 +24,7 @@
  */
 #ifdef CXUX_BROKEN_CONSTANT_CONVERT
 static double UV_MAX_cxux = ((double)UV_MAX);
-#endif  
+#endif
 
 /*
  * Types used in bitwise operations.
@@ -46,7 +46,7 @@ typedef unsigned UBW;
  * have an integral type (except char) small enough to be represented
  * in a double without loss; that is, it has no 32-bit type.
  */
-#if BYTEORDER > 0xFFFF && defined(_CRAY) && !defined(_CRAYMPP)
+#if LONGSIZE > 4  && defined(_CRAY) && !defined(_CRAYMPP)
 #  define BW_BITS  32
 #  define BW_MASK  ((1 << BW_BITS) - 1)
 #  define BW_SIGN  (1 << (BW_BITS - 1))
@@ -69,7 +69,11 @@ typedef unsigned UBW;
  * If they're not right on your machine, then pack() and unpack()
  * wouldn't work right anyway; you'll need to apply the Cray hack.
  * (I'd like to check them with #if, but you can't use sizeof() in
- * the preprocessor.)
+ * the preprocessor.)  --???
+ */
+/*
+    The appropriate SHORTSIZE, INTSIZE, LONGSIZE, and LONGLONGSIZE
+    defines are now in config.h.  --Andy Dougherty  April 1998
  */
 #define SIZE16 2
 #define SIZE32 4
@@ -97,20 +101,26 @@ typedef unsigned UBW;
 #  define CAT32(sv,p)  sv_catpvn(sv, (char*)(p), SIZE32)
 #endif
 
+#ifndef PERL_OBJECT
 static void doencodes _((SV* sv, char* s, I32 len));
 static SV* refto _((SV* sv));
 static U32 seed _((void));
+#endif
 
 static bool srand_called = FALSE;
 
 /* variations on pp_null */
 
-#ifdef DONT_DECLARE_STD
 #ifdef I_UNISTD
 #include <unistd.h>
 #endif
-#else
-extern pid_t getpid (void);
+
+/* XXX I can't imagine anyone who doesn't have this actually _needs_
+   it, since pid_t is an integral type.
+   --AD  2/20/1998
+*/
+#ifdef NEED_GETPID_PROTO
+extern Pid_t getpid (void);
 #endif
 
 PP(pp_stub)
@@ -141,7 +151,16 @@ PP(pp_padav)
     if (GIMME == G_ARRAY) {
        I32 maxarg = AvFILL((AV*)TARG) + 1;
        EXTEND(SP, maxarg);
-       Copy(AvARRAY((AV*)TARG), SP+1, maxarg, SV*);
+       if (SvMAGICAL(TARG)) {
+           U32 i;
+           for (i=0; i < maxarg; i++) {
+               SV **svp = av_fetch((AV*)TARG, i, FALSE);
+               SP[i+1] = (svp) ? *svp : &sv_undef;
+           }
+       }
+       else {
+           Copy(AvARRAY((AV*)TARG), SP+1, maxarg, SV*);
+       }
        SP += maxarg;
     }
     else {
@@ -189,7 +208,7 @@ PP(pp_padany)
 PP(pp_rv2gv)
 {
     djSP; dTOPss;
-    
+
     if (SvROK(sv)) {
       wasref:
        sv = SvRV(sv);
@@ -297,7 +316,7 @@ PP(pp_av2arylen)
 PP(pp_pos)
 {
     djSP; dTARGET; dPOPss;
-    
+
     if (op->op_flags & OPf_MOD) {
        if (SvTYPE(TARG) < SVt_PVLV) {
            sv_upgrade(TARG, SVt_PVLV);
@@ -305,12 +324,16 @@ PP(pp_pos)
        }
 
        LvTYPE(TARG) = '.';
-       LvTARG(TARG) = sv;
+       if (LvTARG(TARG) != sv) {
+           if (LvTARG(TARG))
+               SvREFCNT_dec(LvTARG(TARG));
+           LvTARG(TARG) = SvREFCNT_inc(sv);
+       }
        PUSHs(TARG);    /* no SvSETMAGIC */
        RETURN;
     }
     else {
-       MAGIC* mg; 
+       MAGIC* mg;
 
        if (SvTYPE(sv) >= SVt_PVMG && SvMAGIC(sv)) {
            mg = mg_find(sv, 'g');
@@ -351,9 +374,54 @@ PP(pp_prototype)
     SV *ret;
 
     ret = &sv_undef;
+    if (SvPOK(TOPs) && SvCUR(TOPs) >= 7) {
+       char *s = SvPVX(TOPs);
+       if (strnEQ(s, "CORE::", 6)) {
+           int code;
+           
+           code = keyword(s + 6, SvCUR(TOPs) - 6);
+           if (code < 0) {     /* Overridable. */
+#define MAX_ARGS_OP ((sizeof(I32) - 1) * 2)
+               int i = 0, n = 0, seen_question = 0;
+               I32 oa;
+               char str[ MAX_ARGS_OP * 2 + 2 ]; /* One ';', one '\0' */
+
+               while (i < MAXO) {      /* The slow way. */
+                   if (strEQ(s + 6, op_name[i]) || strEQ(s + 6, op_desc[i]))
+                       goto found;
+                   i++;
+               }
+               goto nonesuch;          /* Should not happen... */
+             found:
+               oa = opargs[i] >> OASHIFT;
+               while (oa) {
+                   if (oa & OA_OPTIONAL) {
+                       seen_question = 1;
+                       str[n++] = ';';
+                   } else if (seen_question) 
+                       goto set;       /* XXXX system, exec */
+                   if ((oa & (OA_OPTIONAL - 1)) >= OA_AVREF 
+                       && (oa & (OA_OPTIONAL - 1)) <= OA_HVREF) {
+                       str[n++] = '\\';
+                   }
+                   /* What to do with R ((un)tie, tied, (sys)read, recv)? */
+                   str[n++] = ("?$@@%&*$")[oa & (OA_OPTIONAL - 1)];
+                   oa = oa >> 4;
+               }
+               str[n++] = '\0';
+               ret = sv_2mortal(newSVpv(str, n - 1));
+           } else if (code)            /* Non-Overridable */
+               goto set;
+           else {                      /* None such */
+             nonesuch:
+               croak("Cannot find an opnumber for \"%s\"", s+6);
+           }
+       }
+    }
     cv = sv_2cv(TOPs, &stash, &gv, FALSE);
     if (cv && SvPOK(cv))
        ret = sv_2mortal(newSVpv(SvPVX(cv), SvCUR(cv)));
+  set:
     SETs(ret);
     RETURN;
 }
@@ -374,14 +442,19 @@ PP(pp_srefgen)
     djSP;
     *SP = refto(*SP);
     RETURN;
-} 
+}
 
 PP(pp_refgen)
 {
     djSP; dMARK;
     if (GIMME != G_ARRAY) {
-       MARK[1] = *SP;
-       SP = MARK + 1;
+       if (++MARK <= SP)
+           *MARK = *SP;
+       else
+           *MARK = &sv_undef;
+       *MARK = refto(*MARK);
+       SP = MARK;
+       RETURN;
     }
     EXTEND_MORTAL(SP - MARK);
     while (++MARK <= SP)
@@ -389,7 +462,7 @@ PP(pp_refgen)
     RETURN;
 }
 
-static SV*
+STATIC SV*
 refto(SV *sv)
 {
     SV* rv;
@@ -422,7 +495,7 @@ PP(pp_ref)
     sv = POPs;
 
     if (sv && SvGMAGICAL(sv))
-       mg_get(sv);     
+       mg_get(sv);
 
     if (!sv || !SvROK(sv))
        RETPUSHNO;
@@ -440,8 +513,14 @@ PP(pp_bless)
 
     if (MAXARG == 1)
        stash = curcop->cop_stash;
-    else
-       stash = gv_stashsv(POPs, TRUE);
+    else {
+       SV *ssv = POPs;
+       STRLEN len;
+       char *ptr = SvPV(ssv,len);
+       if (dowarn && len == 0)
+           warn("Explicit blessing to '' (assuming package main)");
+       stash = gv_stashpvn(ptr, len, TRUE);
+    }
 
     (void)sv_bless(TOPs, stash);
     RETURN;
@@ -451,40 +530,40 @@ PP(pp_gelem)
 {
     GV *gv;
     SV *sv;
-    SV *ref;
+    SV *tmpRef;
     char *elem;
     djSP;
 
     sv = POPs;
     elem = SvPV(sv, na);
     gv = (GV*)POPs;
-    ref = Nullsv;
+    tmpRef = Nullsv;
     sv = Nullsv;
     switch (elem ? *elem : '\0')
     {
     case 'A':
        if (strEQ(elem, "ARRAY"))
-           ref = (SV*)GvAV(gv);
+           tmpRef = (SV*)GvAV(gv);
        break;
     case 'C':
        if (strEQ(elem, "CODE"))
-           ref = (SV*)GvCVu(gv);
+           tmpRef = (SV*)GvCVu(gv);
        break;
     case 'F':
        if (strEQ(elem, "FILEHANDLE")) /* XXX deprecate in 5.005 */
-           ref = (SV*)GvIOp(gv);
+           tmpRef = (SV*)GvIOp(gv);
        break;
     case 'G':
        if (strEQ(elem, "GLOB"))
-           ref = (SV*)gv;
+           tmpRef = (SV*)gv;
        break;
     case 'H':
        if (strEQ(elem, "HASH"))
-           ref = (SV*)GvHV(gv);
+           tmpRef = (SV*)GvHV(gv);
        break;
     case 'I':
        if (strEQ(elem, "IO"))
-           ref = (SV*)GvIOp(gv);
+           tmpRef = (SV*)GvIOp(gv);
        break;
     case 'N':
        if (strEQ(elem, "NAME"))
@@ -496,11 +575,11 @@ PP(pp_gelem)
        break;
     case 'S':
        if (strEQ(elem, "SCALAR"))
-           ref = GvSV(gv);
+           tmpRef = GvSV(gv);
        break;
     }
-    if (ref)
-       sv = newRV(ref);
+    if (tmpRef)
+       sv = newRV(tmpRef);
     if (sv)
        sv_2mortal(sv);
     else
@@ -522,14 +601,6 @@ PP(pp_study)
     register I32 *snext;
     STRLEN len;
 
-    if(unop->op_first && unop->op_first->op_type == OP_PUSHRE) {
-       PMOP *pm = (PMOP *)unop->op_first;
-       SV *rv = sv_newmortal();
-       sv = newSVrv(rv, "Regexp");
-       sv_magic(sv,(SV*)ReREFCNT_inc(pm->op_pmregexp),'r',0,0);
-       RETURNX(PUSHs(rv));
-    }
-
     if (sv == lastscream) {
        if (SvSCREAM(sv))
            RETPUSHYES;
@@ -628,7 +699,7 @@ PP(pp_chomp)
 {
     djSP; dMARK; dTARGET;
     register I32 count = 0;
-    
+
     while (SP > MARK)
        count += do_chomp(POPs);
     PUSHi(count);
@@ -696,7 +767,7 @@ PP(pp_undef)
        hv_undef((HV*)sv);
        break;
     case SVt_PVCV:
-       if (cv_const_sv((CV*)sv))
+       if (dowarn && cv_const_sv((CV*)sv))
            warn("Constant subroutine %s undefined",
                 CvANON((CV*)sv) ? "(anonymous)" : GvENAME(CvGV((CV*)sv)));
        /* FALL THROUGH */
@@ -707,7 +778,17 @@ PP(pp_undef)
        break;
     case SVt_PVGV:
        if (SvFAKE(sv))
-           sv_setsv(sv, &sv_undef);
+           SvSetMagicSV(sv, &sv_undef);
+       else {
+           GP *gp;
+           gp_free((GV*)sv);
+           Newz(602, gp, 1, GP);
+           GvGP(sv) = gp_ref(gp);
+           GvSV(sv) = NEWSV(72,0);
+           GvLINE(sv) = curcop->cop_line;
+           GvEGV(sv) = (GV*)sv;
+           GvMULTI_on(sv);
+       }
        break;
     default:
        if (SvTYPE(sv) >= SVt_PV && SvPVX(sv) && SvLEN(sv)) {
@@ -784,7 +865,7 @@ PP(pp_postdec)
 
 PP(pp_pow)
 {
-    djSP; dATARGET; tryAMAGICbin(pow,opASSIGN); 
+    djSP; dATARGET; tryAMAGICbin(pow,opASSIGN);
     {
       dPOPTOPnnrl;
       SETn( pow( left, right) );
@@ -794,7 +875,7 @@ PP(pp_pow)
 
 PP(pp_multiply)
 {
-    djSP; dATARGET; tryAMAGICbin(mult,opASSIGN); 
+    djSP; dATARGET; tryAMAGICbin(mult,opASSIGN);
     {
       dPOPTOPnnrl;
       SETn( left * right );
@@ -804,7 +885,7 @@ PP(pp_multiply)
 
 PP(pp_divide)
 {
-    djSP; dATARGET; tryAMAGICbin(div,opASSIGN); 
+    djSP; dATARGET; tryAMAGICbin(div,opASSIGN);
     {
       dPOPPOPnnrl;
       double value;
@@ -832,7 +913,7 @@ PP(pp_divide)
 
 PP(pp_modulo)
 {
-    djSP; dATARGET; tryAMAGICbin(mod,opASSIGN);
+    djSP; dATARGET; tryAMAGICbin(modulo,opASSIGN);
     {
       UV left;
       UV right;
@@ -937,7 +1018,7 @@ PP(pp_repeat)
 
 PP(pp_subtract)
 {
-    djSP; dATARGET; tryAMAGICbin(subtr,opASSIGN); 
+    djSP; dATARGET; tryAMAGICbin(subtr,opASSIGN);
     {
       dPOPTOPnnrl_ul;
       SETn( left - right );
@@ -947,7 +1028,7 @@ PP(pp_subtract)
 
 PP(pp_left_shift)
 {
-    djSP; dATARGET; tryAMAGICbin(lshift,opASSIGN); 
+    djSP; dATARGET; tryAMAGICbin(lshift,opASSIGN);
     {
       IBW shift = POPi;
       if (op->op_private & HINT_INTEGER) {
@@ -966,7 +1047,7 @@ PP(pp_left_shift)
 
 PP(pp_right_shift)
 {
-    djSP; dATARGET; tryAMAGICbin(rshift,opASSIGN); 
+    djSP; dATARGET; tryAMAGICbin(rshift,opASSIGN);
     {
       IBW shift = POPi;
       if (op->op_private & HINT_INTEGER) {
@@ -985,7 +1066,7 @@ PP(pp_right_shift)
 
 PP(pp_lt)
 {
-    djSP; tryAMAGICbinSET(lt,0); 
+    djSP; tryAMAGICbinSET(lt,0);
     {
       dPOPnv;
       SETs(boolSV(TOPn < value));
@@ -995,7 +1076,7 @@ PP(pp_lt)
 
 PP(pp_gt)
 {
-    djSP; tryAMAGICbinSET(gt,0); 
+    djSP; tryAMAGICbinSET(gt,0);
     {
       dPOPnv;
       SETs(boolSV(TOPn > value));
@@ -1005,7 +1086,7 @@ PP(pp_gt)
 
 PP(pp_le)
 {
-    djSP; tryAMAGICbinSET(le,0); 
+    djSP; tryAMAGICbinSET(le,0);
     {
       dPOPnv;
       SETs(boolSV(TOPn <= value));
@@ -1015,7 +1096,7 @@ PP(pp_le)
 
 PP(pp_ge)
 {
-    djSP; tryAMAGICbinSET(ge,0); 
+    djSP; tryAMAGICbinSET(ge,0);
     {
       dPOPnv;
       SETs(boolSV(TOPn >= value));
@@ -1025,7 +1106,7 @@ PP(pp_ge)
 
 PP(pp_ne)
 {
-    djSP; tryAMAGICbinSET(ne,0); 
+    djSP; tryAMAGICbinSET(ne,0);
     {
       dPOPnv;
       SETs(boolSV(TOPn != value));
@@ -1035,7 +1116,7 @@ PP(pp_ne)
 
 PP(pp_ncmp)
 {
-    djSP; dTARGET; tryAMAGICbin(ncmp,0); 
+    djSP; dTARGET; tryAMAGICbin(ncmp,0);
     {
       dPOPTOPnnrl;
       I32 value;
@@ -1057,7 +1138,7 @@ PP(pp_ncmp)
 
 PP(pp_slt)
 {
-    djSP; tryAMAGICbinSET(slt,0); 
+    djSP; tryAMAGICbinSET(slt,0);
     {
       dPOPTOPssrl;
       int cmp = ((op->op_private & OPpLOCALE)
@@ -1070,7 +1151,7 @@ PP(pp_slt)
 
 PP(pp_sgt)
 {
-    djSP; tryAMAGICbinSET(sgt,0); 
+    djSP; tryAMAGICbinSET(sgt,0);
     {
       dPOPTOPssrl;
       int cmp = ((op->op_private & OPpLOCALE)
@@ -1083,7 +1164,7 @@ PP(pp_sgt)
 
 PP(pp_sle)
 {
-    djSP; tryAMAGICbinSET(sle,0); 
+    djSP; tryAMAGICbinSET(sle,0);
     {
       dPOPTOPssrl;
       int cmp = ((op->op_private & OPpLOCALE)
@@ -1096,7 +1177,7 @@ PP(pp_sle)
 
 PP(pp_sge)
 {
-    djSP; tryAMAGICbinSET(sge,0); 
+    djSP; tryAMAGICbinSET(sge,0);
     {
       dPOPTOPssrl;
       int cmp = ((op->op_private & OPpLOCALE)
@@ -1109,7 +1190,7 @@ PP(pp_sge)
 
 PP(pp_seq)
 {
-    djSP; tryAMAGICbinSET(seq,0); 
+    djSP; tryAMAGICbinSET(seq,0);
     {
       dPOPTOPssrl;
       SETs(boolSV(sv_eq(left, right)));
@@ -1119,7 +1200,7 @@ PP(pp_seq)
 
 PP(pp_sne)
 {
-    djSP; tryAMAGICbinSET(sne,0); 
+    djSP; tryAMAGICbinSET(sne,0);
     {
       dPOPTOPssrl;
       SETs(boolSV(!sv_eq(left, right)));
@@ -1142,16 +1223,16 @@ PP(pp_scmp)
 
 PP(pp_bit_and)
 {
-    djSP; dATARGET; tryAMAGICbin(band,opASSIGN); 
+    djSP; dATARGET; tryAMAGICbin(band,opASSIGN);
     {
       dPOPTOPssrl;
       if (SvNIOKp(left) || SvNIOKp(right)) {
        if (op->op_private & HINT_INTEGER) {
-         IBW value = SvIV(left) & SvIV(right); 
+         IBW value = SvIV(left) & SvIV(right);
          SETi(BWi(value));
        }
        else {
-         UBW value = SvUV(left) & SvUV(right); 
+         UBW value = SvUV(left) & SvUV(right);
          SETu(BWu(value));
        }
       }
@@ -1165,16 +1246,16 @@ PP(pp_bit_and)
 
 PP(pp_bit_xor)
 {
-    djSP; dATARGET; tryAMAGICbin(bxor,opASSIGN); 
+    djSP; dATARGET; tryAMAGICbin(bxor,opASSIGN);
     {
       dPOPTOPssrl;
       if (SvNIOKp(left) || SvNIOKp(right)) {
        if (op->op_private & HINT_INTEGER) {
-         IBW value = (USE_LEFT(left) ? SvIV(left) : 0) ^ SvIV(right); 
+         IBW value = (USE_LEFT(left) ? SvIV(left) : 0) ^ SvIV(right);
          SETi(BWi(value));
        }
        else {
-         UBW value = (USE_LEFT(left) ? SvUV(left) : 0) ^ SvUV(right); 
+         UBW value = (USE_LEFT(left) ? SvUV(left) : 0) ^ SvUV(right);
          SETu(BWu(value));
        }
       }
@@ -1188,16 +1269,16 @@ PP(pp_bit_xor)
 
 PP(pp_bit_or)
 {
-    djSP; dATARGET; tryAMAGICbin(bor,opASSIGN); 
+    djSP; dATARGET; tryAMAGICbin(bor,opASSIGN);
     {
       dPOPTOPssrl;
       if (SvNIOKp(left) || SvNIOKp(right)) {
        if (op->op_private & HINT_INTEGER) {
-         IBW value = (USE_LEFT(left) ? SvIV(left) : 0) | SvIV(right); 
+         IBW value = (USE_LEFT(left) ? SvIV(left) : 0) | SvIV(right);
          SETi(BWi(value));
        }
        else {
-         UBW value = (USE_LEFT(left) ? SvUV(left) : 0) | SvUV(right); 
+         UBW value = (USE_LEFT(left) ? SvUV(left) : 0) | SvUV(right);
          SETu(BWu(value));
        }
       }
@@ -1252,7 +1333,7 @@ PP(pp_not)
 
 PP(pp_complement)
 {
-    djSP; dTARGET; tryAMAGICun(compl); 
+    djSP; dTARGET; tryAMAGICun(compl);
     {
       dTOPss;
       if (SvNIOKp(sv)) {
@@ -1295,7 +1376,7 @@ PP(pp_complement)
 
 PP(pp_i_multiply)
 {
-    djSP; dATARGET; tryAMAGICbin(mult,opASSIGN); 
+    djSP; dATARGET; tryAMAGICbin(mult,opASSIGN);
     {
       dPOPTOPiirl;
       SETi( left * right );
@@ -1305,7 +1386,7 @@ PP(pp_i_multiply)
 
 PP(pp_i_divide)
 {
-    djSP; dATARGET; tryAMAGICbin(div,opASSIGN); 
+    djSP; dATARGET; tryAMAGICbin(div,opASSIGN);
     {
       dPOPiv;
       if (value == 0)
@@ -1318,7 +1399,7 @@ PP(pp_i_divide)
 
 PP(pp_i_modulo)
 {
-    djSP; dATARGET; tryAMAGICbin(mod,opASSIGN); 
+    djSP; dATARGET; tryAMAGICbin(modulo,opASSIGN); 
     {
       dPOPTOPiirl;
       if (!right)
@@ -1330,7 +1411,7 @@ PP(pp_i_modulo)
 
 PP(pp_i_add)
 {
-    djSP; dATARGET; tryAMAGICbin(add,opASSIGN); 
+    djSP; dATARGET; tryAMAGICbin(add,opASSIGN);
     {
       dPOPTOPiirl;
       SETi( left + right );
@@ -1340,7 +1421,7 @@ PP(pp_i_add)
 
 PP(pp_i_subtract)
 {
-    djSP; dATARGET; tryAMAGICbin(subtr,opASSIGN); 
+    djSP; dATARGET; tryAMAGICbin(subtr,opASSIGN);
     {
       dPOPTOPiirl;
       SETi( left - right );
@@ -1350,7 +1431,7 @@ PP(pp_i_subtract)
 
 PP(pp_i_lt)
 {
-    djSP; tryAMAGICbinSET(lt,0); 
+    djSP; tryAMAGICbinSET(lt,0);
     {
       dPOPTOPiirl;
       SETs(boolSV(left < right));
@@ -1360,7 +1441,7 @@ PP(pp_i_lt)
 
 PP(pp_i_gt)
 {
-    djSP; tryAMAGICbinSET(gt,0); 
+    djSP; tryAMAGICbinSET(gt,0);
     {
       dPOPTOPiirl;
       SETs(boolSV(left > right));
@@ -1370,7 +1451,7 @@ PP(pp_i_gt)
 
 PP(pp_i_le)
 {
-    djSP; tryAMAGICbinSET(le,0); 
+    djSP; tryAMAGICbinSET(le,0);
     {
       dPOPTOPiirl;
       SETs(boolSV(left <= right));
@@ -1380,7 +1461,7 @@ PP(pp_i_le)
 
 PP(pp_i_ge)
 {
-    djSP; tryAMAGICbinSET(ge,0); 
+    djSP; tryAMAGICbinSET(ge,0);
     {
       dPOPTOPiirl;
       SETs(boolSV(left >= right));
@@ -1390,7 +1471,7 @@ PP(pp_i_ge)
 
 PP(pp_i_eq)
 {
-    djSP; tryAMAGICbinSET(eq,0); 
+    djSP; tryAMAGICbinSET(eq,0);
     {
       dPOPTOPiirl;
       SETs(boolSV(left == right));
@@ -1400,7 +1481,7 @@ PP(pp_i_eq)
 
 PP(pp_i_ne)
 {
-    djSP; tryAMAGICbinSET(ne,0); 
+    djSP; tryAMAGICbinSET(ne,0);
     {
       dPOPTOPiirl;
       SETs(boolSV(left != right));
@@ -1410,7 +1491,7 @@ PP(pp_i_ne)
 
 PP(pp_i_ncmp)
 {
-    djSP; dTARGET; tryAMAGICbin(ncmp,0); 
+    djSP; dTARGET; tryAMAGICbin(ncmp,0);
     {
       dPOPTOPiirl;
       I32 value;
@@ -1437,7 +1518,7 @@ PP(pp_i_negate)
 
 PP(pp_atan2)
 {
-    djSP; dTARGET; tryAMAGICbin(atan2,0); 
+    djSP; dTARGET; tryAMAGICbin(atan2,0);
     {
       dPOPTOPnnrl;
       SETn(atan2(left, right));
@@ -1514,7 +1595,7 @@ PP(pp_srand)
     RETPUSHYES;
 }
 
-static U32
+STATIC U32
 seed(void)
 {
     /*
@@ -1713,47 +1794,56 @@ PP(pp_substr)
     I32 lvalue = op->op_flags & OPf_MOD;
     char *tmps;
     I32 arybase = curcop->cop_arybase;
-
-    if (MAXARG > 2)
+    char *repl = 0;
+    STRLEN repl_len;
+
+    SvTAINTED_off(TARG);                       /* decontaminate */
+    if (MAXARG > 2) {
+       if (MAXARG > 3) {
+           sv = POPs;
+           repl = SvPV(sv, repl_len);
+       }
        len = POPi;
+    }
     pos = POPi;
     sv = POPs;
+    PUTBACK;
     tmps = SvPV(sv, curlen);
     if (pos >= arybase) {
        pos -= arybase;
        rem = curlen-pos;
        fail = rem;
-        if (MAXARG > 2) {
-            if (len < 0) {
-               rem += len;
-                if (rem < 0)
-                    rem = 0;
-            }
-            else if (rem > len)
-                     rem = len;
-        }
+       if (MAXARG > 2) {
+           if (len < 0) {
+               rem += len;
+               if (rem < 0)
+                   rem = 0;
+           }
+           else if (rem > len)
+                    rem = len;
+       }
     }
     else {
-        pos += curlen;
-        if (MAXARG < 3)
-            rem = curlen;
-        else if (len >= 0) {
-            rem = pos+len;
-            if (rem > (I32)curlen)
-                rem = curlen;
-        }
-        else {
-            rem = curlen+len;
-            if (rem < pos)
-                rem = pos;
-        }
-        if (pos < 0)
-            pos = 0;
-        fail = rem;
-        rem -= pos;
+       pos += curlen;
+       if (MAXARG < 3)
+           rem = curlen;
+       else if (len >= 0) {
+           rem = pos+len;
+           if (rem > (I32)curlen)
+               rem = curlen;
+       }
+       else {
+           rem = curlen+len;
+           if (rem < pos)
+               rem = pos;
+       }
+       if (pos < 0)
+           pos = 0;
+       fail = rem;
+       rem -= pos;
     }
     if (fail < 0) {
-       if (dowarn || lvalue
+       if (dowarn || lvalue || repl)
            warn("substr outside of string");
        RETPUSHUNDEF;
     }
@@ -1779,11 +1869,18 @@ PP(pp_substr)
            }
 
            LvTYPE(TARG) = 'x';
-           LvTARG(TARG) = sv;
+           if (LvTARG(TARG) != sv) {
+               if (LvTARG(TARG))
+                   SvREFCNT_dec(LvTARG(TARG));
+               LvTARG(TARG) = SvREFCNT_inc(sv);
+           }
            LvTARGOFF(TARG) = pos;
-           LvTARGLEN(TARG) = rem; 
+           LvTARGLEN(TARG) = rem;
        }
+       else if (repl)
+           sv_insert(sv, pos, rem, repl, repl_len);
     }
+    SPAGAIN;
     PUSHs(TARG);               /* avoid SvSETMAGIC here */
     RETURN;
 }
@@ -1800,6 +1897,7 @@ PP(pp_vec)
     unsigned long retnum;
     I32 len;
 
+    SvTAINTED_off(TARG);                       /* decontaminate */
     offset *= size;            /* turn into bit offset */
     len = (offset + size + 7) / 8;
     if (offset < 0 || size < 1)
@@ -1812,9 +1910,13 @@ PP(pp_vec)
            }
 
            LvTYPE(TARG) = 'v';
-           LvTARG(TARG) = src;
-           LvTARGOFF(TARG) = offset; 
-           LvTARGLEN(TARG) = size; 
+           if (LvTARG(TARG) != src) {
+               if (LvTARG(TARG))
+                   SvREFCNT_dec(LvTARG(TARG));
+               LvTARG(TARG) = SvREFCNT_inc(src);
+           }
+           LvTARGOFF(TARG) = offset;
+           LvTARGLEN(TARG) = size;
        }
        if (len > srclen) {
            if (size <= 8)
@@ -1857,7 +1959,7 @@ PP(pp_vec)
        }
     }
 
-    sv_setiv(TARG, (IV)retnum);
+    sv_setuv(TARG, (UV)retnum);
     PUSHs(TARG);
     RETURN;
 }
@@ -1886,7 +1988,7 @@ PP(pp_index)
     else if (offset > biglen)
        offset = biglen;
     if (!(tmps2 = fbm_instr((unsigned char*)tmps + offset,
-      (unsigned char*)tmps + biglen, little)))
+      (unsigned char*)tmps + biglen, little, 0)))
        retval = -1 + arybase;
     else
        retval = tmps2 - tmps + arybase;
@@ -2158,7 +2260,7 @@ PP(pp_aslice)
     if (SvTYPE(av) == SVt_PVAV) {
        if (lval && op->op_private & OPpLVAL_INTRO) {
            I32 max = -1;
-           for (svp = mark + 1; svp <= sp; svp++) {
+           for (svp = MARK + 1; svp <= SP; svp++) {
                elem = SvIVx(*svp);
                if (elem > max)
                    max = elem;
@@ -2176,7 +2278,7 @@ PP(pp_aslice)
                if (!svp || *svp == &sv_undef)
                    DIE(no_aelem, elem);
                if (op->op_private & OPpLVAL_INTRO)
-                   save_svref(svp);
+                   save_aelem(av, elem, svp);
            }
            *MARK = svp ? *svp : &sv_undef;
        }
@@ -2198,7 +2300,7 @@ PP(pp_each)
     HE *entry;
     I32 gimme = GIMME_V;
     I32 realhv = (SvTYPE(hash) == SVt_PVHV);
-    
+
     PUTBACK;
     /* might clobber stack_sp */
     entry = realhv ? hv_iternext(hash) : avhv_iternext((AV*)hash);
@@ -2248,8 +2350,6 @@ PP(pp_delete)
        while (++MARK <= SP) {
            if (hvtype == SVt_PVHV)
                sv = hv_delete_ent(hv, *MARK, discard, 0);
-           else if (hvtype == SVt_PVAV)
-               sv = avhv_delete_ent((AV*)hv, *MARK, discard, 0);
            else
                DIE("Not a HASH reference");
            *MARK = sv ? sv : &sv_undef;
@@ -2267,8 +2367,6 @@ PP(pp_delete)
        hv = (HV*)POPs;
        if (SvTYPE(hv) == SVt_PVHV)
            sv = hv_delete_ent(hv, keysv, discard, 0);
-       else if (SvTYPE(hv) == SVt_PVAV)
-           sv = avhv_delete_ent((AV*)hv, keysv, discard, 0);
        else
            DIE("Not a HASH reference");
        if (!sv)
@@ -2299,7 +2397,6 @@ PP(pp_exists)
 PP(pp_hslice)
 {
     djSP; dMARK; dORIGMARK;
-    register HE *he;
     register HV *hv = (HV*)POPs;
     register I32 lval = op->op_flags & OPf_MOD;
     I32 realhv = (SvTYPE(hv) == SVt_PVHV);
@@ -2309,18 +2406,18 @@ PP(pp_hslice)
            SV *keysv = *MARK;
            SV **svp;
            if (realhv) {
-               he = hv_fetch_ent(hv, keysv, lval, 0);
+               HE *he = hv_fetch_ent(hv, keysv, lval, 0);
                svp = he ? &HeVAL(he) : 0;
            } else {
                svp = avhv_fetch_ent((AV*)hv, keysv, lval, 0);
            }
            if (lval) {
-               if (!he || HeVAL(he) == &sv_undef)
+               if (!svp || *svp == &sv_undef)
                    DIE(no_helem, SvPV(keysv, na));
                if (op->op_private & OPpLVAL_INTRO)
-                   save_svref(&HeVAL(he));
+                   save_helem(hv, keysv, svp);
            }
-           *MARK = he ? HeVAL(he) : &sv_undef;
+           *MARK = svp ? *svp : &sv_undef;
        }
     }
     if (GIMME != G_ARRAY) {
@@ -2425,7 +2522,7 @@ PP(pp_anonhash)
        if (MARK < SP)
            sv_setsv(val, *++MARK);
        else if (dowarn)
-           warn("Odd number of elements in hash list");
+           warn("Odd number of elements in hash assignment");
        (void)hv_store_ent(hv,key,val,0);
     }
     SP = ORIGMARK;
@@ -2446,21 +2543,36 @@ PP(pp_splice)
     I32 after;
     I32 diff;
     SV **tmparyval = 0;
+    MAGIC *mg;
+
+    if (SvRMAGICAL(ary) && (mg = mg_find((SV*)ary,'P'))) {
+       *MARK-- = mg->mg_obj;
+       PUSHMARK(MARK);
+       PUTBACK;
+       ENTER;
+       perl_call_method("SPLICE",GIMME_V);
+       LEAVE;
+       SPAGAIN;
+       RETURN;
+    }
 
     SP++;
 
     if (++MARK < SP) {
        offset = i = SvIVx(*MARK);
        if (offset < 0)
-           offset += AvFILL(ary) + 1;
+           offset += AvFILLp(ary) + 1;
        else
            offset -= curcop->cop_arybase;
        if (offset < 0)
            DIE(no_aelem, i);
        if (++MARK < SP) {
            length = SvIVx(*MARK++);
-           if (length < 0)
-               length = 0;
+           if (length < 0) {
+               length += AvFILLp(ary) - offset + 1;
+               if (length < 0)
+                   length = 0;
+           }
        }
        else
            length = AvMAX(ary) + 1;            /* close enough to infinity */
@@ -2469,9 +2581,9 @@ PP(pp_splice)
        offset = 0;
        length = AvMAX(ary) + 1;
     }
-    if (offset > AvFILL(ary) + 1)
-       offset = AvFILL(ary) + 1;
-    after = AvFILL(ary) + 1 - (offset + length);
+    if (offset > AvFILLp(ary) + 1)
+       offset = AvFILLp(ary) + 1;
+    after = AvFILLp(ary) + 1 - (offset + length);
     if (after < 0) {                           /* not that much array */
        length += after;                        /* offset+length now in array */
        after = 0;
@@ -2503,8 +2615,7 @@ PP(pp_splice)
            if (AvREAL(ary)) {
                EXTEND_MORTAL(length);
                for (i = length, dst = MARK; i; i--) {
-                   if (!SvIMMORTAL(*dst))
-                       sv_2mortal(*dst);       /* free them eventualy */
+                   sv_2mortal(*dst);   /* free them eventualy */
                    dst++;
                }
            }
@@ -2513,13 +2624,12 @@ PP(pp_splice)
        else {
            *MARK = AvARRAY(ary)[offset+length-1];
            if (AvREAL(ary)) {
-               if (!SvIMMORTAL(*MARK))
-                   sv_2mortal(*MARK);
+               sv_2mortal(*MARK);
                for (i = length - 1, dst = &AvARRAY(ary)[offset]; i > 0; i--)
                    SvREFCNT_dec(*dst++);       /* free them now */
            }
        }
-       AvFILL(ary) += diff;
+       AvFILLp(ary) += diff;
 
        /* pull up or down? */
 
@@ -2540,7 +2650,7 @@ PP(pp_splice)
                dst = src + diff;               /* diff is negative */
                Move(src, dst, after, SV*);
            }
-           dst = &AvARRAY(ary)[AvFILL(ary)+1];
+           dst = &AvARRAY(ary)[AvFILLp(ary)+1];
                                                /* avoid later double free */
        }
        i = -diff;
@@ -2574,15 +2684,15 @@ PP(pp_splice)
                }
                SvPVX(ary) = (char*)(AvARRAY(ary) - diff);/* diff is positive */
                AvMAX(ary) += diff;
-               AvFILL(ary) += diff;
+               AvFILLp(ary) += diff;
            }
            else {
-               if (AvFILL(ary) + diff >= AvMAX(ary))   /* oh, well */
-                   av_extend(ary, AvFILL(ary) + diff);
-               AvFILL(ary) += diff;
+               if (AvFILLp(ary) + diff >= AvMAX(ary))  /* oh, well */
+                   av_extend(ary, AvFILLp(ary) + diff);
+               AvFILLp(ary) += diff;
 
                if (after) {
-                   dst = AvARRAY(ary) + AvFILL(ary);
+                   dst = AvARRAY(ary) + AvFILLp(ary);
                    src = dst - diff;
                    for (i = after; i; i--) {
                        *dst-- = *src--;
@@ -2602,8 +2712,7 @@ PP(pp_splice)
                if (AvREAL(ary)) {
                    EXTEND_MORTAL(length);
                    for (i = length, dst = MARK; i; i--) {
-                       if (!SvIMMORTAL(*dst))
-                           sv_2mortal(*dst);   /* free them eventualy */
+                       sv_2mortal(*dst);       /* free them eventualy */
                        dst++;
                    }
                }
@@ -2614,8 +2723,7 @@ PP(pp_splice)
        else if (length--) {
            *MARK = tmparyval[length];
            if (AvREAL(ary)) {
-               if (!SvIMMORTAL(*MARK))
-                   sv_2mortal(*MARK);
+               sv_2mortal(*MARK);
                while (length-- > 0)
                    SvREFCNT_dec(tmparyval[length]);
            }
@@ -2633,12 +2741,25 @@ PP(pp_push)
     djSP; dMARK; dORIGMARK; dTARGET;
     register AV *ary = (AV*)*++MARK;
     register SV *sv = &sv_undef;
+    MAGIC *mg;
 
-    for (++MARK; MARK <= SP; MARK++) {
-       sv = NEWSV(51, 0);
-       if (*MARK)
-           sv_setsv(sv, *MARK);
-       av_push(ary, sv);
+    if (SvRMAGICAL(ary) && (mg = mg_find((SV*)ary,'P'))) {
+       *MARK-- = mg->mg_obj;
+       PUSHMARK(MARK);
+       PUTBACK;
+       ENTER;
+       perl_call_method("PUSH",G_SCALAR|G_DISCARD);
+       LEAVE;
+       SPAGAIN;
+    }
+    else {
+       /* Why no pre-extend of ary here ? */
+       for (++MARK; MARK <= SP; MARK++) {
+           sv = NEWSV(51, 0);
+           if (*MARK)
+               sv_setsv(sv, *MARK);
+           av_push(ary, sv);
+       }
     }
     SP = ORIGMARK;
     PUSHi( AvFILL(ary) + 1 );
@@ -2650,7 +2771,7 @@ PP(pp_pop)
     djSP;
     AV *av = (AV*)POPs;
     SV *sv = av_pop(av);
-    if (!SvIMMORTAL(sv) && AvREAL(av))
+    if (AvREAL(av))
        (void)sv_2mortal(sv);
     PUSHs(sv);
     RETURN;
@@ -2664,7 +2785,7 @@ PP(pp_shift)
     EXTEND(SP, 1);
     if (!sv)
        RETPUSHUNDEF;
-    if (!SvIMMORTAL(sv) && AvREAL(av))
+    if (AvREAL(av))
        (void)sv_2mortal(sv);
     PUSHs(sv);
     RETURN;
@@ -2676,14 +2797,25 @@ PP(pp_unshift)
     register AV *ary = (AV*)*++MARK;
     register SV *sv;
     register I32 i = 0;
+    MAGIC *mg;
 
-    av_unshift(ary, SP - MARK);
-    while (MARK < SP) {
-       sv = NEWSV(27, 0);
-       sv_setsv(sv, *++MARK);
-       (void)av_store(ary, i++, sv);
+    if (SvRMAGICAL(ary) && (mg = mg_find((SV*)ary,'P'))) {
+       *MARK-- = mg->mg_obj;
+       PUSHMARK(MARK);
+       PUTBACK;
+       ENTER;
+       perl_call_method("UNSHIFT",G_SCALAR|G_DISCARD);
+       LEAVE;
+       SPAGAIN;
+    }
+    else {
+       av_unshift(ary, SP - MARK);
+       while (MARK < SP) {
+           sv = NEWSV(27, 0);
+           sv_setsv(sv, *++MARK);
+           (void)av_store(ary, i++, sv);
+       }
     }
-
     SP = ORIGMARK;
     PUSHi( AvFILL(ary) + 1 );
     RETURN;
@@ -2731,7 +2863,7 @@ PP(pp_reverse)
     RETURN;
 }
 
-static SV      *
+STATIC SV      *
 mul128(SV *sv, U8 m)
 {
   STRLEN          len;
@@ -2740,11 +2872,11 @@ mul128(SV *sv, U8 m)
   U32             i = 0;
 
   if (!strnEQ(s, "0000", 4)) {  /* need to grow sv */
-    SV             *New = newSVpv("0000000000", 10);
+    SV             *tmpNew = newSVpv("0000000000", 10);
 
-    sv_catsv(New, sv);
+    sv_catsv(tmpNew, sv);
     SvREFCNT_dec(sv);          /* free old sv */
-    sv = New;
+    sv = tmpNew;
     s = SvPV(sv, len);
   }
   t = s + len - 1;
@@ -2764,7 +2896,7 @@ PP(pp_unpack)
 {
     djSP;
     dPOPPOPssrl;
-    SV **oldsp = sp;
+    SV **oldsp = SP;
     I32 gimme = GIMME_V;
     SV *sv;
     STRLEN llen;
@@ -3061,7 +3193,7 @@ PP(pp_unpack)
                    s += SIZE16;
 #ifdef HAS_NTOHS
                    if (datumtype == 'n')
-                       aushort = ntohs(aushort);
+                       aushort = PerlSock_ntohs(aushort);
 #endif
 #ifdef HAS_VTOHS
                    if (datumtype == 'v')
@@ -3079,7 +3211,7 @@ PP(pp_unpack)
                    sv = NEWSV(39, 0);
 #ifdef HAS_NTOHS
                    if (datumtype == 'n')
-                       aushort = ntohs(aushort);
+                       aushort = PerlSock_ntohs(aushort);
 #endif
 #ifdef HAS_VTOHS
                    if (datumtype == 'v')
@@ -3111,6 +3243,13 @@ PP(pp_unpack)
                    Copy(s, &aint, 1, int);
                    s += sizeof(int);
                    sv = NEWSV(40, 0);
+#ifdef __osf__
+                    /* Without the dummy below unpack("i", pack("i",-1))
+                     * return 0xFFffFFff instead of -1 for Digital Unix V4.0
+                     * cc with optimization turned on */
+                    (aint) ?
+                       sv_setiv(sv, (IV)aint) :
+#endif
                    sv_setiv(sv, (IV)aint);
                    PUSHs(sv_2mortal(sv));
                }
@@ -3180,7 +3319,7 @@ PP(pp_unpack)
                    s += SIZE32;
 #ifdef HAS_NTOHL
                    if (datumtype == 'N')
-                       aulong = ntohl(aulong);
+                       aulong = PerlSock_ntohl(aulong);
 #endif
 #ifdef HAS_VTOHL
                    if (datumtype == 'V')
@@ -3200,7 +3339,7 @@ PP(pp_unpack)
                    s += SIZE32;
 #ifdef HAS_NTOHL
                    if (datumtype == 'N')
-                       aulong = ntohl(aulong);
+                       aulong = PerlSock_ntohl(aulong);
 #endif
 #ifdef HAS_VTOHL
                    if (datumtype == 'V')
@@ -3234,7 +3373,7 @@ PP(pp_unpack)
        case 'w':
            EXTEND(SP, len);
            EXTEND_MORTAL(len);
-           { 
+           {
                UV auv = 0;
                U32 bytes = 0;
                
@@ -3287,6 +3426,9 @@ PP(pp_unpack)
            break;
 #ifdef HAS_QUAD
        case 'q':
+           along = (strend - s) / sizeof(Quad_t);
+           if (len > along)
+               len = along;
            EXTEND(SP, len);
            EXTEND_MORTAL(len);
            while (len-- > 0) {
@@ -3305,6 +3447,9 @@ PP(pp_unpack)
            }
            break;
        case 'Q':
+           along = (strend - s) / sizeof(Quad_t);
+           if (len > along)
+               len = along;
            EXTEND(SP, len);
            EXTEND_MORTAL(len);
            while (len-- > 0) {
@@ -3315,7 +3460,7 @@ PP(pp_unpack)
                    s += sizeof(unsigned Quad_t);
                }
                sv = NEWSV(43, 0);
-               if (aquad <= UV_MAX)
+               if (auquad <= UV_MAX)
                    sv_setuv(sv, (UV)auquad);
                else
                    sv_setnv(sv, (double)auquad);
@@ -3448,12 +3593,12 @@ PP(pp_unpack)
            checksum = 0;
        }
     }
-    if (sp == oldsp && gimme == G_SCALAR)
+    if (SP == oldsp && gimme == G_SCALAR)
        PUSHs(&sv_undef);
     RETURN;
 }
 
-static void
+STATIC void
 doencodes(register SV *sv, register char *s, register I32 len)
 {
     char hunk[5];
@@ -3477,7 +3622,7 @@ doencodes(register SV *sv, register char *s, register I32 len)
     sv_catpvn(sv, "\n", 1);
 }
 
-static SV      *
+STATIC SV      *
 is_an_int(char *s, STRLEN l)
 {
   SV             *result = newSVpv("", l);
@@ -3525,10 +3670,10 @@ is_an_int(char *s, STRLEN l)
   return (result);
 }
 
-static int
-div128(SV *pnum, char *done)
+STATIC int
+div128(SV *pnum, bool *done)
                                            /* must be '\0' terminated */
-                          
+
 {
   STRLEN          len;
   char           *s = SvPV(pnum, len);
@@ -3810,7 +3955,7 @@ PP(pp_pack)
                fromstr = NEXTFROM;
                ashort = (I16)SvIV(fromstr);
 #ifdef HAS_HTONS
-               ashort = htons(ashort);
+               ashort = PerlSock_htons(ashort);
 #endif
                CAT16(cat, &ashort);
            }
@@ -3876,7 +4021,7 @@ PP(pp_pack)
                    SV             *norm;
                    STRLEN          len;
                    bool            done;
-            
+
                    /* Copy string and check for compliance */
                    from = SvPV(fromstr, len);
                    if ((norm = is_an_int(from, len)) == NULL)
@@ -3922,7 +4067,7 @@ PP(pp_pack)
                fromstr = NEXTFROM;
                aulong = SvUV(fromstr);
 #ifdef HAS_HTONL
-               aulong = htonl(aulong);
+               aulong = PerlSock_htonl(aulong);
 #endif
                CAT32(cat, &aulong);
            }
@@ -4020,6 +4165,7 @@ PP(pp_pack)
 }
 #undef NEXTFROM
 
+
 PP(pp_split)
 {
     djSP; dTARG;
@@ -4043,6 +4189,8 @@ PP(pp_split)
     AV *oldstack = curstack;
     I32 gimme = GIMME_V;
     I32 oldsave = savestack_ix;
+    I32 make_mortal = 1;
+    MAGIC *mg = (MAGIC *) NULL;
 
 #ifdef DEBUGGING
     Copy(&LvTARGOFF(POPs), &pm, 1, PMOP*);
@@ -4068,15 +4216,24 @@ PP(pp_split)
        ary = Nullav;
     if (ary && (gimme != G_ARRAY || (pm->op_pmflags & PMf_ONCE))) {
        realarray = 1;
-       if (!AvREAL(ary)) {
-           AvREAL_on(ary);
-           for (i = AvFILL(ary); i >= 0; i--)
-               AvARRAY(ary)[i] = &sv_undef;    /* don't free mere refs */
-       }
+       PUTBACK;
        av_extend(ary,0);
        av_clear(ary);
-       /* temporarily switch stacks */
-       SWITCHSTACK(curstack, ary);
+       SPAGAIN;
+       if (SvRMAGICAL(ary) && (mg = mg_find((SV *) ary, 'P'))) {
+           PUSHMARK(SP);
+           XPUSHs(mg->mg_obj);
+       }
+       else {
+           if (!AvREAL(ary)) {
+               AvREAL_on(ary);
+               for (i = AvFILLp(ary); i >= 0; i--)
+                   AvARRAY(ary)[i] = &sv_undef;        /* don't free mere refs */
+           }
+           /* temporarily switch stacks */
+           SWITCHSTACK(curstack, ary);
+           make_mortal = 0;
+       }
     }
     base = SP - stack_base;
     orig = s;
@@ -4109,7 +4266,7 @@ PP(pp_split)
 
            dstr = NEWSV(30, m-s);
            sv_setpvn(dstr, s, m-s);
-           if (!realarray)
+           if (make_mortal)
                sv_2mortal(dstr);
            XPUSHs(dstr);
 
@@ -4129,13 +4286,13 @@ PP(pp_split)
                break;
            dstr = NEWSV(30, m-s);
            sv_setpvn(dstr, s, m-s);
-           if (!realarray)
+           if (make_mortal)
                sv_2mortal(dstr);
            XPUSHs(dstr);
            s = m;
        }
     }
-    else if (rx->check_substr && !rx->nparens 
+    else if (rx->check_substr && !rx->nparens
             && (rx->reganch & ROPT_CHECK_ALL)
             && !(rx->reganch & ROPT_ANCH)) {
        i = SvCUR(rx->check_substr);
@@ -4148,7 +4305,7 @@ PP(pp_split)
                    break;
                dstr = NEWSV(30, m-s);
                sv_setpvn(dstr, s, m-s);
-               if (!realarray)
+               if (make_mortal)
                    sv_2mortal(dstr);
                XPUSHs(dstr);
                s = m + 1;
@@ -4158,12 +4315,12 @@ PP(pp_split)
 #ifndef lint
            while (s < strend && --limit &&
              (m=fbm_instr((unsigned char*)s, (unsigned char*)strend,
-                   rx->check_substr)) )
+                   rx->check_substr, 0)) )
 #endif
            {
                dstr = NEWSV(31, m-s);
                sv_setpvn(dstr, s, m-s);
-               if (!realarray)
+               if (make_mortal)
                    sv_2mortal(dstr);
                XPUSHs(dstr);
                s = m + i;
@@ -4173,7 +4330,7 @@ PP(pp_split)
     else {
        maxiters += (strend - s) * rx->nparens;
        while (s < strend && --limit &&
-              regexec_flags(rx, s, strend, orig, 1, Nullsv, NULL, 0))
+              CALLREGEXEC(rx, s, strend, orig, 1, Nullsv, NULL, 0))
        {
            TAINT_IF(RX_MATCH_TAINTED(rx));
            if (rx->subbase
@@ -4187,7 +4344,7 @@ PP(pp_split)
            m = rx->startp[0];
            dstr = NEWSV(32, m-s);
            sv_setpvn(dstr, s, m-s);
-           if (!realarray)
+           if (make_mortal)
                sv_2mortal(dstr);
            XPUSHs(dstr);
            if (rx->nparens) {
@@ -4200,7 +4357,7 @@ PP(pp_split)
                    }
                    else
                        dstr = NEWSV(33, 0);
-                   if (!realarray)
+                   if (make_mortal)
                        sv_2mortal(dstr);
                    XPUSHs(dstr);
                }
@@ -4208,16 +4365,17 @@ PP(pp_split)
            s = rx->endp[0];
        }
     }
+
     LEAVE_SCOPE(oldsave);
     iters = (SP - stack_base) - base;
     if (iters > maxiters)
        DIE("Split loop");
-    
+
     /* keep field after final delim? */
     if (s < strend || (iters && origlimit)) {
        dstr = NEWSV(34, strend-s);
        sv_setpvn(dstr, s, strend-s);
-       if (!realarray)
+       if (make_mortal)
            sv_2mortal(dstr);
        XPUSHs(dstr);
        iters++;
@@ -4226,18 +4384,37 @@ PP(pp_split)
        while (iters > 0 && (!TOPs || !SvANY(TOPs) || SvCUR(TOPs) == 0))
            iters--, SP--;
     }
+
     if (realarray) {
-       SWITCHSTACK(ary, oldstack);
-       if (SvSMAGICAL(ary)) {
+       if (!mg) {
+           SWITCHSTACK(ary, oldstack);
+           if (SvSMAGICAL(ary)) {
+               PUTBACK;
+               mg_set((SV*)ary);
+               SPAGAIN;
+           }
+           if (gimme == G_ARRAY) {
+               EXTEND(SP, iters);
+               Copy(AvARRAY(ary), SP + 1, iters, SV*);
+               SP += iters;
+               RETURN;
+           }
+       }
+       else {
            PUTBACK;
-           mg_set((SV*)ary);
+           ENTER;
+           perl_call_method("PUSH",G_SCALAR|G_DISCARD);
+           LEAVE;
            SPAGAIN;
-       }
-       if (gimme == G_ARRAY) {
-           EXTEND(SP, iters);
-           Copy(AvARRAY(ary), SP + 1, iters, SV*);
-           SP += iters;
-           RETURN;
+           if (gimme == G_ARRAY) {
+               /* EXTEND should not be needed - we just popped them */
+               EXTEND(SP, iters);
+               for (i=0; i < iters; i++) {
+                   SV **svp = av_fetch(ary, i, FALSE);
+                   PUSHs((svp) ? *svp : &sv_undef);
+               }
+               RETURN;
+           }
        }
     }
     else {
@@ -4258,7 +4435,7 @@ unlock_condpair(void *svv)
 {
     dTHR;
     MAGIC *mg = mg_find((SV*)svv, 'm');
-    
+
     if (!mg)
        croak("panic: unlock_condpair unlocking non-mutex");
     MUTEX_LOCK(MgMUTEXP(mg));
@@ -4279,7 +4456,7 @@ PP(pp_lock)
     SV *retsv = sv;
 #ifdef USE_THREADS
     MAGIC *mg;
-    
+
     if (SvROK(sv))
        sv = SvRV(sv);
 
@@ -4310,11 +4487,11 @@ PP(pp_threadsv)
 {
     djSP;
 #ifdef USE_THREADS
-    EXTEND(sp, 1);
+    EXTEND(SP, 1);
     if (op->op_private & OPpLVAL_INTRO)
        PUSHs(*save_threadsv(op->op_targ));
     else
-       PUSHs(*av_fetch(thr->threadsv, op->op_targ, FALSE));
+       PUSHs(THREADSV(op->op_targ));
     RETURN;
 #else
     DIE("tried to access per-thread data in non-threaded perl");