turbidity in av.[ch]
[p5sagit/p5-mst-13.2.git] / pp.c
diff --git a/pp.c b/pp.c
index 23fd79c..711ba29 100644 (file)
--- a/pp.c
+++ b/pp.c
@@ -98,11 +98,19 @@ PP(pp_rv2gv)
     if (SvROK(sv)) {
       wasref:
        sv = SvRV(sv);
-       if (SvTYPE(sv) != SVt_PVGV)
+       if (SvTYPE(sv) == SVt_PVIO) {
+           GV *gv = (GV*) sv_newmortal();
+           gv_init(gv, 0, "", 0, 0);
+           GvIOp(gv) = (IO *)sv;
+           SvREFCNT_inc(sv);
+           sv = (SV*) gv;
+       } else if (SvTYPE(sv) != SVt_PVGV)
            DIE("Not a GLOB reference");
     }
     else {
        if (SvTYPE(sv) != SVt_PVGV) {
+           char *sym;
+
            if (SvGMAGICAL(sv)) {
                mg_get(sv);
                if (SvROK(sv))
@@ -114,22 +122,23 @@ PP(pp_rv2gv)
                    DIE(no_usym, "a symbol");
                RETSETUNDEF;
            }
+           sym = SvPV(sv, na);
            if (op->op_private & HINT_STRICT_REFS)
-               DIE(no_symref, "a symbol");
-           sv = (SV*)gv_fetchpv(SvPV(sv, na), TRUE, SVt_PVGV);
+               DIE(no_symref, sym, "a symbol");
+           sv = (SV*)gv_fetchpv(sym, TRUE, SVt_PVGV);
        }
     }
     if (op->op_private & OPpLVAL_INTRO) {
        GP *ogp = GvGP(sv);
 
        SSCHECK(3);
-       SSPUSHPTR(sv);
+       SSPUSHPTR(SvREFCNT_inc(sv));
        SSPUSHPTR(ogp);
        SSPUSHINT(SAVEt_GP);
 
        if (op->op_flags & OPf_SPECIAL) {
            GvGP(sv)->gp_refcnt++;              /* will soon be assigned */
-           GvFLAGS(sv) |= GVf_INTRO;
+           GvINTRO_on(sv);
        }
        else {
            GP *gp;
@@ -138,21 +147,13 @@ PP(pp_rv2gv)
            GvREFCNT(sv) = 1;
            GvSV(sv) = NEWSV(72,0);
            GvLINE(sv) = curcop->cop_line;
-           GvEGV(sv) = sv;
+           GvEGV(sv) = (GV*)sv;
        }
     }
     SETs(sv);
     RETURN;
 }
 
-PP(pp_sv2len)
-{
-    dSP; dTARGET;
-    dPOPss;
-    PUSHi(sv_len(sv));
-    RETURN;
-}
-
 PP(pp_rv2sv)
 {
     dSP; dTOPss;
@@ -168,7 +169,9 @@ PP(pp_rv2sv)
        }
     }
     else {
-       GV *gv = sv;
+       GV *gv = (GV*)sv;
+       char *sym;
+
        if (SvTYPE(gv) != SVt_PVGV) {
            if (SvGMAGICAL(sv)) {
                mg_get(sv);
@@ -181,26 +184,18 @@ PP(pp_rv2sv)
                    DIE(no_usym, "a SCALAR");
                RETSETUNDEF;
            }
+           sym = SvPV(sv, na);
            if (op->op_private & HINT_STRICT_REFS)
-               DIE(no_symref, "a SCALAR");
-           gv = (SV*)gv_fetchpv(SvPV(sv, na), TRUE, SVt_PV);
+               DIE(no_symref, sym, "a SCALAR");
+           gv = (GV*)gv_fetchpv(sym, TRUE, SVt_PV);
        }
        sv = GvSV(gv);
     }
     if (op->op_flags & OPf_MOD) {
        if (op->op_private & OPpLVAL_INTRO)
            sv = save_scalar((GV*)TOPs);
-       else if (op->op_private & (OPpDEREF_HV|OPpDEREF_AV)) {
-           if (SvGMAGICAL(sv))
-               mg_get(sv);
-           if (!SvOK(sv)) {
-               (void)SvUPGRADE(sv, SVt_RV);
-               SvRV(sv) = (op->op_private & OPpDEREF_HV ?
-                           (SV*)newHV() : (SV*)newAV());
-               SvROK_on(sv);
-               SvSETMAGIC(sv);
-           }
-       }
+       else if (op->op_private & (OPpDEREF_HV|OPpDEREF_AV))
+           provide_ref(op, sv);
     }
     SETs(sv);
     RETURN;
@@ -250,17 +245,44 @@ PP(pp_rv2cv)
     GV *gv;
     HV *stash;
 
-    /* We always try to add a non-existent subroutine in case of AUTOLOAD. */
-    CV *cv = sv_2cv(TOPs, &stash, &gv, TRUE);
+    /* We usually try to add a non-existent subroutine in case of AUTOLOAD. */
+    /* (But not in defined().) */
+    CV *cv = sv_2cv(TOPs, &stash, &gv, !(op->op_flags & OPf_SPECIAL));
 
+    if (!cv)
+       cv = (CV*)&sv_undef;
     SETs((SV*)cv);
     RETURN;
 }
 
+PP(pp_prototype)
+{
+    dSP;
+    CV *cv;
+    HV *stash;
+    GV *gv;
+    SV *ret;
+
+    ret = &sv_undef;
+    cv = sv_2cv(TOPs, &stash, &gv, FALSE);
+    if (cv && SvPOK(cv)) {
+       char *p = SvPVX(cv);
+       ret = sv_2mortal(newSVpv(p ? p : "", SvLEN(cv)));
+    }
+    SETs(ret);
+    RETURN;
+}
+
 PP(pp_anoncode)
 {
     dSP;
-    XPUSHs(cSVOP->op_sv);
+    CV* cv = (CV*)cSVOP->op_sv;
+    EXTEND(SP,1);
+
+    if (CvCLONE(cv))
+       cv = (CV*)sv_2mortal((SV*)cv_clone(cv));
+
+    PUSHs((SV*)cv);
     RETURN;
 }
 
@@ -315,8 +337,12 @@ PP(pp_ref)
     char *pv;
 
     sv = POPs;
+
+    if (sv && SvGMAGICAL(sv))
+       mg_get(sv);     
+
     if (!sv || !SvROK(sv))
-       RETPUSHUNDEF;
+       RETPUSHNO;
 
     sv = SvRV(sv);
     pv = sv_reftype(sv,TRUE);
@@ -342,7 +368,7 @@ PP(pp_bless)
 
 PP(pp_study)
 {
-    dSP; dTARGET;
+    dSP; dPOPss;
     register unsigned char *s;
     register I32 pos;
     register I32 ch;
@@ -351,11 +377,17 @@ PP(pp_study)
     I32 retval;
     STRLEN len;
 
-    s = (unsigned char*)(SvPV(TARG, len));
+    s = (unsigned char*)(SvPV(sv, len));
     pos = len;
-    if (lastscream)
-       SvSCREAM_off(lastscream);
-    lastscream = TARG;
+    if (sv == lastscream)
+       SvSCREAM_off(sv);
+    else {
+       if (lastscream) {
+           SvSCREAM_off(lastscream);
+           SvREFCNT_dec(lastscream);
+       }
+       lastscream = SvREFCNT_inc(sv);
+    }
     if (pos <= 0) {
        retval = 0;
        goto ret;
@@ -398,7 +430,8 @@ PP(pp_study)
            sfirst[fold[ch]] = pos;
     }
 
-    SvSCREAM_on(TARG);
+    SvSCREAM_on(sv);
+    sv_magic(sv, Nullsv, 'g', Nullch, 0);      /* piggyback on m//g magic */
     retval = 1;
   ret:
     XPUSHs(sv_2mortal(newSViv((I32)retval)));
@@ -468,11 +501,11 @@ PP(pp_defined)
        RETPUSHNO;
     switch (SvTYPE(sv)) {
     case SVt_PVAV:
-       if (AvMAX(sv) >= 0)
+       if (AvMAX(sv) >= 0 || SvRMAGICAL(sv))
            RETPUSHYES;
        break;
     case SVt_PVHV:
-       if (HvARRAY(sv))
+       if (HvARRAY(sv) || SvRMAGICAL(sv))
            RETPUSHYES;
        break;
     case SVt_PVCV:
@@ -520,17 +553,20 @@ PP(pp_undef)
        cv_undef((CV*)sv);
        sub_generation++;
        break;
+    case SVt_PVGV:
+        if (SvFAKE(sv)) {
+            sv_setsv(sv, &sv_undef);
+            break;
+        }
     default:
-       if (sv != GvSV(defgv)) {
-           if (SvPOK(sv) && SvLEN(sv)) {
-               (void)SvOOK_off(sv);
-               Safefree(SvPVX(sv));
-               SvPV_set(sv, Nullch);
-               SvLEN_set(sv, 0);
-           }
-           (void)SvOK_off(sv);
-           SvSETMAGIC(sv);
+       if (SvPOK(sv) && SvLEN(sv)) {
+           (void)SvOOK_off(sv);
+           Safefree(SvPVX(sv));
+           SvPV_set(sv, Nullch);
+           SvLEN_set(sv, 0);
        }
+       (void)SvOK_off(sv);
+       SvSETMAGIC(sv);
     }
 
     RETPUSHUNDEF;
@@ -539,7 +575,17 @@ PP(pp_undef)
 PP(pp_predec)
 {
     dSP;
-    sv_dec(TOPs);
+    if (SvIOK(TOPs)) {
+       if (SvIVX(TOPs) == IV_MIN) {
+           sv_setnv(TOPs, (double)SvIVX(TOPs) - 1.0);
+       }
+       else {
+           --SvIVX(TOPs);
+           SvFLAGS(TOPs) &= ~(SVf_NOK|SVf_POK|SVp_NOK|SVp_POK);
+       }
+    }
+    else
+       sv_dec(TOPs);
     SvSETMAGIC(TOPs);
     return NORMAL;
 }
@@ -548,7 +594,17 @@ PP(pp_postinc)
 {
     dSP; dTARGET;
     sv_setsv(TARG, TOPs);
-    sv_inc(TOPs);
+    if (SvIOK(TOPs)) {
+       if (SvIVX(TOPs) == IV_MAX) {
+           sv_setnv(TOPs, (double)SvIVX(TOPs) + 1.0);
+       }
+       else {
+           ++SvIVX(TOPs);
+           SvFLAGS(TOPs) &= ~(SVf_NOK|SVf_POK|SVp_NOK|SVp_POK);
+       }
+    }
+    else
+       sv_inc(TOPs);
     SvSETMAGIC(TOPs);
     if (!SvOK(TARG))
        sv_setiv(TARG, 0);
@@ -560,7 +616,17 @@ PP(pp_postdec)
 {
     dSP; dTARGET;
     sv_setsv(TARG, TOPs);
-    sv_dec(TOPs);
+    if (SvIOK(TOPs)) {
+       if (SvIVX(TOPs) == IV_MIN) {
+           sv_setnv(TOPs, (double)SvIVX(TOPs) - 1.0);
+       }
+       else {
+           --SvIVX(TOPs);
+           SvFLAGS(TOPs) &= ~(SVf_NOK|SVf_POK|SVp_NOK|SVp_POK);
+       }
+    }
+    else
+       sv_dec(TOPs);
     SvSETMAGIC(TOPs);
     SETs(TARG);
     return NORMAL;
@@ -642,7 +708,8 @@ PP(pp_modulo)
 
 PP(pp_repeat)
 {
-    dSP; dATARGET;
+  dSP; dATARGET; tryAMAGICbin(repeat,opASSIGN);
+  {
     register I32 count = POPi;
     if (GIMME == G_ARRAY && op->op_private & OPpREPEAT_DOLIST) {
        dMARK;
@@ -691,6 +758,7 @@ PP(pp_repeat)
        PUSHTARG;
     }
     RETURN;
+  }
 }
 
 PP(pp_subtract)
@@ -707,9 +775,9 @@ PP(pp_left_shift)
 {
     dSP; dATARGET; tryAMAGICbin(lshift,opASSIGN); 
     {
-      dPOPTOPiirl;
-      SETi( left << right );
-      RETURN;
+        dPOPTOPiirl;
+        SETi( left << right );
+        RETURN;
     }
 }
 
@@ -855,7 +923,7 @@ PP(pp_bit_and) {
     dSP; dATARGET; tryAMAGICbin(band,opASSIGN); 
     {
       dPOPTOPssrl;
-      if (SvNIOK(left) || SvNIOK(right)) {
+      if (SvNIOKp(left) || SvNIOKp(right)) {
        unsigned long value = U_L(SvNV(left));
        value = value & U_L(SvNV(right));
        SETn((double)value);
@@ -873,7 +941,7 @@ PP(pp_bit_xor)
     dSP; dATARGET; tryAMAGICbin(bxor,opASSIGN); 
     {
       dPOPTOPssrl;
-      if (SvNIOK(left) || SvNIOK(right)) {
+      if (SvNIOKp(left) || SvNIOKp(right)) {
        unsigned long value = U_L(SvNV(left));
        value = value ^ U_L(SvNV(right));
        SETn((double)value);
@@ -891,7 +959,7 @@ PP(pp_bit_or)
     dSP; dATARGET; tryAMAGICbin(bor,opASSIGN); 
     {
       dPOPTOPssrl;
-      if (SvNIOK(left) || SvNIOK(right)) {
+      if (SvNIOKp(left) || SvNIOKp(right)) {
        unsigned long value = U_L(SvNV(left));
        value = value | U_L(SvNV(right));
        SETn((double)value);
@@ -909,9 +977,11 @@ PP(pp_negate)
     dSP; dTARGET; tryAMAGICun(neg);
     {
        dTOPss;
-       if (SvNIOK(sv))
+       if (SvGMAGICAL(sv))
+           mg_get(sv);
+       if (SvNIOKp(sv))
            SETn(-SvNV(sv));
-       else if (SvPOK(sv)) {
+       else if (SvPOKp(sv)) {
            STRLEN len;
            char *s = SvPV(sv, len);
            if (isALPHA(*s) || *s == '_') {
@@ -926,6 +996,8 @@ PP(pp_negate)
                sv_setnv(TARG, -SvNV(sv));
            SETTARG;
        }
+       else
+           SETn(-SvNV(sv));
     }
     RETURN;
 }
@@ -946,8 +1018,12 @@ PP(pp_complement)
       dTOPss;
       register I32 anum;
 
-      if (SvNIOK(sv)) {
-       SETi(  ~SvIV(sv) );
+      if (SvNIOKp(sv)) {
+       IV iv = ~SvIV(sv);
+       if (iv < 0)
+           SETn( (double) ~U_L(SvNV(sv)) );
+       else
+           SETi( iv );
       }
       else {
        register char *tmps;
@@ -976,84 +1052,6 @@ PP(pp_complement)
 
 /* integer versions of some of the above */
 
-PP(pp_i_preinc)
-{
-#ifndef OVERLOAD
-    dSP; dTOPiv;
-    sv_setiv(TOPs, value + 1);
-    SvSETMAGIC(TOPs);
-#else
-    dSP;
-    if (SvAMAGIC(TOPs) ) {
-      sv_inc(TOPs);
-    } else {
-      dTOPiv;
-      sv_setiv(TOPs, value + 1);
-      SvSETMAGIC(TOPs);
-    }
-#endif /* OVERLOAD */
-    return NORMAL;
-}
-
-PP(pp_i_predec)
-{
-#ifndef OVERLOAD
-    dSP; dTOPiv;
-    sv_setiv(TOPs, value - 1);
-    SvSETMAGIC(TOPs);
-#else
-    dSP;
-    if (SvAMAGIC(TOPs)) {
-      sv_dec(TOPs);
-    } else {
-      dTOPiv;
-      sv_setiv(TOPs, value - 1);
-      SvSETMAGIC(TOPs);
-    }
-#endif /* OVERLOAD */
-    return NORMAL;
-}
-
-PP(pp_i_postinc)
-{
-    dSP; dTARGET;
-    sv_setsv(TARG, TOPs);
-#ifndef OVERLOAD
-    sv_setiv(TOPs, SvIV(TOPs) + 1);
-    SvSETMAGIC(TOPs);
-#else
-    if (SvAMAGIC(TOPs) ) {
-      sv_inc(TOPs);
-    } else {
-      sv_setiv(TOPs, SvIV(TOPs) + 1);
-      SvSETMAGIC(TOPs);
-    }
-#endif /* OVERLOAD */
-    if (!SvOK(TARG))
-       sv_setiv(TARG, 0);
-    SETs(TARG);
-    return NORMAL;
-}
-
-PP(pp_i_postdec)
-{
-    dSP; dTARGET;
-    sv_setsv(TARG, TOPs);
-#ifndef OVERLOAD
-    sv_setiv(TOPs, SvIV(TOPs) - 1);
-    SvSETMAGIC(TOPs);
-#else
-    if (SvAMAGIC(TOPs) ) {
-      sv_dec(TOPs);
-    } else {
-      sv_setiv(TOPs, SvIV(TOPs) - 1);
-      SvSETMAGIC(TOPs);
-    }
-#endif /* OVERLOAD */
-    SETs(TARG);
-    return NORMAL;
-}
-
 PP(pp_i_multiply)
 {
     dSP; dATARGET; tryAMAGICbin(mult,opASSIGN); 
@@ -1259,11 +1257,31 @@ PP(pp_srand)
 {
     dSP;
     I32 anum;
-    Time_t when;
 
     if (MAXARG < 1) {
+#ifdef VMS
+#  include <starlet.h>
+       unsigned int when[2];
+       _ckvmssts(sys$gettim(when));
+       anum = when[0] ^ when[1];
+#else
+#  if defined(I_SYS_TIME) && !defined(PLAN9)
+       struct timeval when;
+       gettimeofday(&when,(struct timezone *) 0);
+       anum = when.tv_sec ^ when.tv_usec;
+#  else
+       Time_t when;
        (void)time(&when);
        anum = when;
+#  endif
+#endif
+#if !defined(PLAN9) /* XXX Plan9 assembler chokes on this; fix coming soon  */
+                    /*     17-Jul-1996  bailey@genetics.upenn.edu           */
+       /* What is a good hashing algorithm here? */
+       anum ^= (  (  269 * (U32)getpid())
+                ^ (26107 * (U32)&when)
+                ^ (73819 * (U32)stack_sp));
+#endif
     }
     else
        anum = POPi;
@@ -1346,28 +1364,38 @@ PP(pp_hex)
 {
     dSP; dTARGET;
     char *tmps;
+    unsigned long value;
     I32 argtype;
 
     tmps = POPp;
-    XPUSHi( scan_hex(tmps, 99, &argtype) );
+    value = scan_hex(tmps, 99, &argtype);
+    if ((IV)value >= 0)
+       XPUSHi(value);
+    else
+       XPUSHn(U_V(value));
     RETURN;
 }
 
 PP(pp_oct)
 {
     dSP; dTARGET;
-    I32 value;
+    unsigned long value;
     I32 argtype;
     char *tmps;
 
     tmps = POPp;
-    while (*tmps && (isSPACE(*tmps) || *tmps == '0'))
+    while (*tmps && isSPACE(*tmps))
+       tmps++;
+    if (*tmps == '0')
        tmps++;
     if (*tmps == 'x')
-       value = (I32)scan_hex(++tmps, 99, &argtype);
+       value = scan_hex(++tmps, 99, &argtype);
     else
-       value = (I32)scan_oct(tmps, 99, &argtype);
-    XPUSHi(value);
+       value = scan_oct(tmps, 99, &argtype);
+    if ((IV)value >= 0)
+       XPUSHi(value);
+    else
+       XPUSHn(U_V(value));
     RETURN;
 }
 
@@ -1408,7 +1436,7 @@ PP(pp_substr)
        if (MAXARG < 3)
            len = curlen;
        else if (len < 0) {
-           len += curlen;
+           len += curlen - pos;
            if (len < 0)
                len = 0;
        }
@@ -1418,6 +1446,17 @@ PP(pp_substr)
            rem = len;
        sv_setpvn(TARG, tmps, rem);
        if (lvalue) {                   /* it's an lvalue! */
+           if (!SvGMAGICAL(sv)) {
+               if (SvROK(sv)) {
+                   SvPV_force(sv,na);
+                   if (dowarn)
+                       warn("Attempt to use reference as lvalue in substr");
+               }
+               if (SvOK(sv))           /* is it defined ? */
+                   (void)SvPOK_only(sv);
+               else
+                   sv_setpvn(sv,"",0); /* avoid lexical reincarnation */
+           }
            if (SvTYPE(TARG) < SVt_PVLV) {
                sv_upgrade(TARG, SVt_PVLV);
                sv_magic(TARG, Nullsv, 'x', Nullch, 0);
@@ -1466,20 +1505,24 @@ PP(pp_vec)
                retnum = 0;
            else {
                offset >>= 3;
-               if (size == 16)
-                   retnum = (unsigned long) s[offset] << 8;
-               else if (size == 32) {
-                   if (offset < len) {
-                       if (offset + 1 < len)
-                           retnum = ((unsigned long) s[offset] << 24) +
-                               ((unsigned long) s[offset + 1] << 16) +
-                               (s[offset + 2] << 8);
-                       else
-                           retnum = ((unsigned long) s[offset] << 24) +
-                               ((unsigned long) s[offset + 1] << 16);
-                   }
+               if (size == 16) {
+                   if (offset >= srclen)
+                       retnum = 0;
                    else
+                       retnum = (unsigned long) s[offset] << 8;
+               }
+               else if (size == 32) {
+                   if (offset >= srclen)
+                       retnum = 0;
+                   else if (offset + 1 >= srclen)
                        retnum = (unsigned long) s[offset] << 24;
+                   else if (offset + 2 >= srclen)
+                       retnum = ((unsigned long) s[offset] << 24) +
+                           ((unsigned long) s[offset + 1] << 16);
+                   else
+                       retnum = ((unsigned long) s[offset] << 24) +
+                           ((unsigned long) s[offset + 1] << 16) +
+                           (s[offset + 2] << 8);
                }
            }
        }
@@ -1605,13 +1648,12 @@ PP(pp_chr)
     dSP; dTARGET;
     char *tmps;
 
-    if (!SvPOK(TARG)) {
-       (void)SvUPGRADE(TARG,SVt_PV);
-       SvGROW(TARG,1);
-    }
+    (void)SvUPGRADE(TARG,SVt_PV);
+    SvGROW(TARG,2);
     SvCUR_set(TARG, 1);
     tmps = SvPVX(TARG);
-    *tmps = POPi;
+    *tmps++ = POPi;
+    *tmps = '\0';
     (void)SvPOK_only(TARG);
     XPUSHs(TARG);
     RETURN;
@@ -1732,7 +1774,7 @@ PP(pp_quotemeta)
 
     if (len) {
        (void)SvUPGRADE(TARG, SVt_PV);
-       SvGROW(TARG, len * 2);
+       SvGROW(TARG, (len * 2) + 1);
        d = SvPVX(TARG);
        while (len--) {
            if (!isALNUM(*s))
@@ -1757,11 +1799,25 @@ PP(pp_aslice)
     register SV** svp;
     register AV* av = (AV*)POPs;
     register I32 lval = op->op_flags & OPf_MOD;
+    I32 arybase = curcop->cop_arybase;
+    I32 elem;
 
     if (SvTYPE(av) == SVt_PVAV) {
+       if (lval && op->op_private & OPpLVAL_INTRO) {
+           I32 max = -1;
+           for (svp = mark + 1; svp <= sp; svp++) {
+               elem = SvIVx(*svp);
+               if (elem > max)
+                   max = elem;
+           }
+           if (max > AvMAX(av))
+               av_extend(av, max);
+       }
        while (++MARK <= SP) {
-           I32 elem = SvIVx(*MARK);
+           elem = SvIVx(*MARK);
 
+           if (elem > 0)
+               elem -= arybase;
            svp = av_fetch(av, elem, lval);
            if (lval) {
                if (!svp || *svp == &sv_undef)
@@ -1772,7 +1828,7 @@ PP(pp_aslice)
            *MARK = svp ? *svp : &sv_undef;
        }
     }
-    else if (GIMME != G_ARRAY) {
+    if (GIMME != G_ARRAY) {
        MARK = ORIGMARK;
        *++MARK = *SP;
        SP = MARK;
@@ -1786,18 +1842,19 @@ PP(pp_each)
 {
     dSP; dTARGET;
     HV *hash = (HV*)POPs;
-    HE *entry = hv_iternext(hash);
-    I32 i;
-    char *tmps;
+    HE *entry;
+    
+    PUTBACK;
+    entry = hv_iternext(hash);                        /* might clobber stack_sp */
+    SPAGAIN;
 
     EXTEND(SP, 2);
     if (entry) {
-       tmps = hv_iterkey(entry, &i);
-       if (!i)
-           tmps = "";
-       PUSHs(sv_2mortal(newSVpv(tmps, i)));
+       PUSHs(hv_iterkeysv(entry));                   /* won't clobber stack_sp */
        if (GIMME == G_ARRAY) {
-           sv_setsv(TARG, hv_iterval(hash, entry));
+           PUTBACK;
+           sv_setsv(TARG, hv_iterval(hash, entry));  /* might clobber stack_sp */
+           SPAGAIN;
            PUSHs(TARG);
        }
     }
@@ -1823,13 +1880,12 @@ PP(pp_delete)
     SV *sv;
     SV *tmpsv = POPs;
     HV *hv = (HV*)POPs;
-    char *tmps;
     STRLEN len;
     if (SvTYPE(hv) != SVt_PVHV) {
        DIE("Not a HASH reference");
     }
-    tmps = SvPV(tmpsv, len);
-    sv = hv_delete(hv, tmps, len);
+    sv = hv_delete_ent(hv, tmpsv,
+       (op->op_private & OPpLEAVE_VOID ? G_DISCARD : 0), 0);
     if (!sv)
        RETPUSHUNDEF;
     PUSHs(sv);
@@ -1841,13 +1897,11 @@ PP(pp_exists)
     dSP;
     SV *tmpsv = POPs;
     HV *hv = (HV*)POPs;
-    char *tmps;
     STRLEN len;
     if (SvTYPE(hv) != SVt_PVHV) {
        DIE("Not a HASH reference");
     }
-    tmps = SvPV(tmpsv, len);
-    if (hv_exists(hv, tmps, len))
+    if (hv_exists_ent(hv, tmpsv, 0))
        RETPUSHYES;
     RETPUSHNO;
 }
@@ -1855,23 +1909,22 @@ PP(pp_exists)
 PP(pp_hslice)
 {
     dSP; dMARK; dORIGMARK;
-    register SV **svp;
+    register HE *he;
     register HV *hv = (HV*)POPs;
     register I32 lval = op->op_flags & OPf_MOD;
 
     if (SvTYPE(hv) == SVt_PVHV) {
        while (++MARK <= SP) {
-           STRLEN keylen;
-           char *key = SvPV(*MARK, keylen);
+           SV *keysv = *MARK;
 
-           svp = hv_fetch(hv, key, keylen, lval);
+           he = hv_fetch_ent(hv, keysv, lval, 0);
            if (lval) {
-               if (!svp || *svp == &sv_undef)
-                   DIE(no_helem, key);
+               if (!he || HeVAL(he) == &sv_undef)
+                   DIE(no_helem, SvPV(keysv, na));
                if (op->op_private & OPpLVAL_INTRO)
-                   save_svref(svp);
+                   save_svref(&HeVAL(he));
            }
-           *MARK = svp ? *svp : &sv_undef;
+           *MARK = he ? HeVAL(he) : &sv_undef;
        }
     }
     if (GIMME != G_ARRAY) {
@@ -1905,13 +1958,19 @@ PP(pp_lslice)
     SV **firstlelem = stack_base + POPMARK + 1;
     register SV **firstrelem = lastlelem + 1;
     I32 arybase = curcop->cop_arybase;
+    I32 lval = op->op_flags & OPf_MOD;
+    I32 is_something_there = lval;
 
     register I32 max = lastrelem - lastlelem;
     register SV **lelem;
     register I32 ix;
 
     if (GIMME != G_ARRAY) {
-       ix = SvIVx(*lastlelem) - arybase;
+       ix = SvIVx(*lastlelem);
+       if (ix < 0)
+           ix += max;
+       else
+           ix -= arybase;
        if (ix < 0 || ix >= max)
            *firstlelem = &sv_undef;
        else
@@ -1926,7 +1985,7 @@ PP(pp_lslice)
     }
 
     for (lelem = firstlelem; lelem <= lastlelem; lelem++) {
-       ix = SvIVx(*lelem) - arybase;
+       ix = SvIVx(*lelem);
        if (ix < 0) {
            ix += max;
            if (ix < 0)
@@ -1934,10 +1993,18 @@ PP(pp_lslice)
            else if (!(*lelem = firstrelem[ix]))
                *lelem = &sv_undef;
        }
-       else if (ix >= max || !(*lelem = firstrelem[ix]))
-           *lelem = &sv_undef;
+       else {
+           ix -= arybase;
+           if (ix >= max || !(*lelem = firstrelem[ix]))
+               *lelem = &sv_undef;
+       }
+       if (!is_something_there && (SvOKp(*lelem) || SvGMAGICAL(*lelem)))
+           is_something_there = TRUE;
     }
-    SP = lastlelem;
+    if (is_something_there)
+       SP = lastlelem;
+    else
+       SP = firstlelem - 1;
     RETURN;
 }
 
@@ -1958,14 +2025,12 @@ PP(pp_anonhash)
 
     while (MARK < SP) {
        SV* key = *++MARK;
-       char *tmps;
        SV *val = NEWSV(46, 0);
        if (MARK < SP)
            sv_setsv(val, *++MARK);
        else
            warn("Odd number of elements in hash list");
-       tmps = SvPV(key,len);
-       (void)hv_store(hv,tmps,len,val,0);
+       (void)hv_store_ent(hv,key,val,0);
     }
     SP = ORIGMARK;
     XPUSHs((SV*)hv);
@@ -2300,7 +2365,7 @@ PP(pp_unpack)
     if (GIMME != G_ARRAY) {            /* arrange to do first one only */
        /*SUPPRESS 530*/
        for (patend = pat; !isALPHA(*patend) || *patend == 'x'; patend++) ;
-       if (strchr("aAbBhH", *patend) || *pat == '%') {
+       if (strchr("aAbBhHP", *patend) || *pat == '%') {
            patend++;
            while (isDIGIT(*patend) || *patend == '*')
                patend++;
@@ -2806,6 +2871,8 @@ PP(pp_unpack)
        case 'u':
            along = (strend - s) * 3 / 4;
            sv = NEWSV(42, along);
+           if (along)
+               SvPOK_on(sv);
            while (s < strend && *s > ' ' && *s < 'a') {
                I32 a, b, c, d;
                char hunk[4];
@@ -3301,9 +3368,10 @@ PP(pp_split)
     I32 origlimit = limit;
     I32 realarray = 0;
     I32 base;
-    AV *oldstack = stack;
+    AV *oldstack = curstack;
     register REGEXP *rx = pm->op_pmregexp;
     I32 gimme = GIMME;
+    I32 oldsave = savestack_ix;
 
     if (!pm || !s)
        DIE("panic: do_split");
@@ -3323,7 +3391,7 @@ PP(pp_split)
        av_extend(ary,0);
        av_clear(ary);
        /* temporarily switch stacks */
-       SWITCHSTACK(stack, ary);
+       SWITCHSTACK(curstack, ary);
     }
     base = SP - stack_base;
     orig = s;
@@ -3331,6 +3399,11 @@ PP(pp_split)
        while (isSPACE(*s))
            s++;
     }
+    if (pm->op_pmflags & (PMf_MULTILINE|PMf_SINGLELINE)) {
+       SAVEINT(multiline);
+       multiline = pm->op_pmflags & PMf_MULTILINE;
+    }
+
     if (!limit)
        limit = maxiters + 2;
     if (pm->op_pmflags & PMf_WHITE) {
@@ -3409,7 +3482,7 @@ PP(pp_split)
     else {
        maxiters += (strend - s) * rx->nparens;
        while (s < strend && --limit &&
-           regexec(rx, s, strend, orig, 1, Nullsv, TRUE) ) {
+           pregexec(rx, s, strend, orig, 1, Nullsv, TRUE) ) {
            if (rx->subbase
              && rx->subbase != orig) {
                m = s;
@@ -3428,8 +3501,12 @@ PP(pp_split)
                for (i = 1; i <= rx->nparens; i++) {
                    s = rx->startp[i];
                    m = rx->endp[i];
-                   dstr = NEWSV(33, m-s);
-                   sv_setpvn(dstr, s, m-s);
+                   if (m && s) {
+                       dstr = NEWSV(33, m-s);
+                       sv_setpvn(dstr, s, m-s);
+                   }
+                   else
+                       dstr = NEWSV(33, 0);
                    if (!realarray)
                        sv_2mortal(dstr);
                    XPUSHs(dstr);
@@ -3438,6 +3515,7 @@ PP(pp_split)
            s = rx->endp[0];
        }
     }
+    LEAVE_SCOPE(oldsave);
     iters = (SP - stack_base) - base;
     if (iters > maxiters)
        DIE("Split loop");
@@ -3452,7 +3530,7 @@ PP(pp_split)
        iters++;
     }
     else if (!origlimit) {
-       while (iters > 0 && SvCUR(TOPs) == 0)
+       while (iters > 0 && (!TOPs || !SvANY(TOPs) || SvCUR(TOPs) == 0))
            iters--, SP--;
     }
     if (realarray) {