PATCH: untaint method for IO::Handle, 5.003_06 version
[p5sagit/p5-mst-13.2.git] / pp.c
diff --git a/pp.c b/pp.c
index 711ba29..48e3321 100644 (file)
--- a/pp.c
+++ b/pp.c
@@ -687,19 +687,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;
@@ -926,7 +924,10 @@ PP(pp_bit_and) {
       if (SvNIOKp(left) || SvNIOKp(right)) {
        unsigned long value = U_L(SvNV(left));
        value = value & U_L(SvNV(right));
-       SETn((double)value);
+       if ((IV)value == value)
+           SETi(value);
+       else
+           SETn((double)value);
       }
       else {
        do_vop(op->op_type, TARG, left, right);
@@ -944,7 +945,10 @@ PP(pp_bit_xor)
       if (SvNIOKp(left) || SvNIOKp(right)) {
        unsigned long value = U_L(SvNV(left));
        value = value ^ U_L(SvNV(right));
-       SETn((double)value);
+       if ((IV)value == value)
+           SETi(value);
+       else
+           SETn((double)value);
       }
       else {
        do_vop(op->op_type, TARG, left, right);
@@ -962,7 +966,10 @@ PP(pp_bit_or)
       if (SvNIOKp(left) || SvNIOKp(right)) {
        unsigned long value = U_L(SvNV(left));
        value = value | U_L(SvNV(right));
-       SETn((double)value);
+       if ((IV)value == value)
+           SETi(value);
+       else
+           SETn((double)value);
       }
       else {
        do_vop(op->op_type, TARG, left, right);
@@ -1019,11 +1026,11 @@ PP(pp_complement)
       register I32 anum;
 
       if (SvNIOKp(sv)) {
-       IV iv = ~SvIV(sv);
-       if (iv < 0)
-           SETn( (double) ~U_L(SvNV(sv)) );
+       UV value = ~SvIV(sv);
+       if ((IV)value == value)
+           SETi(value);
        else
-           SETi( iv );
+           SETn((double)value);
       }
       else {
        register char *tmps;
@@ -2687,7 +2694,10 @@ PP(pp_unpack)
                    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));
                }
            }
@@ -2778,6 +2788,51 @@ PP(pp_unpack)
                PUSHs(sv_2mortal(sv));
            }
            break;
+       case 'w':
+           along = (strend - s) / sizeof(char);
+           if (len > along)
+               len = along;
+           EXTEND(SP, len);
+            { 
+              I8  bytes = 0;
+
+              auint = 0;
+              while  (len > 0) {
+                if (s >= strend) {
+                  if (auint) {
+                    DIE("Unterminated compressed integer");
+                  } else {
+                    break;
+                  }
+                }
+                auint = (auint << 7) | (*s & 0x7f);
+                if (!(*s & 0x80)) {
+                  sv = NEWSV(40, 0);
+                  sv_setiv(sv, (I32) auint);
+                  PUSHs(sv_2mortal(sv));
+                  len--;
+                  auint = 0;
+                  bytes = 0;
+                } else if (++bytes >= sizeof(auint)) {         /* promote to double */
+                  adouble = auint;
+
+                  while (*s &  0x80) {
+                    adouble = (adouble * 128) + (*(++s) & 0x7f);
+                    if (s >= strend) {
+                      DIE("Unterminated compressed integer");
+                    }
+                  }
+                  sv = NEWSV(40, 0);
+                  sv_setnv(sv, adouble);
+                  PUSHs(sv_2mortal(sv));
+                  len--;
+                  auint = 0;
+                  bytes = 0;
+                }
+                s++;
+              }
+            }
+           break;
        case 'P':
            EXTEND(SP, 1);
            if (sizeof(char*) > strend - s)
@@ -3253,6 +3308,42 @@ PP(pp_pack)
                sv_catpvn(cat, (char*)&auint, sizeof(unsigned int));
            }
            break;
+       case 'w':
+            while (len-- > 0) {
+              fromstr = NEXTFROM;
+              adouble = floor((double)SvNV(fromstr));
+
+              if (adouble < 268435456) {           /* we can use integers */
+                unsigned char buf[4];              /* buffer for compressed int */
+                unsigned char *in = buf + 3;
+                auint = U_I(adouble);
+                do {
+                  *(in--) = (unsigned char) ((auint & 0x7f) |  0x80); 
+                  auint >>= 7;
+                } while (auint);
+                buf[3]  &= 0x7f;                   /* clear continue bit */
+                sv_catpvn(cat, (char*) in+1, buf+3-in);
+              } else {
+                unsigned char buf[sizeof(double)*2]; /* buffer for compressed int */
+                I8       msize = sizeof(double)*2; /* 8/7 would be enough */
+                unsigned char *in = buf + msize -1;
+                if (adouble<0) {
+                  croak("Cannot compress negative numbers");
+                }
+                do  {
+                  double next = adouble/128;
+                  *in = (unsigned char) (adouble - floor(next)*128);
+                  *in |= 0x80;                     /* set continue bit */
+                  if (--in < buf) {                /* this cannot happen ;-) */
+                    croak ("Cannot compress integer");
+                  }
+                  adouble = next;
+                } while (floor(adouble)>0);        /* floor() not necessary? */
+                buf[msize-1] &= 0x7f;              /* clear continue bit */
+                sv_catpvn(cat, (char*) in+1, buf+msize-in-1);
+              }
+            }
+            break;
        case 'i':
            while (len-- > 0) {
                fromstr = NEXTFROM;