[inseparable changes from patch from perl5.003_09 to perl5.003_10]
[p5sagit/p5-mst-13.2.git] / pp.c
diff --git a/pp.c b/pp.c
index 711ba29..48ca9bb 100644 (file)
--- a/pp.c
+++ b/pp.c
@@ -313,6 +313,7 @@ PP(pp_refgen)
        MARK[1] = *SP;
        SP = MARK + 1;
     }
+    EXTEND_MORTAL(SP - MARK);
     while (MARK < SP) {
        sv = *++MARK;
        rv = sv_newmortal();
@@ -421,13 +422,6 @@ PP(pp_study)
        else
            snext[pos] = -pos;
        sfirst[ch] = pos;
-
-       /* If there were any case insensitive searches, we must assume they
-        * all are.  This speeds up insensitive searches much more than
-        * it slows down sensitive ones.
-        */
-       if (sawi)
-           sfirst[fold[ch]] = pos;
     }
 
     SvSCREAM_on(sv);
@@ -575,14 +569,11 @@ PP(pp_undef)
 PP(pp_predec)
 {
     dSP;
-    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);
-       }
+    if (SvIOK(TOPs) && !SvNOK(TOPs) && !SvPOK(TOPs) &&
+       SvIVX(TOPs) != IV_MIN)
+    {
+       --SvIVX(TOPs);
+       SvFLAGS(TOPs) &= ~(SVp_NOK|SVp_POK);
     }
     else
        sv_dec(TOPs);
@@ -594,14 +585,11 @@ PP(pp_postinc)
 {
     dSP; dTARGET;
     sv_setsv(TARG, 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);
-       }
+    if (SvIOK(TOPs) && !SvNOK(TOPs) && !SvPOK(TOPs) &&
+       SvIVX(TOPs) != IV_MAX)
+    {
+       ++SvIVX(TOPs);
+       SvFLAGS(TOPs) &= ~(SVp_NOK|SVp_POK);
     }
     else
        sv_inc(TOPs);
@@ -616,14 +604,11 @@ PP(pp_postdec)
 {
     dSP; dTARGET;
     sv_setsv(TARG, 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);
-       }
+    if (SvIOK(TOPs) && !SvNOK(TOPs) && !SvPOK(TOPs) &&
+       SvIVX(TOPs) != IV_MIN)
+    {
+       --SvIVX(TOPs);
+       SvFLAGS(TOPs) &= ~(SVp_NOK|SVp_POK);
     }
     else
        sv_dec(TOPs);
@@ -687,19 +672,17 @@ PP(pp_modulo)
 {
     dSP; dATARGET; tryAMAGICbin(mod,opASSIGN);
     {
-      register unsigned long tmpulong;
-      register long tmplong;
-      I32 value;
+      register IV value;
+      register UV uval;
 
-      tmpulong = (unsigned long) POPn;
-      if (tmpulong == 0L)
+      uval = POPn;
+      if (!uval)
        DIE("Illegal modulus zero");
       value = TOPn;
-      if (value >= 0.0)
-       value = (I32)(((unsigned long)value) % tmpulong);
+      if (value >= 0)
+       value = (UV)value % uval;
       else {
-       tmplong = (long)value;
-       value = (I32)(tmpulong - ((-tmplong - 1) % tmpulong)) - 1;
+       value = (uval - ((UV)(-value - 1) % uval)) - 1;
       }
       SETi(value);
       RETURN;
@@ -775,9 +758,16 @@ PP(pp_left_shift)
 {
     dSP; dATARGET; tryAMAGICbin(lshift,opASSIGN); 
     {
-        dPOPTOPiirl;
-        SETi( left << right );
-        RETURN;
+      IV shift = POPi;
+      if (op->op_private & HINT_INTEGER) {
+       IV i = TOPi;
+       SETi( i << shift );
+      }
+      else {
+       UV u = TOPu;
+       SETu( u << shift );
+      }
+      RETURN;
     }
 }
 
@@ -785,8 +775,15 @@ PP(pp_right_shift)
 {
     dSP; dATARGET; tryAMAGICbin(rshift,opASSIGN); 
     {
-      dPOPTOPiirl;
-      SETi( left >> right );
+      IV shift = POPi;
+      if (op->op_private & HINT_INTEGER) {
+       IV i = TOPi;
+       SETi( i >> shift );
+      }
+      else {
+       UV u = TOPu;
+       SETu( u >> shift );
+      }
       RETURN;
     }
 }
@@ -864,7 +861,10 @@ PP(pp_slt)
     dSP; tryAMAGICbinSET(slt,0); 
     {
       dPOPTOPssrl;
-      SETs( sv_cmp(left, right) < 0 ? &sv_yes : &sv_no );
+      int cmp = ((op->op_private & OPpLOCALE)
+                ? sv_cmp_locale(left, right)
+                : sv_cmp(left, right));
+      SETs( cmp < 0 ? &sv_yes : &sv_no );
       RETURN;
     }
 }
@@ -874,7 +874,10 @@ PP(pp_sgt)
     dSP; tryAMAGICbinSET(sgt,0); 
     {
       dPOPTOPssrl;
-      SETs( sv_cmp(left, right) > 0 ? &sv_yes : &sv_no );
+      int cmp = ((op->op_private & OPpLOCALE)
+                ? sv_cmp_locale(left, right)
+                : sv_cmp(left, right));
+      SETs( cmp > 0 ? &sv_yes : &sv_no );
       RETURN;
     }
 }
@@ -884,7 +887,10 @@ PP(pp_sle)
     dSP; tryAMAGICbinSET(sle,0); 
     {
       dPOPTOPssrl;
-      SETs( sv_cmp(left, right) <= 0 ? &sv_yes : &sv_no );
+      int cmp = ((op->op_private & OPpLOCALE)
+                ? sv_cmp_locale(left, right)
+                : sv_cmp(left, right));
+      SETs( cmp <= 0 ? &sv_yes : &sv_no );
       RETURN;
     }
 }
@@ -894,7 +900,10 @@ PP(pp_sge)
     dSP; tryAMAGICbinSET(sge,0); 
     {
       dPOPTOPssrl;
-      SETs( sv_cmp(left, right) >= 0 ? &sv_yes : &sv_no );
+      int cmp = ((op->op_private & OPpLOCALE)
+                ? sv_cmp_locale(left, right)
+                : sv_cmp(left, right));
+      SETs( cmp >= 0 ? &sv_yes : &sv_no );
       RETURN;
     }
 }
@@ -904,7 +913,10 @@ PP(pp_sne)
     dSP; tryAMAGICbinSET(sne,0); 
     {
       dPOPTOPssrl;
-      SETs( !sv_eq(left, right) ? &sv_yes : &sv_no );
+      bool ne = ((op->op_private & OPpLOCALE)
+                ? (sv_cmp_locale(left, right) != 0)
+                : !sv_eq(left, right));
+      SETs( ne ? &sv_yes : &sv_no );
       RETURN;
     }
 }
@@ -914,19 +926,25 @@ PP(pp_scmp)
     dSP; dTARGET;  tryAMAGICbin(scmp,0);
     {
       dPOPTOPssrl;
-      SETi( sv_cmp(left, right) );
+      int cmp = ((op->op_private & OPpLOCALE)
+                ? sv_cmp_locale(left, right)
+                : sv_cmp(left, right));
+      SETi( cmp );
       RETURN;
     }
 }
 
-PP(pp_bit_and) {
+PP(pp_bit_and)
+{
     dSP; dATARGET; tryAMAGICbin(band,opASSIGN); 
     {
       dPOPTOPssrl;
       if (SvNIOKp(left) || SvNIOKp(right)) {
-       unsigned long value = U_L(SvNV(left));
-       value = value & U_L(SvNV(right));
-       SETn((double)value);
+       UV value = SvUV(left) & SvUV(right); 
+       if (op->op_private & HINT_INTEGER)
+         SETi( (IV)value );
+       else
+         SETu( value );
       }
       else {
        do_vop(op->op_type, TARG, left, right);
@@ -942,9 +960,11 @@ PP(pp_bit_xor)
     {
       dPOPTOPssrl;
       if (SvNIOKp(left) || SvNIOKp(right)) {
-       unsigned long value = U_L(SvNV(left));
-       value = value ^ U_L(SvNV(right));
-       SETn((double)value);
+       UV value = SvUV(left) ^ SvUV(right);
+       if (op->op_private & HINT_INTEGER)
+         SETi( (IV)value );
+       else
+         SETu( value );
       }
       else {
        do_vop(op->op_type, TARG, left, right);
@@ -960,9 +980,11 @@ PP(pp_bit_or)
     {
       dPOPTOPssrl;
       if (SvNIOKp(left) || SvNIOKp(right)) {
-       unsigned long value = U_L(SvNV(left));
-       value = value | U_L(SvNV(right));
-       SETn((double)value);
+       UV value = SvUV(left) | SvUV(right);
+       if (op->op_private & HINT_INTEGER)
+         SETi( (IV)value );
+       else
+         SETu( value );
       }
       else {
        do_vop(op->op_type, TARG, left, right);
@@ -979,12 +1001,14 @@ PP(pp_negate)
        dTOPss;
        if (SvGMAGICAL(sv))
            mg_get(sv);
-       if (SvNIOKp(sv))
+       if (SvIOKp(sv) && !SvNOKp(sv) && !SvPOKp(sv) && SvIVX(sv) != IV_MIN)
+           SETi(-SvIVX(sv));
+       else if (SvNIOKp(sv))
            SETn(-SvNV(sv));
        else if (SvPOKp(sv)) {
            STRLEN len;
            char *s = SvPV(sv, len);
-           if (isALPHA(*s) || *s == '_') {
+           if (isIDFIRST(*s)) {
                sv_setpvn(TARG, "-", 1);
                sv_catsv(TARG, sv);
            }
@@ -1016,18 +1040,17 @@ PP(pp_complement)
     dSP; dTARGET; tryAMAGICun(compl); 
     {
       dTOPss;
-      register I32 anum;
-
       if (SvNIOKp(sv)) {
-       IV iv = ~SvIV(sv);
-       if (iv < 0)
-           SETn( (double) ~U_L(SvNV(sv)) );
+       UV value = ~SvUV(sv);
+       if (op->op_private & HINT_INTEGER)
+         SETi( (IV)value );
        else
-           SETi( iv );
+         SETu( value );
       }
       else {
        register char *tmps;
        register long *tmpl;
+       register I32 anum;
        STRLEN len;
 
        SvSetSV(TARG, sv);
@@ -1308,8 +1331,10 @@ PP(pp_log)
     {
       double value;
       value = POPn;
-      if (value <= 0.0)
+      if (value <= 0.0) {
+       NUMERIC_STANDARD();
        DIE("Can't take log of %g", value);
+      }
       value = log(value);
       XPUSHn(value);
       RETURN;
@@ -1322,8 +1347,10 @@ PP(pp_sqrt)
     {
       double value;
       value = POPn;
-      if (value < 0.0)
+      if (value < 0.0) {
+       NUMERIC_STANDARD();
        DIE("Can't take sqrt of %g", value);
+      }
       value = sqrt(value);
       XPUSHn(value);
       RETURN;
@@ -1364,22 +1391,17 @@ PP(pp_hex)
 {
     dSP; dTARGET;
     char *tmps;
-    unsigned long value;
     I32 argtype;
 
     tmps = POPp;
-    value = scan_hex(tmps, 99, &argtype);
-    if ((IV)value >= 0)
-       XPUSHi(value);
-    else
-       XPUSHn(U_V(value));
+    XPUSHu(scan_hex(tmps, 99, &argtype));
     RETURN;
 }
 
 PP(pp_oct)
 {
     dSP; dTARGET;
-    unsigned long value;
+    UV value;
     I32 argtype;
     char *tmps;
 
@@ -1392,10 +1414,7 @@ PP(pp_oct)
        value = scan_hex(++tmps, 99, &argtype);
     else
        value = scan_oct(tmps, 99, &argtype);
-    if ((IV)value >= 0)
-       XPUSHi(value);
-    else
-       XPUSHn(U_V(value));
+    XPUSHu(value);
     RETURN;
 }
 
@@ -1618,7 +1637,14 @@ PP(pp_rindex)
 PP(pp_sprintf)
 {
     dSP; dMARK; dORIGMARK; dTARGET;
+#ifdef LC_NUMERIC
+    if (op->op_private & OPpLOCALE)
+       NUMERIC_LOCAL();
+    else
+       NUMERIC_STANDARD();
+#endif /* LC_NUMERIC */
     do_sprintf(TARG, SP-MARK, MARK+1);
+    TAINT_IF(SvTAINTED(TARG));
     SP = ORIGMARK;
     PUSHTARG;
     RETURN;
@@ -1690,8 +1716,15 @@ PP(pp_ucfirst)
        SETs(sv);
     }
     s = SvPV_force(sv, na);
-    if (isLOWER(*s))
-       *s = toUPPER(*s);
+    if (*s) {
+       if (op->op_private & OPpLOCALE) {
+           TAINT;
+           SvTAINTED_on(sv);
+           *s = toUPPER_LC(*s);
+       }
+       else
+           *s = toUPPER(*s);
+    }
 
     RETURN;
 }
@@ -1709,8 +1742,15 @@ PP(pp_lcfirst)
        SETs(sv);
     }
     s = SvPV_force(sv, na);
-    if (isUPPER(*s))
-       *s = toLOWER(*s);
+    if (*s) {
+       if (op->op_private & OPpLOCALE) {
+           TAINT;
+           SvTAINTED_on(sv);
+           *s = toLOWER_LC(*s);
+       }
+       else
+           *s = toLOWER(*s);
+    }
 
     SETs(sv);
     RETURN;
@@ -1721,7 +1761,6 @@ PP(pp_uc)
     dSP;
     SV *sv = TOPs;
     register char *s;
-    register char *send;
     STRLEN len;
 
     if (!SvPADTMP(sv)) {
@@ -1730,12 +1769,21 @@ PP(pp_uc)
        sv = TARG;
        SETs(sv);
     }
+
     s = SvPV_force(sv, len);
-    send = s + len;
-    while (s < send) {
-       if (isLOWER(*s))
-           *s = toUPPER(*s);
-       s++;
+    if (len) {
+       register char *send = s + len;
+
+       if (op->op_private & OPpLOCALE) {
+           TAINT;
+           SvTAINTED_on(sv);
+           for (; s < send; s++)
+               *s = toUPPER_LC(*s);
+       }
+       else {
+           for (; s < send; s++)
+               *s = toUPPER(*s);
+       }
     }
     RETURN;
 }
@@ -1745,7 +1793,6 @@ PP(pp_lc)
     dSP;
     SV *sv = TOPs;
     register char *s;
-    register char *send;
     STRLEN len;
 
     if (!SvPADTMP(sv)) {
@@ -1754,12 +1801,21 @@ PP(pp_lc)
        sv = TARG;
        SETs(sv);
     }
+
     s = SvPV_force(sv, len);
-    send = s + len;
-    while (s < send) {
-       if (isUPPER(*s))
-           *s = toLOWER(*s);
-       s++;
+    if (len) {
+       register char *send = s + len;
+
+       if (op->op_private & OPpLOCALE) {
+           TAINT;
+           SvTAINTED_on(sv);
+           for (; s < send; s++)
+               *s = toLOWER_LC(*s);
+       }
+       else {
+           for (; s < send; s++)
+               *s = toLOWER(*s);
+       }
     }
     RETURN;
 }
@@ -2103,6 +2159,7 @@ PP(pp_splice)
            MEXTEND(MARK, length);
            Copy(AvARRAY(ary)+offset, MARK, length, SV*);
            if (AvREAL(ary)) {
+               EXTEND_MORTAL(length);
                for (i = length, dst = MARK; i; i--)
                    sv_2mortal(*dst++); /* free them eventualy */
            }
@@ -2197,6 +2254,7 @@ PP(pp_splice)
            if (length) {
                Copy(tmparyval, MARK, length, SV*);
                if (AvREAL(ary)) {
+                   EXTEND_MORTAL(length);
                    for (i = length, dst = MARK; i; i--)
                        sv_2mortal(*dst++);     /* free them eventualy */
                }
@@ -2323,6 +2381,35 @@ PP(pp_reverse)
     RETURN;
 }
 
+static SV      *
+mul128(sv, m)
+     SV             *sv;
+     U8              m;
+{
+  STRLEN          len;
+  char           *s = SvPV(sv, len);
+  char           *t;
+  U32             i = 0;
+
+  if (!strnEQ(s, "0000", 4)) {  /* need to grow sv */
+    SV             *new = newSVpv("0000000000", 10);
+
+    sv_catsv(new, sv);
+    SvREFCNT_dec(sv);          /* free old sv */
+    sv = new;
+    s = SvPV(sv, len);
+  }
+  t = s + len - 1;
+  while (!*t)                   /* trailing '\0'? */
+    t--;
+  while (t > s) {
+    i = ((*t - '0') << 7) + m;
+    *(t--) = '0' + (i % 10);
+    m = i / 10;
+  }
+  return (sv);
+}
+
 /* Explosives and implosives. */
 
 PP(pp_unpack)
@@ -2550,6 +2637,7 @@ PP(pp_unpack)
            }
            else {
                EXTEND(SP, len);
+               EXTEND_MORTAL(len);
                while (len-- > 0) {
                    aint = *s++;
                    if (aint >= 128)    /* fake up signed chars */
@@ -2572,6 +2660,7 @@ PP(pp_unpack)
            }
            else {
                EXTEND(SP, len);
+               EXTEND_MORTAL(len);
                while (len-- > 0) {
                    auint = *s++ & 255;
                    sv = NEWSV(37, 0);
@@ -2593,6 +2682,7 @@ PP(pp_unpack)
            }
            else {
                EXTEND(SP, len);
+               EXTEND_MORTAL(len);
                while (len-- > 0) {
                    Copy(s, &ashort, 1, I16);
                    s += sizeof(I16);
@@ -2625,6 +2715,7 @@ PP(pp_unpack)
            }
            else {
                EXTEND(SP, len);
+               EXTEND_MORTAL(len);
                while (len-- > 0) {
                    Copy(s, &aushort, 1, U16);
                    s += sizeof(U16);
@@ -2658,6 +2749,7 @@ PP(pp_unpack)
            }
            else {
                EXTEND(SP, len);
+               EXTEND_MORTAL(len);
                while (len-- > 0) {
                    Copy(s, &aint, 1, int);
                    s += sizeof(int);
@@ -2683,11 +2775,15 @@ PP(pp_unpack)
            }
            else {
                EXTEND(SP, len);
+               EXTEND_MORTAL(len);
                while (len-- > 0) {
                    Copy(s, &auint, 1, unsigned int);
                    s += sizeof(unsigned int);
                    sv = NEWSV(41, 0);
-                   sv_setiv(sv, (I32)auint);
+                   if (auint <= I32_MAX)
+                       sv_setiv(sv, (I32)auint);
+                   else
+                       sv_setnv(sv, (double)auint);
                    PUSHs(sv_2mortal(sv));
                }
            }
@@ -2708,6 +2804,7 @@ PP(pp_unpack)
            }
            else {
                EXTEND(SP, len);
+               EXTEND_MORTAL(len);
                while (len-- > 0) {
                    Copy(s, &along, 1, I32);
                    s += sizeof(I32);
@@ -2743,6 +2840,7 @@ PP(pp_unpack)
            }
            else {
                EXTEND(SP, len);
+               EXTEND_MORTAL(len);
                while (len-- > 0) {
                    Copy(s, &aulong, 1, U32);
                    s += sizeof(U32);
@@ -2765,6 +2863,7 @@ PP(pp_unpack)
            if (len > along)
                len = along;
            EXTEND(SP, len);
+           EXTEND_MORTAL(len);
            while (len-- > 0) {
                if (sizeof(char*) > strend - s)
                    break;
@@ -2778,6 +2877,49 @@ PP(pp_unpack)
                PUSHs(sv_2mortal(sv));
            }
            break;
+       case 'w':
+           EXTEND(SP, len);
+           EXTEND_MORTAL(len);
+           { 
+               UV auv = 0;
+               U32 bytes = 0;
+               
+               while ((len > 0) && (s < strend)) {
+                   auv = (auv << 7) | (*s & 0x7f);
+                   if (!(*s++ & 0x80)) {
+                       bytes = 0;
+                       sv = NEWSV(40, 0);
+                       sv_setuv(sv, auv);
+                       PUSHs(sv_2mortal(sv));
+                       len--;
+                       auv = 0;
+                   }
+                   else if (++bytes >= sizeof(UV)) {   /* promote to string */
+                       char decn[sizeof(UV) * 3 + 1];
+                       char *t;
+
+                       (void) sprintf(decn, "%0*ld", sizeof(decn) - 1, auv);
+                       sv = newSVpv(decn, 0);
+                       while (s < strend) {
+                           sv = mul128(sv, *s & 0x7f);
+                           if (!(*s++ & 0x80)) {
+                               bytes = 0;
+                               break;
+                           }
+                       }
+                       t = SvPV(sv, na);
+                       while (*t == '0')
+                           t++;
+                       sv_chop(sv, t);
+                       PUSHs(sv_2mortal(sv));
+                       len--;
+                       auv = 0;
+                   }
+               }
+               if ((s >= strend) && bytes)
+                   croak("Unterminated compressed integer");
+           }
+           break;
        case 'P':
            EXTEND(SP, 1);
            if (sizeof(char*) > strend - s)
@@ -2794,6 +2936,7 @@ PP(pp_unpack)
 #ifdef HAS_QUAD
        case 'q':
            EXTEND(SP, len);
+           EXTEND_MORTAL(len);
            while (len-- > 0) {
                if (s + sizeof(Quad_t) > strend)
                    aquad = 0;
@@ -2808,6 +2951,7 @@ PP(pp_unpack)
            break;
        case 'Q':
            EXTEND(SP, len);
+           EXTEND_MORTAL(len);
            while (len-- > 0) {
                if (s + sizeof(unsigned Quad_t) > strend)
                    auquad = 0;
@@ -2836,6 +2980,7 @@ PP(pp_unpack)
            }
            else {
                EXTEND(SP, len);
+               EXTEND_MORTAL(len);
                while (len-- > 0) {
                    Copy(s, &afloat, 1, float);
                    s += sizeof(float);
@@ -2859,6 +3004,7 @@ PP(pp_unpack)
            }
            else {
                EXTEND(SP, len);
+               EXTEND_MORTAL(len);
                while (len-- > 0) {
                    Copy(s, &adouble, 1, double);
                    s += sizeof(double);
@@ -2974,6 +3120,85 @@ register I32 len;
     sv_catpvn(sv, "\n", 1);
 }
 
+static SV      *
+is_an_int(s, l)
+     char           *s;
+     STRLEN          l;
+{
+  SV             *result = newSVpv("", l);
+  char           *result_c = SvPV(result, na); /* convenience */
+  char           *out = result_c;
+  bool            skip = 1;
+  bool            ignore = 0;
+
+  while (*s) {
+    switch (*s) {
+    case ' ':
+      break;
+    case '+':
+      if (!skip) {
+       SvREFCNT_dec(result);
+       return (NULL);
+      }
+      break;
+    case '0':
+    case '1':
+    case '2':
+    case '3':
+    case '4':
+    case '5':
+    case '6':
+    case '7':
+    case '8':
+    case '9':
+      skip = 0;
+      if (!ignore) {
+       *(out++) = *s;
+      }
+      break;
+    case '.':
+      ignore = 1;
+      break;
+    default:
+      SvREFCNT_dec(result);
+      return (NULL);
+    }
+    s++;
+  }
+  *(out++) = '\0';
+  SvCUR_set(result, out - result_c);
+  return (result);
+}
+
+static int
+div128(pnum, done)
+     SV             *pnum;                 /* must be '\0' terminated */
+     bool           *done;
+{
+  STRLEN          len;
+  char           *s = SvPV(pnum, len);
+  int             m = 0;
+  int             r = 0;
+  char           *t = s;
+
+  *done = 1;
+  while (*t) {
+    int             i;
+
+    i = m * 10 + (*t - '0');
+    m = i & 0x7F;
+    r = (i >> 7);              /* r < 10 */
+    if (r) {
+      *done = 0;
+    }
+    *(t++) = '0' + r;
+  }
+  *(t++) = '\0';
+  SvCUR_set(pnum, (STRLEN) (t - s));
+  return (m);
+}
+
+
 PP(pp_pack)
 {
     dSP; dMARK; dORIGMARK; dTARGET;
@@ -3253,6 +3478,64 @@ PP(pp_pack)
                sv_catpvn(cat, (char*)&auint, sizeof(unsigned int));
            }
            break;
+       case 'w':
+            while (len-- > 0) {
+               fromstr = NEXTFROM;
+               adouble = floor(SvNV(fromstr));
+
+               if (adouble < 0)
+                   croak("Cannot compress negative numbers");
+
+               if (adouble <= UV_MAX) {
+                   char   buf[1 + sizeof(UV)];
+                   char  *in = buf + sizeof(buf);
+                   UV     auv = U_V(adouble);;
+
+                   do {
+                       *--in = (auv & 0x7f) | 0x80;
+                       auv >>= 7;
+                   } while (auv);
+                   buf[sizeof(buf) - 1] &= 0x7f; /* clear continue bit */
+                   sv_catpvn(cat, in, (buf + sizeof(buf)) - in);
+               }
+               else if (SvPOKp(fromstr)) {  /* decimal string arithmetics */
+                   char           *from, *result, *in;
+                   SV             *norm;
+                   STRLEN          len;
+                   bool            done;
+            
+                   /* Copy string and check for compliance */
+                   from = SvPV(fromstr, len);
+                   if ((norm = is_an_int(from, len)) == NULL)
+                       croak("can compress only unsigned integer");
+
+                   New('w', result, len, char);
+                   in = result + len;
+                   done = FALSE;
+                   while (!done)
+                       *--in = div128(norm, &done) | 0x80;
+                   result[len - 1] &= 0x7F; /* clear continue bit */
+                   sv_catpvn(cat, in, (result + len) - in);
+                   SvREFCNT_dec(norm); /* free norm */
+                }
+               else if (SvNOKp(fromstr)) {
+                   char   buf[sizeof(double) * 2];     /* 8/7 <= 2 */
+                   char  *in = buf + sizeof(buf);
+
+                   do {
+                       double next = floor(adouble / 128);
+                       *--in = (unsigned char)(adouble - (next * 128)) | 0x80;
+                       if (--in < buf)  /* this cannot happen ;-) */
+                           croak ("Cannot compress integer");
+                       adouble = next;
+                   } while (adouble > 0);
+                   buf[sizeof(buf) - 1] &= 0x7f; /* clear continue bit */
+                   sv_catpvn(cat, in, (buf + sizeof(buf)) - in);
+               }
+               else
+                   croak("Cannot compress non integer");
+           }
+            break;
        case 'i':
            while (len-- > 0) {
                fromstr = NEXTFROM;
@@ -3375,6 +3658,10 @@ PP(pp_split)
 
     if (!pm || !s)
        DIE("panic: do_split");
+
+    TAINT_IF((pm->op_pmflags & PMf_LOCALE) &&
+            (pm->op_pmflags & (PMf_WHITE | PMf_SKIPWHITE)));
+
     if (pm->op_pmreplroot)
        ary = GvAVn((GV*)pm->op_pmreplroot);
     else if (gimme != G_ARRAY)
@@ -3396,8 +3683,14 @@ PP(pp_split)
     base = SP - stack_base;
     orig = s;
     if (pm->op_pmflags & PMf_SKIPWHITE) {
-       while (isSPACE(*s))
-           s++;
+       if (pm->op_pmflags & PMf_LOCALE) {
+           while (isSPACE_LC(*s))
+               s++;
+       }
+       else {
+           while (isSPACE(*s))
+               s++;
+       }
     }
     if (pm->op_pmflags & (PMf_MULTILINE|PMf_SINGLELINE)) {
        SAVEINT(multiline);
@@ -3408,17 +3701,25 @@ PP(pp_split)
        limit = maxiters + 2;
     if (pm->op_pmflags & PMf_WHITE) {
        while (--limit) {
-           /*SUPPRESS 530*/
-           for (m = s; m < strend && !isSPACE(*m); m++) ;
+           m = s;
+           while (m < strend &&
+                  !((pm->op_pmflags & PMf_LOCALE)
+                    ? isSPACE_LC(*m) : isSPACE(*m)))
+               ++m;
            if (m >= strend)
                break;
+
            dstr = NEWSV(30, m-s);
            sv_setpvn(dstr, s, m-s);
            if (!realarray)
                sv_2mortal(dstr);
            XPUSHs(dstr);
-           /*SUPPRESS 530*/
-           for (s = m + 1; s < strend && isSPACE(*s); s++) ;
+
+           s = m + 1;
+           while (s < strend &&
+                  ((pm->op_pmflags & PMf_LOCALE)
+                   ? isSPACE_LC(*s) : isSPACE(*s)))
+               ++s;
        }
     }
     else if (strEQ("^", rx->precomp)) {
@@ -3439,20 +3740,10 @@ PP(pp_split)
     else if (pm->op_pmshort) {
        i = SvCUR(pm->op_pmshort);
        if (i == 1) {
-           I32 fold = (pm->op_pmflags & PMf_FOLD);
            i = *SvPVX(pm->op_pmshort);
-           if (fold && isUPPER(i))
-               i = toLOWER(i);
            while (--limit) {
-               if (fold) {
-                   for ( m = s;
-                         m < strend && *m != i &&
-                           (!isUPPER(*m) || toLOWER(*m) != i);
-                         m++)                  /*SUPPRESS 530*/
-                       ;
-               }
-               else                            /*SUPPRESS 530*/
-                   for (m = s; m < strend && *m != i; m++) ;
+               /*SUPPRESS 530*/
+               for (m = s; m < strend && *m != i; m++) ;
                if (m >= strend)
                    break;
                dstr = NEWSV(30, m-s);
@@ -3482,7 +3773,9 @@ PP(pp_split)
     else {
        maxiters += (strend - s) * rx->nparens;
        while (s < strend && --limit &&
-           pregexec(rx, s, strend, orig, 1, Nullsv, TRUE) ) {
+              pregexec(rx, s, strend, orig, 1, Nullsv, TRUE))
+       {
+           TAINT_IF(rx->exec_tainted);
            if (rx->subbase
              && rx->subbase != orig) {
                m = s;