AIX patch for hints/aix.sh:
[p5sagit/p5-mst-13.2.git] / pp.c
diff --git a/pp.c b/pp.c
index 6423e27..8fbe61d 100644 (file)
--- a/pp.c
+++ b/pp.c
 #include "perl.h"
 
 /*
+ * The compiler on Concurrent CX/UX systems has a subtle bug which only
+ * seems to show up when compiling pp.c - it generates the wrong double
+ * precision constant value for (double)UV_MAX when used inline in the body
+ * of the code below, so this makes a static variable up front (which the
+ * compiler seems to get correct) and uses it in place of UV_MAX below.
+ */
+#ifdef CXUX_BROKEN_CONSTANT_CONVERT
+static double UV_MAX_cxux = ((double)UV_MAX);
+#endif  
+
+/*
  * Types used in bitwise operations.
  *
  * Normally we'd just use IV and UV.  However, some hardware and
@@ -36,9 +47,9 @@ typedef unsigned UBW;
  * in a double without loss; that is, it has no 32-bit type.
  */
 #if BYTEORDER > 0xFFFF && defined(_CRAY) && !defined(_CRAYMPP)
-#  define BWBITS  32
-#  define BWMASK  ((1 << BWBITS) - 1)
-#  define BWSIGN  (1 << (BWBITS - 1))
+#  define BW_BITS  32
+#  define BW_MASK  ((1 << BW_BITS) - 1)
+#  define BW_SIGN  (1 << (BW_BITS - 1))
 #  define BWi(i)  (((i) & BW_SIGN) ? ((i) | ~BW_MASK) : ((i) & BW_MASK))
 #  define BWu(u)  ((u) & BW_MASK)
 #else
@@ -94,9 +105,17 @@ 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);
+#endif
+
 PP(pp_stub)
 {
-    dSP;
+    djSP;
     if (GIMME_V == G_SCALAR)
        XPUSHs(&sv_undef);
     RETURN;
@@ -111,7 +130,7 @@ PP(pp_scalar)
 
 PP(pp_padav)
 {
-    dSP; dTARGET;
+    djSP; dTARGET;
     if (op->op_private & OPpLVAL_INTRO)
        SAVECLEARSV(curpad[op->op_targ]);
     EXTEND(SP, 1);
@@ -136,7 +155,7 @@ PP(pp_padav)
 
 PP(pp_padhv)
 {
-    dSP; dTARGET;
+    djSP; dTARGET;
     I32 gimme;
 
     XPUSHs(TARG);
@@ -150,11 +169,9 @@ PP(pp_padhv)
     }
     else if (gimme == G_SCALAR) {
        SV* sv = sv_newmortal();
-       if (HvFILL((HV*)TARG)) {
-           sprintf(buf, "%ld/%ld",
-                   (long)HvFILL((HV*)TARG), (long)HvMAX((HV*)TARG)+1);
-           sv_setpv(sv, buf);
-       }
+       if (HvFILL((HV*)TARG))
+           sv_setpvf(sv, "%ld/%ld",
+                     (long)HvFILL((HV*)TARG), (long)HvMAX((HV*)TARG) + 1);
        else
            sv_setiv(sv, 0);
        SETs(sv);
@@ -171,7 +188,7 @@ PP(pp_padany)
 
 PP(pp_rv2gv)
 {
-    dSP; dTOPss;
+    djSP; dTOPss;
     
     if (SvROK(sv)) {
       wasref:
@@ -180,7 +197,7 @@ PP(pp_rv2gv)
            GV *gv = (GV*) sv_newmortal();
            gv_init(gv, 0, "", 0, 0);
            GvIOp(gv) = (IO *)sv;
-           SvREFCNT_inc(sv);
+           (void)SvREFCNT_inc(sv);
            sv = (SV*) gv;
        } else if (SvTYPE(sv) != SVt_PVGV)
            DIE("Not a GLOB reference");
@@ -216,7 +233,7 @@ PP(pp_rv2gv)
 
 PP(pp_rv2sv)
 {
-    dSP; dTOPss;
+    djSP; dTOPss;
 
     if (SvROK(sv)) {
       wasref:
@@ -265,7 +282,7 @@ PP(pp_rv2sv)
 
 PP(pp_av2arylen)
 {
-    dSP;
+    djSP;
     AV *av = (AV*)TOPs;
     SV *sv = AvARYLEN(av);
     if (!sv) {
@@ -279,7 +296,7 @@ PP(pp_av2arylen)
 
 PP(pp_pos)
 {
-    dSP; dTARGET; dPOPss;
+    djSP; dTARGET; dPOPss;
     
     if (op->op_flags & OPf_MOD) {
        if (SvTYPE(TARG) < SVt_PVLV) {
@@ -308,7 +325,7 @@ PP(pp_pos)
 
 PP(pp_rv2cv)
 {
-    dSP;
+    djSP;
     GV *gv;
     HV *stash;
 
@@ -327,7 +344,7 @@ PP(pp_rv2cv)
 
 PP(pp_prototype)
 {
-    dSP;
+    djSP;
     CV *cv;
     HV *stash;
     GV *gv;
@@ -343,7 +360,7 @@ PP(pp_prototype)
 
 PP(pp_anoncode)
 {
-    dSP;
+    djSP;
     CV* cv = (CV*)curpad[op->op_targ];
     if (CvCLONE(cv))
        cv = (CV*)sv_2mortal((SV*)cv_clone(cv));
@@ -354,14 +371,14 @@ PP(pp_anoncode)
 
 PP(pp_srefgen)
 {
-    dSP;
+    djSP;
     *SP = refto(*SP);
     RETURN;
 } 
 
 PP(pp_refgen)
 {
-    dSP; dMARK;
+    djSP; dMARK;
     if (GIMME != G_ARRAY) {
        MARK[1] = *SP;
        SP = MARK + 1;
@@ -373,8 +390,7 @@ PP(pp_refgen)
 }
 
 static SV*
-refto(sv)
-SV* sv;
+refto(SV *sv)
 {
     SV* rv;
 
@@ -399,7 +415,7 @@ SV* sv;
 
 PP(pp_ref)
 {
-    dSP; dTARGET;
+    djSP; dTARGET;
     SV *sv;
     char *pv;
 
@@ -419,7 +435,7 @@ PP(pp_ref)
 
 PP(pp_bless)
 {
-    dSP;
+    djSP;
     HV *stash;
 
     if (MAXARG == 1)
@@ -431,11 +447,74 @@ PP(pp_bless)
     RETURN;
 }
 
+PP(pp_gelem)
+{
+    GV *gv;
+    SV *sv;
+    SV *ref;
+    char *elem;
+    djSP;
+
+    sv = POPs;
+    elem = SvPV(sv, na);
+    gv = (GV*)POPs;
+    ref = Nullsv;
+    sv = Nullsv;
+    switch (elem ? *elem : '\0')
+    {
+    case 'A':
+       if (strEQ(elem, "ARRAY"))
+           ref = (SV*)GvAV(gv);
+       break;
+    case 'C':
+       if (strEQ(elem, "CODE"))
+           ref = (SV*)GvCVu(gv);
+       break;
+    case 'F':
+       if (strEQ(elem, "FILEHANDLE")) /* XXX deprecate in 5.005 */
+           ref = (SV*)GvIOp(gv);
+       break;
+    case 'G':
+       if (strEQ(elem, "GLOB"))
+           ref = (SV*)gv;
+       break;
+    case 'H':
+       if (strEQ(elem, "HASH"))
+           ref = (SV*)GvHV(gv);
+       break;
+    case 'I':
+       if (strEQ(elem, "IO"))
+           ref = (SV*)GvIOp(gv);
+       break;
+    case 'N':
+       if (strEQ(elem, "NAME"))
+           sv = newSVpv(GvNAME(gv), GvNAMELEN(gv));
+       break;
+    case 'P':
+       if (strEQ(elem, "PACKAGE"))
+           sv = newSVpv(HvNAME(GvSTASH(gv)), 0);
+       break;
+    case 'S':
+       if (strEQ(elem, "SCALAR"))
+           ref = GvSV(gv);
+       break;
+    }
+    if (ref)
+       sv = newRV(ref);
+    if (sv)
+       sv_2mortal(sv);
+    else
+       sv = &sv_undef;
+    XPUSHs(sv);
+    RETURN;
+}
+
 /* Pattern matching */
 
 PP(pp_study)
 {
-    dSP; dPOPss;
+    djSP; dPOPss;
+    register UNOP *unop = cUNOP;
     register unsigned char *s;
     register I32 pos;
     register I32 ch;
@@ -443,6 +522,14 @@ 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;
@@ -497,13 +584,13 @@ PP(pp_study)
 
 PP(pp_trans)
 {
-    dSP; dTARG;
+    djSP; dTARG;
     SV *sv;
 
     if (op->op_flags & OPf_STACKED)
        sv = POPs;
     else {
-       sv = GvSV(defgv);
+       sv = DEFSV;
        EXTEND(SP,1);
     }
     TARG = sv_newmortal();
@@ -515,7 +602,7 @@ PP(pp_trans)
 
 PP(pp_schop)
 {
-    dSP; dTARGET;
+    djSP; dTARGET;
     do_chop(TARG, TOPs);
     SETTARG;
     RETURN;
@@ -523,7 +610,7 @@ PP(pp_schop)
 
 PP(pp_chop)
 {
-    dSP; dMARK; dTARGET;
+    djSP; dMARK; dTARGET;
     while (SP > MARK)
        do_chop(TARG, POPs);
     PUSHTARG;
@@ -532,14 +619,14 @@ PP(pp_chop)
 
 PP(pp_schomp)
 {
-    dSP; dTARGET;
+    djSP; dTARGET;
     SETi(do_chomp(TOPs));
     RETURN;
 }
 
 PP(pp_chomp)
 {
-    dSP; dMARK; dTARGET;
+    djSP; dMARK; dTARGET;
     register I32 count = 0;
     
     while (SP > MARK)
@@ -550,7 +637,7 @@ PP(pp_chomp)
 
 PP(pp_defined)
 {
-    dSP;
+    djSP;
     register SV* sv;
 
     sv = POPs;
@@ -558,11 +645,11 @@ PP(pp_defined)
        RETPUSHNO;
     switch (SvTYPE(sv)) {
     case SVt_PVAV:
-       if (AvMAX(sv) >= 0 || SvRMAGICAL(sv))
+       if (AvMAX(sv) >= 0 || SvGMAGICAL(sv))
            RETPUSHYES;
        break;
     case SVt_PVHV:
-       if (HvARRAY(sv) || SvRMAGICAL(sv))
+       if (HvARRAY(sv) || SvGMAGICAL(sv))
            RETPUSHYES;
        break;
     case SVt_PVCV:
@@ -580,7 +667,7 @@ PP(pp_defined)
 
 PP(pp_undef)
 {
-    dSP;
+    djSP;
     SV *sv;
 
     if (!op->op_private) {
@@ -638,7 +725,7 @@ PP(pp_undef)
 
 PP(pp_predec)
 {
-    dSP;
+    djSP;
     if (SvREADONLY(TOPs) || SvTYPE(TOPs) > SVt_PVLV)
        croak(no_modify);
     if (SvIOK(TOPs) && !SvNOK(TOPs) && !SvPOK(TOPs) &&
@@ -655,7 +742,7 @@ PP(pp_predec)
 
 PP(pp_postinc)
 {
-    dSP; dTARGET;
+    djSP; dTARGET;
     if (SvREADONLY(TOPs) || SvTYPE(TOPs) > SVt_PVLV)
        croak(no_modify);
     sv_setsv(TARG, TOPs);
@@ -676,7 +763,7 @@ PP(pp_postinc)
 
 PP(pp_postdec)
 {
-    dSP; dTARGET;
+    djSP; dTARGET;
     if(SvREADONLY(TOPs) || SvTYPE(TOPs) > SVt_PVLV)
        croak(no_modify);
     sv_setsv(TARG, TOPs);
@@ -697,7 +784,7 @@ PP(pp_postdec)
 
 PP(pp_pow)
 {
-    dSP; dATARGET; tryAMAGICbin(pow,opASSIGN); 
+    djSP; dATARGET; tryAMAGICbin(pow,opASSIGN); 
     {
       dPOPTOPnnrl;
       SETn( pow( left, right) );
@@ -707,7 +794,7 @@ PP(pp_pow)
 
 PP(pp_multiply)
 {
-    dSP; dATARGET; tryAMAGICbin(mult,opASSIGN); 
+    djSP; dATARGET; tryAMAGICbin(mult,opASSIGN); 
     {
       dPOPTOPnnrl;
       SETn( left * right );
@@ -717,7 +804,7 @@ PP(pp_multiply)
 
 PP(pp_divide)
 {
-    dSP; dATARGET; tryAMAGICbin(div,opASSIGN); 
+    djSP; dATARGET; tryAMAGICbin(div,opASSIGN); 
     {
       dPOPPOPnnrl;
       double value;
@@ -745,7 +832,7 @@ PP(pp_divide)
 
 PP(pp_modulo)
 {
-    dSP; dATARGET; tryAMAGICbin(mod,opASSIGN);
+    djSP; dATARGET; tryAMAGICbin(mod,opASSIGN);
     {
       UV left;
       UV right;
@@ -778,8 +865,10 @@ PP(pp_modulo)
       if ((left_neg != right_neg) && ans)
        ans = right - ans;
       if (right_neg) {
-       if (ans <= -(UV)IV_MAX)
-         sv_setiv(TARG, (IV) -ans);
+       /* XXX may warn: unary minus operator applied to unsigned type */
+       /* could change -foo to be (~foo)+1 instead     */
+       if (ans <= ~((UV)IV_MAX)+1)
+         sv_setiv(TARG, ~ans+1);
        else
          sv_setnv(TARG, -(double)ans);
       }
@@ -792,7 +881,7 @@ PP(pp_modulo)
 
 PP(pp_repeat)
 {
-  dSP; dATARGET; tryAMAGICbin(repeat,opASSIGN);
+  djSP; dATARGET; tryAMAGICbin(repeat,opASSIGN);
   {
     register I32 count = POPi;
     if (GIMME == G_ARRAY && op->op_private & OPpREPEAT_DOLIST) {
@@ -848,7 +937,7 @@ PP(pp_repeat)
 
 PP(pp_subtract)
 {
-    dSP; dATARGET; tryAMAGICbin(subtr,opASSIGN); 
+    djSP; dATARGET; tryAMAGICbin(subtr,opASSIGN); 
     {
       dPOPTOPnnrl_ul;
       SETn( left - right );
@@ -858,12 +947,12 @@ PP(pp_subtract)
 
 PP(pp_left_shift)
 {
-    dSP; dATARGET; tryAMAGICbin(lshift,opASSIGN); 
+    djSP; dATARGET; tryAMAGICbin(lshift,opASSIGN); 
     {
       IBW shift = POPi;
       if (op->op_private & HINT_INTEGER) {
        IBW i = TOPi;
-       i <<= shift;
+       i = BWi(i) << shift;
        SETi(BWi(i));
       }
       else {
@@ -877,12 +966,12 @@ PP(pp_left_shift)
 
 PP(pp_right_shift)
 {
-    dSP; dATARGET; tryAMAGICbin(rshift,opASSIGN); 
+    djSP; dATARGET; tryAMAGICbin(rshift,opASSIGN); 
     {
       IBW shift = POPi;
       if (op->op_private & HINT_INTEGER) {
        IBW i = TOPi;
-       i >>= shift;
+       i = BWi(i) >> shift;
        SETi(BWi(i));
       }
       else {
@@ -896,7 +985,7 @@ PP(pp_right_shift)
 
 PP(pp_lt)
 {
-    dSP; tryAMAGICbinSET(lt,0); 
+    djSP; tryAMAGICbinSET(lt,0); 
     {
       dPOPnv;
       SETs(boolSV(TOPn < value));
@@ -906,7 +995,7 @@ PP(pp_lt)
 
 PP(pp_gt)
 {
-    dSP; tryAMAGICbinSET(gt,0); 
+    djSP; tryAMAGICbinSET(gt,0); 
     {
       dPOPnv;
       SETs(boolSV(TOPn > value));
@@ -916,7 +1005,7 @@ PP(pp_gt)
 
 PP(pp_le)
 {
-    dSP; tryAMAGICbinSET(le,0); 
+    djSP; tryAMAGICbinSET(le,0); 
     {
       dPOPnv;
       SETs(boolSV(TOPn <= value));
@@ -926,7 +1015,7 @@ PP(pp_le)
 
 PP(pp_ge)
 {
-    dSP; tryAMAGICbinSET(ge,0); 
+    djSP; tryAMAGICbinSET(ge,0); 
     {
       dPOPnv;
       SETs(boolSV(TOPn >= value));
@@ -936,7 +1025,7 @@ PP(pp_ge)
 
 PP(pp_ne)
 {
-    dSP; tryAMAGICbinSET(ne,0); 
+    djSP; tryAMAGICbinSET(ne,0); 
     {
       dPOPnv;
       SETs(boolSV(TOPn != value));
@@ -946,7 +1035,7 @@ PP(pp_ne)
 
 PP(pp_ncmp)
 {
-    dSP; dTARGET; tryAMAGICbin(ncmp,0); 
+    djSP; dTARGET; tryAMAGICbin(ncmp,0); 
     {
       dPOPTOPnnrl;
       I32 value;
@@ -968,7 +1057,7 @@ PP(pp_ncmp)
 
 PP(pp_slt)
 {
-    dSP; tryAMAGICbinSET(slt,0); 
+    djSP; tryAMAGICbinSET(slt,0); 
     {
       dPOPTOPssrl;
       int cmp = ((op->op_private & OPpLOCALE)
@@ -981,7 +1070,7 @@ PP(pp_slt)
 
 PP(pp_sgt)
 {
-    dSP; tryAMAGICbinSET(sgt,0); 
+    djSP; tryAMAGICbinSET(sgt,0); 
     {
       dPOPTOPssrl;
       int cmp = ((op->op_private & OPpLOCALE)
@@ -994,7 +1083,7 @@ PP(pp_sgt)
 
 PP(pp_sle)
 {
-    dSP; tryAMAGICbinSET(sle,0); 
+    djSP; tryAMAGICbinSET(sle,0); 
     {
       dPOPTOPssrl;
       int cmp = ((op->op_private & OPpLOCALE)
@@ -1007,7 +1096,7 @@ PP(pp_sle)
 
 PP(pp_sge)
 {
-    dSP; tryAMAGICbinSET(sge,0); 
+    djSP; tryAMAGICbinSET(sge,0); 
     {
       dPOPTOPssrl;
       int cmp = ((op->op_private & OPpLOCALE)
@@ -1020,7 +1109,7 @@ PP(pp_sge)
 
 PP(pp_seq)
 {
-    dSP; tryAMAGICbinSET(seq,0); 
+    djSP; tryAMAGICbinSET(seq,0); 
     {
       dPOPTOPssrl;
       SETs(boolSV(sv_eq(left, right)));
@@ -1030,7 +1119,7 @@ PP(pp_seq)
 
 PP(pp_sne)
 {
-    dSP; tryAMAGICbinSET(sne,0); 
+    djSP; tryAMAGICbinSET(sne,0); 
     {
       dPOPTOPssrl;
       SETs(boolSV(!sv_eq(left, right)));
@@ -1040,7 +1129,7 @@ PP(pp_sne)
 
 PP(pp_scmp)
 {
-    dSP; dTARGET;  tryAMAGICbin(scmp,0);
+    djSP; dTARGET;  tryAMAGICbin(scmp,0);
     {
       dPOPTOPssrl;
       int cmp = ((op->op_private & OPpLOCALE)
@@ -1053,7 +1142,7 @@ PP(pp_scmp)
 
 PP(pp_bit_and)
 {
-    dSP; dATARGET; tryAMAGICbin(band,opASSIGN); 
+    djSP; dATARGET; tryAMAGICbin(band,opASSIGN); 
     {
       dPOPTOPssrl;
       if (SvNIOKp(left) || SvNIOKp(right)) {
@@ -1076,7 +1165,7 @@ PP(pp_bit_and)
 
 PP(pp_bit_xor)
 {
-    dSP; dATARGET; tryAMAGICbin(bxor,opASSIGN); 
+    djSP; dATARGET; tryAMAGICbin(bxor,opASSIGN); 
     {
       dPOPTOPssrl;
       if (SvNIOKp(left) || SvNIOKp(right)) {
@@ -1099,7 +1188,7 @@ PP(pp_bit_xor)
 
 PP(pp_bit_or)
 {
-    dSP; dATARGET; tryAMAGICbin(bor,opASSIGN); 
+    djSP; dATARGET; tryAMAGICbin(bor,opASSIGN); 
     {
       dPOPTOPssrl;
       if (SvNIOKp(left) || SvNIOKp(right)) {
@@ -1122,7 +1211,7 @@ PP(pp_bit_or)
 
 PP(pp_negate)
 {
-    dSP; dTARGET; tryAMAGICun(neg);
+    djSP; dTARGET; tryAMAGICun(neg);
     {
        dTOPss;
        if (SvGMAGICAL(sv))
@@ -1155,7 +1244,7 @@ PP(pp_negate)
 PP(pp_not)
 {
 #ifdef OVERLOAD
-    dSP; tryAMAGICunSET(not);
+    djSP; tryAMAGICunSET(not);
 #endif /* OVERLOAD */
     *stack_sp = boolSV(!SvTRUE(*stack_sp));
     return NORMAL;
@@ -1163,7 +1252,7 @@ PP(pp_not)
 
 PP(pp_complement)
 {
-    dSP; dTARGET; tryAMAGICun(compl); 
+    djSP; dTARGET; tryAMAGICun(compl); 
     {
       dTOPss;
       if (SvNIOKp(sv)) {
@@ -1206,7 +1295,7 @@ PP(pp_complement)
 
 PP(pp_i_multiply)
 {
-    dSP; dATARGET; tryAMAGICbin(mult,opASSIGN); 
+    djSP; dATARGET; tryAMAGICbin(mult,opASSIGN); 
     {
       dPOPTOPiirl;
       SETi( left * right );
@@ -1216,7 +1305,7 @@ PP(pp_i_multiply)
 
 PP(pp_i_divide)
 {
-    dSP; dATARGET; tryAMAGICbin(div,opASSIGN); 
+    djSP; dATARGET; tryAMAGICbin(div,opASSIGN); 
     {
       dPOPiv;
       if (value == 0)
@@ -1229,7 +1318,7 @@ PP(pp_i_divide)
 
 PP(pp_i_modulo)
 {
-    dSP; dATARGET; tryAMAGICbin(mod,opASSIGN); 
+    djSP; dATARGET; tryAMAGICbin(mod,opASSIGN); 
     {
       dPOPTOPiirl;
       if (!right)
@@ -1241,7 +1330,7 @@ PP(pp_i_modulo)
 
 PP(pp_i_add)
 {
-    dSP; dATARGET; tryAMAGICbin(add,opASSIGN); 
+    djSP; dATARGET; tryAMAGICbin(add,opASSIGN); 
     {
       dPOPTOPiirl;
       SETi( left + right );
@@ -1251,7 +1340,7 @@ PP(pp_i_add)
 
 PP(pp_i_subtract)
 {
-    dSP; dATARGET; tryAMAGICbin(subtr,opASSIGN); 
+    djSP; dATARGET; tryAMAGICbin(subtr,opASSIGN); 
     {
       dPOPTOPiirl;
       SETi( left - right );
@@ -1261,7 +1350,7 @@ PP(pp_i_subtract)
 
 PP(pp_i_lt)
 {
-    dSP; tryAMAGICbinSET(lt,0); 
+    djSP; tryAMAGICbinSET(lt,0); 
     {
       dPOPTOPiirl;
       SETs(boolSV(left < right));
@@ -1271,7 +1360,7 @@ PP(pp_i_lt)
 
 PP(pp_i_gt)
 {
-    dSP; tryAMAGICbinSET(gt,0); 
+    djSP; tryAMAGICbinSET(gt,0); 
     {
       dPOPTOPiirl;
       SETs(boolSV(left > right));
@@ -1281,7 +1370,7 @@ PP(pp_i_gt)
 
 PP(pp_i_le)
 {
-    dSP; tryAMAGICbinSET(le,0); 
+    djSP; tryAMAGICbinSET(le,0); 
     {
       dPOPTOPiirl;
       SETs(boolSV(left <= right));
@@ -1291,7 +1380,7 @@ PP(pp_i_le)
 
 PP(pp_i_ge)
 {
-    dSP; tryAMAGICbinSET(ge,0); 
+    djSP; tryAMAGICbinSET(ge,0); 
     {
       dPOPTOPiirl;
       SETs(boolSV(left >= right));
@@ -1301,7 +1390,7 @@ PP(pp_i_ge)
 
 PP(pp_i_eq)
 {
-    dSP; tryAMAGICbinSET(eq,0); 
+    djSP; tryAMAGICbinSET(eq,0); 
     {
       dPOPTOPiirl;
       SETs(boolSV(left == right));
@@ -1311,7 +1400,7 @@ PP(pp_i_eq)
 
 PP(pp_i_ne)
 {
-    dSP; tryAMAGICbinSET(ne,0); 
+    djSP; tryAMAGICbinSET(ne,0); 
     {
       dPOPTOPiirl;
       SETs(boolSV(left != right));
@@ -1321,7 +1410,7 @@ PP(pp_i_ne)
 
 PP(pp_i_ncmp)
 {
-    dSP; dTARGET; tryAMAGICbin(ncmp,0); 
+    djSP; dTARGET; tryAMAGICbin(ncmp,0); 
     {
       dPOPTOPiirl;
       I32 value;
@@ -1339,7 +1428,7 @@ PP(pp_i_ncmp)
 
 PP(pp_i_negate)
 {
-    dSP; dTARGET; tryAMAGICun(neg);
+    djSP; dTARGET; tryAMAGICun(neg);
     SETi(-TOPi);
     RETURN;
 }
@@ -1348,7 +1437,7 @@ PP(pp_i_negate)
 
 PP(pp_atan2)
 {
-    dSP; dTARGET; tryAMAGICbin(atan2,0); 
+    djSP; dTARGET; tryAMAGICbin(atan2,0); 
     {
       dPOPTOPnnrl;
       SETn(atan2(left, right));
@@ -1358,7 +1447,7 @@ PP(pp_atan2)
 
 PP(pp_sin)
 {
-    dSP; dTARGET; tryAMAGICun(sin);
+    djSP; dTARGET; tryAMAGICun(sin);
     {
       double value;
       value = POPn;
@@ -1370,7 +1459,7 @@ PP(pp_sin)
 
 PP(pp_cos)
 {
-    dSP; dTARGET; tryAMAGICun(cos);
+    djSP; dTARGET; tryAMAGICun(cos);
     {
       double value;
       value = POPn;
@@ -1382,7 +1471,7 @@ PP(pp_cos)
 
 PP(pp_rand)
 {
-    dSP; dTARGET;
+    djSP; dTARGET;
     double value;
     if (MAXARG < 1)
        value = 1.0;
@@ -1413,7 +1502,7 @@ PP(pp_rand)
 
 PP(pp_srand)
 {
-    dSP;
+    djSP;
     UV anum;
     if (MAXARG < 1)
        anum = seed();
@@ -1426,7 +1515,7 @@ PP(pp_srand)
 }
 
 static U32
-seed()
+seed(void)
 {
     /*
      * This is really just a quick hack which grabs various garbage
@@ -1450,6 +1539,7 @@ seed()
 #define   SEED_C3      269
 #define   SEED_C5      26107
 
+    dTHR;
     U32 u;
 #ifdef VMS
 #  include <starlet.h>
@@ -1479,7 +1569,7 @@ seed()
 
 PP(pp_exp)
 {
-    dSP; dTARGET; tryAMAGICun(exp);
+    djSP; dTARGET; tryAMAGICun(exp);
     {
       double value;
       value = POPn;
@@ -1491,7 +1581,7 @@ PP(pp_exp)
 
 PP(pp_log)
 {
-    dSP; dTARGET; tryAMAGICun(log);
+    djSP; dTARGET; tryAMAGICun(log);
     {
       double value;
       value = POPn;
@@ -1507,7 +1597,7 @@ PP(pp_log)
 
 PP(pp_sqrt)
 {
-    dSP; dTARGET; tryAMAGICun(sqrt);
+    djSP; dTARGET; tryAMAGICun(sqrt);
     {
       double value;
       value = POPn;
@@ -1523,7 +1613,7 @@ PP(pp_sqrt)
 
 PP(pp_int)
 {
-    dSP; dTARGET;
+    djSP; dTARGET;
     {
       double value = TOPn;
       IV iv;
@@ -1551,7 +1641,7 @@ PP(pp_int)
 
 PP(pp_abs)
 {
-    dSP; dTARGET; tryAMAGICun(abs);
+    djSP; dTARGET; tryAMAGICun(abs);
     {
       double value = TOPn;
       IV iv;
@@ -1573,7 +1663,7 @@ PP(pp_abs)
 
 PP(pp_hex)
 {
-    dSP; dTARGET;
+    djSP; dTARGET;
     char *tmps;
     I32 argtype;
 
@@ -1584,7 +1674,7 @@ PP(pp_hex)
 
 PP(pp_oct)
 {
-    dSP; dTARGET;
+    djSP; dTARGET;
     UV value;
     I32 argtype;
     char *tmps;
@@ -1606,50 +1696,69 @@ PP(pp_oct)
 
 PP(pp_length)
 {
-    dSP; dTARGET;
+    djSP; dTARGET;
     SETi( sv_len(TOPs) );
     RETURN;
 }
 
 PP(pp_substr)
 {
-    dSP; dTARGET;
+    djSP; dTARGET;
     SV *sv;
     I32 len;
     STRLEN curlen;
     I32 pos;
     I32 rem;
+    I32 fail;
     I32 lvalue = op->op_flags & OPf_MOD;
     char *tmps;
     I32 arybase = curcop->cop_arybase;
 
     if (MAXARG > 2)
        len = POPi;
-    pos = POPi - arybase;
+    pos = POPi;
     sv = POPs;
     tmps = SvPV(sv, curlen);
-    if (pos < 0) {
-       pos += curlen + arybase;
-       if (pos < 0 && MAXARG < 3)
-           pos = 0;
+    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 (pos < 0 || pos > curlen) {
-       if (dowarn || lvalue)
+    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;
+    }
+    if (fail < 0) {
+       if (dowarn || lvalue) 
            warn("substr outside of string");
        RETPUSHUNDEF;
     }
     else {
-       if (MAXARG < 3)
-           len = curlen;
-       else if (len < 0) {
-           len += curlen - pos;
-           if (len < 0)
-               len = 0;
-       }
        tmps += pos;
-       rem = curlen - pos;     /* rem=how many bytes left*/
-       if (rem > len)
-           rem = len;
        sv_setpvn(TARG, tmps, rem);
        if (lvalue) {                   /* it's an lvalue! */
            if (!SvGMAGICAL(sv)) {
@@ -1681,7 +1790,7 @@ PP(pp_substr)
 
 PP(pp_vec)
 {
-    dSP; dTARGET;
+    djSP; dTARGET;
     register I32 size = POPi;
     register I32 offset = POPi;
     register SV *src = POPs;
@@ -1755,7 +1864,7 @@ PP(pp_vec)
 
 PP(pp_index)
 {
-    dSP; dTARGET;
+    djSP; dTARGET;
     SV *big;
     SV *little;
     I32 offset;
@@ -1787,7 +1896,7 @@ PP(pp_index)
 
 PP(pp_rindex)
 {
-    dSP; dTARGET;
+    djSP; dTARGET;
     SV *big;
     SV *little;
     STRLEN blen;
@@ -1824,7 +1933,7 @@ PP(pp_rindex)
 
 PP(pp_sprintf)
 {
-    dSP; dMARK; dORIGMARK; dTARGET;
+    djSP; dMARK; dORIGMARK; dTARGET;
 #ifdef USE_LOCALE_NUMERIC
     if (op->op_private & OPpLOCALE)
        SET_NUMERIC_LOCAL();
@@ -1840,7 +1949,7 @@ PP(pp_sprintf)
 
 PP(pp_ord)
 {
-    dSP; dTARGET;
+    djSP; dTARGET;
     I32 value;
     char *tmps;
 
@@ -1859,7 +1968,7 @@ PP(pp_ord)
 
 PP(pp_chr)
 {
-    dSP; dTARGET;
+    djSP; dTARGET;
     char *tmps;
 
     (void)SvUPGRADE(TARG,SVt_PV);
@@ -1875,7 +1984,7 @@ PP(pp_chr)
 
 PP(pp_crypt)
 {
-    dSP; dTARGET; dPOPTOPssrl;
+    djSP; dTARGET; dPOPTOPssrl;
 #ifdef HAS_CRYPT
     char *tmps = SvPV(left, na);
 #ifdef FCRYPT
@@ -1893,7 +2002,7 @@ PP(pp_crypt)
 
 PP(pp_ucfirst)
 {
-    dSP;
+    djSP;
     SV *sv = TOPs;
     register char *s;
 
@@ -1919,7 +2028,7 @@ PP(pp_ucfirst)
 
 PP(pp_lcfirst)
 {
-    dSP;
+    djSP;
     SV *sv = TOPs;
     register char *s;
 
@@ -1946,7 +2055,7 @@ PP(pp_lcfirst)
 
 PP(pp_uc)
 {
-    dSP;
+    djSP;
     SV *sv = TOPs;
     register char *s;
     STRLEN len;
@@ -1978,7 +2087,7 @@ PP(pp_uc)
 
 PP(pp_lc)
 {
-    dSP;
+    djSP;
     SV *sv = TOPs;
     register char *s;
     STRLEN len;
@@ -2010,7 +2119,7 @@ PP(pp_lc)
 
 PP(pp_quotemeta)
 {
-    dSP; dTARGET;
+    djSP; dTARGET;
     SV *sv = TOPs;
     STRLEN len;
     register char *s = SvPV(sv,len);
@@ -2039,7 +2148,7 @@ PP(pp_quotemeta)
 
 PP(pp_aslice)
 {
-    dSP; dMARK; dORIGMARK;
+    djSP; dMARK; dORIGMARK;
     register SV** svp;
     register AV* av = (AV*)POPs;
     register I32 lval = op->op_flags & OPf_MOD;
@@ -2084,13 +2193,15 @@ PP(pp_aslice)
 
 PP(pp_each)
 {
-    dSP; dTARGET;
+    djSP; dTARGET;
     HV *hash = (HV*)POPs;
     HE *entry;
     I32 gimme = GIMME_V;
+    I32 realhv = (SvTYPE(hash) == SVt_PVHV);
     
     PUTBACK;
-    entry = hv_iternext(hash);         /* might clobber stack_sp */
+    /* might clobber stack_sp */
+    entry = realhv ? hv_iternext(hash) : avhv_iternext((AV*)hash);
     SPAGAIN;
 
     EXTEND(SP, 2);
@@ -2098,7 +2209,9 @@ PP(pp_each)
        PUSHs(hv_iterkeysv(entry));     /* won't clobber stack_sp */
        if (gimme == G_ARRAY) {
            PUTBACK;
-           sv_setsv(TARG, hv_iterval(hash, entry));  /* might hit stack_sp */
+           /* might clobber stack_sp */
+           sv_setsv(TARG, realhv ?
+                    hv_iterval(hash, entry) : avhv_iterval((AV*)hash, entry));
            SPAGAIN;
            PUSHs(TARG);
        }
@@ -2121,7 +2234,7 @@ PP(pp_keys)
 
 PP(pp_delete)
 {
-    dSP;
+    djSP;
     I32 gimme = GIMME_V;
     I32 discard = (gimme == G_VOID) ? G_DISCARD : 0;
     SV *sv;
@@ -2129,11 +2242,16 @@ PP(pp_delete)
 
     if (op->op_private & OPpSLICE) {
        dMARK; dORIGMARK;
+       U32 hvtype;
        hv = (HV*)POPs;
-       if (SvTYPE(hv) != SVt_PVHV)
-           DIE("Not a HASH reference");
+       hvtype = SvTYPE(hv);
        while (++MARK <= SP) {
-           sv = hv_delete_ent(hv, *MARK, discard, 0);
+           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;
        }
        if (discard)
@@ -2147,9 +2265,12 @@ PP(pp_delete)
     else {
        SV *keysv = POPs;
        hv = (HV*)POPs;
-       if (SvTYPE(hv) != SVt_PVHV)
+       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");
-       sv = hv_delete_ent(hv, keysv, discard, 0);
        if (!sv)
            sv = &sv_undef;
        if (!discard)
@@ -2160,30 +2281,39 @@ PP(pp_delete)
 
 PP(pp_exists)
 {
-    dSP;
+    djSP;
     SV *tmpsv = POPs;
     HV *hv = (HV*)POPs;
-    STRLEN len;
-    if (SvTYPE(hv) != SVt_PVHV) {
+    if (SvTYPE(hv) == SVt_PVHV) {
+       if (hv_exists_ent(hv, tmpsv, 0))
+           RETPUSHYES;
+    } else if (SvTYPE(hv) == SVt_PVAV) {
+       if (avhv_exists_ent((AV*)hv, tmpsv, 0))
+           RETPUSHYES;
+    } else {
        DIE("Not a HASH reference");
     }
-    if (hv_exists_ent(hv, tmpsv, 0))
-       RETPUSHYES;
     RETPUSHNO;
 }
 
 PP(pp_hslice)
 {
-    dSP; dMARK; dORIGMARK;
+    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);
 
-    if (SvTYPE(hv) == SVt_PVHV) {
+    if (realhv || SvTYPE(hv) == SVt_PVAV) {
        while (++MARK <= SP) {
            SV *keysv = *MARK;
-
-           he = hv_fetch_ent(hv, keysv, lval, 0);
+           SV **svp;
+           if (realhv) {
+               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)
                    DIE(no_helem, SvPV(keysv, na));
@@ -2205,7 +2335,7 @@ PP(pp_hslice)
 
 PP(pp_list)
 {
-    dSP; dMARK;
+    djSP; dMARK;
     if (GIMME != G_ARRAY) {
        if (++MARK <= SP)
            *MARK = *SP;                /* unwanted list, return last item */
@@ -2218,7 +2348,7 @@ PP(pp_list)
 
 PP(pp_lslice)
 {
-    dSP;
+    djSP;
     SV **lastrelem = stack_sp;
     SV **lastlelem = stack_base + POPMARK;
     SV **firstlelem = stack_base + POPMARK + 1;
@@ -2276,7 +2406,7 @@ PP(pp_lslice)
 
 PP(pp_anonlist)
 {
-    dSP; dMARK; dORIGMARK;
+    djSP; dMARK; dORIGMARK;
     I32 items = SP - MARK;
     SV *av = sv_2mortal((SV*)av_make(items, MARK+1));
     SP = ORIGMARK;             /* av_make() might realloc stack_sp */
@@ -2286,7 +2416,7 @@ PP(pp_anonlist)
 
 PP(pp_anonhash)
 {
-    dSP; dMARK; dORIGMARK;
+    djSP; dMARK; dORIGMARK;
     HV* hv = (HV*)sv_2mortal((SV*)newHV());
 
     while (MARK < SP) {
@@ -2294,7 +2424,7 @@ PP(pp_anonhash)
        SV *val = NEWSV(46, 0);
        if (MARK < SP)
            sv_setsv(val, *++MARK);
-       else
+       else if (dowarn)
            warn("Odd number of elements in hash list");
        (void)hv_store_ent(hv,key,val,0);
     }
@@ -2305,7 +2435,7 @@ PP(pp_anonhash)
 
 PP(pp_splice)
 {
-    dSP; dMARK; dORIGMARK;
+    djSP; dMARK; dORIGMARK;
     register AV *ary = (AV*)*++MARK;
     register SV **src;
     register SV **dst;
@@ -2320,11 +2450,13 @@ PP(pp_splice)
     SP++;
 
     if (++MARK < SP) {
-       offset = SvIVx(*MARK);
+       offset = i = SvIVx(*MARK);
        if (offset < 0)
            offset += AvFILL(ary) + 1;
        else
            offset -= curcop->cop_arybase;
+       if (offset < 0)
+           DIE(no_aelem, i);
        if (++MARK < SP) {
            length = SvIVx(*MARK++);
            if (length < 0)
@@ -2337,12 +2469,6 @@ PP(pp_splice)
        offset = 0;
        length = AvMAX(ary) + 1;
     }
-    if (offset < 0) {
-       length += offset;
-       offset = 0;
-       if (length < 0)
-           length = 0;
-    }
     if (offset > AvFILL(ary) + 1)
        offset = AvFILL(ary) + 1;
     after = AvFILL(ary) + 1 - (offset + length);
@@ -2357,6 +2483,12 @@ PP(pp_splice)
 
     newlen = SP - MARK;
     diff = newlen - length;
+    if (newlen && !AvREAL(ary)) {
+       if (AvREIFY(ary))
+           av_reify(ary);
+       else
+           assert(AvREAL(ary));                /* would leak, so croak */
+    }
 
     if (diff < 0) {                            /* shrinking the area */
        if (newlen) {
@@ -2498,7 +2630,7 @@ PP(pp_splice)
 
 PP(pp_push)
 {
-    dSP; dMARK; dORIGMARK; dTARGET;
+    djSP; dMARK; dORIGMARK; dTARGET;
     register AV *ary = (AV*)*++MARK;
     register SV *sv = &sv_undef;
 
@@ -2515,7 +2647,7 @@ PP(pp_push)
 
 PP(pp_pop)
 {
-    dSP;
+    djSP;
     AV *av = (AV*)POPs;
     SV *sv = av_pop(av);
     if (!SvIMMORTAL(sv) && AvREAL(av))
@@ -2526,7 +2658,7 @@ PP(pp_pop)
 
 PP(pp_shift)
 {
-    dSP;
+    djSP;
     AV *av = (AV*)POPs;
     SV *sv = av_shift(av);
     EXTEND(SP, 1);
@@ -2540,7 +2672,7 @@ PP(pp_shift)
 
 PP(pp_unshift)
 {
-    dSP; dMARK; dORIGMARK; dTARGET;
+    djSP; dMARK; dORIGMARK; dTARGET;
     register AV *ary = (AV*)*++MARK;
     register SV *sv;
     register I32 i = 0;
@@ -2559,7 +2691,7 @@ PP(pp_unshift)
 
 PP(pp_reverse)
 {
-    dSP; dMARK;
+    djSP; dMARK;
     register SV *tmp;
     SV **oldsp = SP;
 
@@ -2582,7 +2714,7 @@ PP(pp_reverse)
        if (SP - MARK > 1)
            do_join(TARG, &sv_no, MARK, SP);
        else
-           sv_setsv(TARG, (SP > MARK) ? *SP : GvSV(defgv));
+           sv_setsv(TARG, (SP > MARK) ? *SP : DEFSV);
        up = SvPV_force(TARG, len);
        if (len > 1) {
            down = SvPVX(TARG) + len - 1;
@@ -2600,9 +2732,7 @@ PP(pp_reverse)
 }
 
 static SV      *
-mul128(sv, m)
-     SV             *sv;
-     U8              m;
+mul128(SV *sv, U8 m)
 {
   STRLEN          len;
   char           *s = SvPV(sv, len);
@@ -2610,11 +2740,11 @@ mul128(sv, m)
   U32             i = 0;
 
   if (!strnEQ(s, "0000", 4)) {  /* need to grow sv */
-    SV             *new = newSVpv("0000000000", 10);
+    SV             *New = newSVpv("0000000000", 10);
 
-    sv_catsv(new, sv);
+    sv_catsv(New, sv);
     SvREFCNT_dec(sv);          /* free old sv */
-    sv = new;
+    sv = New;
     s = SvPV(sv, len);
   }
   t = s + len - 1;
@@ -2632,7 +2762,7 @@ mul128(sv, m)
 
 PP(pp_unpack)
 {
-    dSP;
+    djSP;
     dPOPPOPssrl;
     SV **oldsp = sp;
     I32 gimme = GIMME_V;
@@ -2668,6 +2798,7 @@ PP(pp_unpack)
     register U32 culong;
     double cdouble;
     static char* bitcount = 0;
+    int commas = 0;
 
     if (gimme != G_ARRAY) {            /* arrange to do first one only */
        /*SUPPRESS 530*/
@@ -2701,6 +2832,10 @@ PP(pp_unpack)
        switch(datumtype) {
        default:
            croak("Invalid type in unpack: '%c'", (int)datumtype);
+       case ',': /* grandfather in commas but with a warning */
+           if (commas++ == 0 && dowarn)
+               warn("Invalid type in unpack: '%c'", (int)datumtype);
+           break;
        case '%':
            if (len == 1 && pat[-1] != '1')
                len = 16;
@@ -3114,12 +3249,9 @@ PP(pp_unpack)
                        auv = 0;
                    }
                    else if (++bytes >= sizeof(UV)) {   /* promote to string */
-                       char decn[sizeof(UV) * 3 + 1];
                        char *t;
 
-                       (void) sprintf(decn, "%0*ld",
-                                      (int)sizeof(decn) - 1, auv);
-                       sv = newSVpv(decn, 0);
+                       sv = newSVpvf("%.*Vu", (int)TYPE_DIGITS(UV), auv);
                        while (s < strend) {
                            sv = mul128(sv, *s & 0x7f);
                            if (!(*s++ & 0x80)) {
@@ -3268,10 +3400,10 @@ PP(pp_unpack)
                        d = (*s++ - ' ') & 077;
                    else
                        d = 0;
-                   hunk[0] = a << 2 | b >> 4;
-                   hunk[1] = b << 4 | c >> 2;
-                   hunk[2] = c << 6 | d;
-                   sv_catpvn(sv, hunk, len > 3 ? 3 : len);
+                   hunk[0] = (a << 2) | (b >> 4);
+                   hunk[1] = (b << 4) | (c >> 2);
+                   hunk[2] = (c << 6) | d;
+                   sv_catpvn(sv, hunk, (len > 3) ? 3 : len);
                    len -= 3;
                }
                if (*s == '\n')
@@ -3322,10 +3454,7 @@ PP(pp_unpack)
 }
 
 static void
-doencodes(sv, s, len)
-register SV *sv;
-register char *s;
-register I32 len;
+doencodes(register SV *sv, register char *s, register I32 len)
 {
     char hunk[5];
 
@@ -3334,8 +3463,8 @@ register I32 len;
     hunk[4] = '\0';
     while (len > 0) {
        hunk[0] = ' ' + (077 & (*s >> 2));
-       hunk[1] = ' ' + (077 & ((*s << 4) & 060 | (s[1] >> 4) & 017));
-       hunk[2] = ' ' + (077 & ((s[1] << 2) & 074 | (s[2] >> 6) & 03));
+       hunk[1] = ' ' + (077 & (((*s << 4) & 060) | ((s[1] >> 4) & 017)));
+       hunk[2] = ' ' + (077 & (((s[1] << 2) & 074) | ((s[2] >> 6) & 03)));
        hunk[3] = ' ' + (077 & (s[2] & 077));
        sv_catpvn(sv, hunk, 4);
        s += 3;
@@ -3349,9 +3478,7 @@ register I32 len;
 }
 
 static SV      *
-is_an_int(s, l)
-     char           *s;
-     STRLEN          l;
+is_an_int(char *s, STRLEN l)
 {
   SV             *result = newSVpv("", l);
   char           *result_c = SvPV(result, na); /* convenience */
@@ -3399,9 +3526,9 @@ is_an_int(s, l)
 }
 
 static int
-div128(pnum, done)
-     SV             *pnum;                 /* must be '\0' terminated */
-     bool           *done;
+div128(SV *pnum, char *done)
+                                           /* must be '\0' terminated */
+                          
 {
   STRLEN          len;
   char           *s = SvPV(pnum, len);
@@ -3429,7 +3556,7 @@ div128(pnum, done)
 
 PP(pp_pack)
 {
-    dSP; dMARK; dORIGMARK; dTARGET;
+    djSP; dMARK; dORIGMARK; dTARGET;
     register SV *cat = TARG;
     register I32 items;
     STRLEN fromlen;
@@ -3456,6 +3583,7 @@ PP(pp_pack)
     char *aptr;
     float afloat;
     double adouble;
+    int commas = 0;
 
     items = SP - MARK;
     MARK++;
@@ -3479,6 +3607,10 @@ PP(pp_pack)
        switch(datumtype) {
        default:
            croak("Invalid type in pack: '%c'", (int)datumtype);
+       case ',': /* grandfather in commas but with a warning */
+           if (commas++ == 0 && dowarn)
+               warn("Invalid type in pack: '%c'", (int)datumtype);
+           break;
        case '%':
            DIE("%% may only be used in unpack");
        case '@':
@@ -3716,7 +3848,18 @@ PP(pp_pack)
                if (adouble < 0)
                    croak("Cannot compress negative numbers");
 
-               if (adouble <= UV_MAX) {
+               if (
+#ifdef BW_BITS
+                   adouble <= BW_MASK
+#else
+#ifdef CXUX_BROKEN_CONSTANT_CONVERT
+                   adouble <= UV_MAX_cxux
+#else
+                   adouble <= UV_MAX
+#endif
+#endif
+                   )
+               {
                    char   buf[1 + sizeof(UV)];
                    char  *in = buf + sizeof(buf);
                    UV     auv = U_V(adouble);;
@@ -3830,7 +3973,21 @@ PP(pp_pack)
        case 'p':
            while (len-- > 0) {
                fromstr = NEXTFROM;
-               aptr = SvPV_force(fromstr, na); /* XXX Error if TEMP? */
+               if (fromstr == &sv_undef)
+                   aptr = NULL;
+               else {
+                   /* XXX better yet, could spirit away the string to
+                    * a safe spot and hang on to it until the result
+                    * of pack() (and all copies of the result) are
+                    * gone.
+                    */
+                   if (dowarn && (SvTEMP(fromstr) || SvPADTMP(fromstr)))
+                       warn("Attempt to pack pointer to temporary value");
+                   if (SvPOK(fromstr) || SvNIOK(fromstr))
+                       aptr = SvPV(fromstr,na);
+                   else
+                       aptr = SvPV_force(fromstr,na);
+               }
                sv_catpvn(cat, (char*)&aptr, sizeof(char*));
            }
            break;
@@ -3865,7 +4022,7 @@ PP(pp_pack)
 
 PP(pp_split)
 {
-    dSP; dTARG;
+    djSP; dTARG;
     AV *ary;
     register I32 limit = POPi;                 /* note, negative is forever */
     SV *sv = POPs;
@@ -3902,7 +4059,11 @@ PP(pp_split)
     if (pm->op_pmreplroot)
        ary = GvAVn((GV*)pm->op_pmreplroot);
     else if (gimme != G_ARRAY)
+#ifdef USE_THREADS
+       ary = (AV*)curpad[0];
+#else
        ary = GvAVn(defgv);
+#endif /* USE_THREADS */
     else
        ary = Nullav;
     if (ary && (gimme != G_ARRAY || (pm->op_pmflags & PMf_ONCE))) {
@@ -3974,10 +4135,12 @@ PP(pp_split)
            s = m;
        }
     }
-    else if (pm->op_pmshort && !rx->nparens) {
-       i = SvCUR(pm->op_pmshort);
-       if (i == 1) {
-           i = *SvPVX(pm->op_pmshort);
+    else if (rx->check_substr && !rx->nparens 
+            && (rx->reganch & ROPT_CHECK_ALL)
+            && !(rx->reganch & ROPT_ANCH)) {
+       i = SvCUR(rx->check_substr);
+       if (i == 1 && !SvTAIL(rx->check_substr)) {
+           i = *SvPVX(rx->check_substr);
            while (--limit) {
                /*SUPPRESS 530*/
                for (m = s; m < strend && *m != i; m++) ;
@@ -3995,7 +4158,7 @@ PP(pp_split)
 #ifndef lint
            while (s < strend && --limit &&
              (m=fbm_instr((unsigned char*)s, (unsigned char*)strend,
-                   pm->op_pmshort)) )
+                   rx->check_substr)) )
 #endif
            {
                dstr = NEWSV(31, m-s);
@@ -4010,9 +4173,9 @@ PP(pp_split)
     else {
        maxiters += (strend - s) * rx->nparens;
        while (s < strend && --limit &&
-              pregexec(rx, s, strend, orig, 1, Nullsv, TRUE))
+              regexec_flags(rx, s, strend, orig, 1, Nullsv, NULL, 0))
        {
-           TAINT_IF(rx->exec_tainted);
+           TAINT_IF(RX_MATCH_TAINTED(rx));
            if (rx->subbase
              && rx->subbase != orig) {
                m = s;
@@ -4065,6 +4228,11 @@ PP(pp_split)
     }
     if (realarray) {
        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*);
@@ -4084,3 +4252,71 @@ PP(pp_split)
     RETPUSHUNDEF;
 }
 
+#ifdef USE_THREADS
+void
+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));
+    if (MgOWNER(mg) != thr)
+       croak("panic: unlock_condpair unlocking mutex that we don't own");
+    MgOWNER(mg) = 0;
+    COND_SIGNAL(MgOWNERCONDP(mg));
+    DEBUG_L(PerlIO_printf(PerlIO_stderr(), "0x%lx: unlock 0x%lx\n",
+                         (unsigned long)thr, (unsigned long)svv);)
+    MUTEX_UNLOCK(MgMUTEXP(mg));
+}
+#endif /* USE_THREADS */
+
+PP(pp_lock)
+{
+    djSP;
+    dTOPss;
+    SV *retsv = sv;
+#ifdef USE_THREADS
+    MAGIC *mg;
+    
+    if (SvROK(sv))
+       sv = SvRV(sv);
+
+    mg = condpair_magic(sv);
+    MUTEX_LOCK(MgMUTEXP(mg));
+    if (MgOWNER(mg) == thr)
+       MUTEX_UNLOCK(MgMUTEXP(mg));
+    else {
+       while (MgOWNER(mg))
+           COND_WAIT(MgOWNERCONDP(mg), MgMUTEXP(mg));
+       MgOWNER(mg) = thr;
+       DEBUG_L(PerlIO_printf(PerlIO_stderr(), "0x%lx: pp_lock lock 0x%lx\n",
+                             (unsigned long)thr, (unsigned long)sv);)
+       MUTEX_UNLOCK(MgMUTEXP(mg));
+       SvREFCNT_inc(sv);       /* keep alive until magic_mutexfree */
+       save_destructor(unlock_condpair, sv);
+    }
+#endif /* USE_THREADS */
+    if (SvTYPE(retsv) == SVt_PVAV || SvTYPE(retsv) == SVt_PVHV
+       || SvTYPE(retsv) == SVt_PVCV) {
+       retsv = refto(retsv);
+    }
+    SETs(retsv);
+    RETURN;
+}
+
+PP(pp_threadsv)
+{
+    djSP;
+#ifdef USE_THREADS
+    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));
+#else
+    DIE("tried to access per-thread data in non-threaded perl");
+#endif /* USE_THREADS */
+    RETURN;
+}