Integrate with Sarathy.
[p5sagit/p5-mst-13.2.git] / doop.c
diff --git a/doop.c b/doop.c
index ec14a76..4f536f0 100644 (file)
--- a/doop.c
+++ b/doop.c
@@ -1,6 +1,6 @@
 /*    doop.c
  *
- *    Copyright (c) 1991-1999, Larry Wall
+ *    Copyright (c) 1991-2000, Larry Wall
  *
  *    You may distribute under the terms of either the GNU General Public
  *    License or the Artistic License, as specified in the README file.
  */
 
 #include "EXTERN.h"
+#define PERL_IN_DOOP_C
 #include "perl.h"
 
 #if !defined(NSIG) || defined(M_UNIX) || defined(M_XENIX)
 #include <signal.h>
 #endif
 
-#ifndef PERL_OBJECT
-static I32 do_trans_CC_simple _((SV *sv));
-static I32 do_trans_CC_count _((SV *sv));
-static I32 do_trans_CC_complex _((SV *sv));
-static I32 do_trans_UU_simple _((SV *sv));
-static I32 do_trans_UU_count _((SV *sv));
-static I32 do_trans_UU_complex _((SV *sv));
-static I32 do_trans_UC_simple _((SV *sv));
-static I32 do_trans_CU_simple _((SV *sv));
-static I32 do_trans_UC_trivial _((SV *sv));
-static I32 do_trans_CU_trivial _((SV *sv));
-#endif
-
 STATIC I32
-do_trans_CC_simple(SV *sv)
+S_do_trans_CC_simple(pTHX_ SV *sv)
 {
     dTHR;
     U8 *s;
@@ -44,7 +32,7 @@ do_trans_CC_simple(SV *sv)
 
     tbl = (short*)cPVOP->op_pv;
     if (!tbl)
-       croak("panic: do_trans");
+       Perl_croak(aTHX_ "panic: do_trans");
 
     s = (U8*)SvPV(sv, len);
     send = s + len;
@@ -62,7 +50,7 @@ do_trans_CC_simple(SV *sv)
 }
 
 STATIC I32
-do_trans_CC_count(SV *sv)
+S_do_trans_CC_count(pTHX_ SV *sv)
 {
     dTHR;
     U8 *s;
@@ -73,7 +61,7 @@ do_trans_CC_count(SV *sv)
 
     tbl = (short*)cPVOP->op_pv;
     if (!tbl)
-       croak("panic: do_trans");
+       Perl_croak(aTHX_ "panic: do_trans");
 
     s = (U8*)SvPV(sv, len);
     send = s + len;
@@ -88,7 +76,7 @@ do_trans_CC_count(SV *sv)
 }
 
 STATIC I32
-do_trans_CC_complex(SV *sv)
+S_do_trans_CC_complex(pTHX_ SV *sv)
 {
     dTHR;
     U8 *s;
@@ -101,7 +89,7 @@ do_trans_CC_complex(SV *sv)
 
     tbl = (short*)cPVOP->op_pv;
     if (!tbl)
-       croak("panic: do_trans");
+       Perl_croak(aTHX_ "panic: do_trans");
 
     s = (U8*)SvPV(sv, len);
     send = s + len;
@@ -145,7 +133,7 @@ do_trans_CC_complex(SV *sv)
 }
 
 STATIC I32
-do_trans_UU_simple(SV *sv)
+S_do_trans_UU_simple(pTHX_ SV *sv)
 {
     dTHR;
     U8 *s;
@@ -197,7 +185,7 @@ do_trans_UU_simple(SV *sv)
 }
 
 STATIC I32
-do_trans_UU_count(SV *sv)
+S_do_trans_UU_count(pTHX_ SV *sv)
 {
     dTHR;
     U8 *s;
@@ -224,7 +212,7 @@ do_trans_UU_count(SV *sv)
 }
 
 STATIC I32
-do_trans_UC_simple(SV *sv)
+S_do_trans_UC_simple(pTHX_ SV *sv)
 {
     dTHR;
     U8 *s;
@@ -277,7 +265,7 @@ do_trans_UC_simple(SV *sv)
 }
 
 STATIC I32
-do_trans_CU_simple(SV *sv)
+S_do_trans_CU_simple(pTHX_ SV *sv)
 {
     dTHR;
     U8 *s;
@@ -294,7 +282,7 @@ do_trans_CU_simple(SV *sv)
     UV extra = none + 1;
     UV final;
     UV uv;
-    U8 tmpbuf[10];
+    U8 tmpbuf[UTF8_MAXLEN];
     I32 bits = 16;
 
     s = (U8*)SvPV(sv, len);
@@ -340,7 +328,7 @@ do_trans_CU_simple(SV *sv)
 /* utf-8 to latin-1 */
 
 STATIC I32
-do_trans_UC_trivial(SV *sv)
+S_do_trans_UC_trivial(pTHX_ SV *sv)
 {
     dTHR;
     U8 *s;
@@ -372,7 +360,7 @@ do_trans_UC_trivial(SV *sv)
 /* latin-1 to utf-8 */
 
 STATIC I32
-do_trans_CU_trivial(SV *sv)
+S_do_trans_CU_trivial(pTHX_ SV *sv)
 {
     dTHR;
     U8 *s;
@@ -406,7 +394,7 @@ do_trans_CU_trivial(SV *sv)
 }
 
 STATIC I32
-do_trans_UU_complex(SV *sv)
+S_do_trans_UU_complex(pTHX_ SV *sv)
 {
     dTHR;
     U8 *s;
@@ -591,13 +579,13 @@ do_trans_UU_complex(SV *sv)
 }
 
 I32
-do_trans(SV *sv)
+Perl_do_trans(pTHX_ SV *sv)
 {
     dTHR;
     STRLEN len;
 
     if (SvREADONLY(sv) && !(PL_op->op_private & OPpTRANS_IDENTICAL))
-       croak(PL_no_modify);
+       Perl_croak(aTHX_ PL_no_modify);
 
     (void)SvPV(sv, len);
     if (!len)
@@ -606,7 +594,7 @@ do_trans(SV *sv)
        (void)SvPV_force(sv, len);
     (void)SvPOK_only(sv);
 
-    DEBUG_t( deb("2.TBL\n"));
+    DEBUG_t( Perl_deb(aTHX_ "2.TBL\n"));
 
     switch (PL_op->op_private & 63) {
     case 0:
@@ -642,7 +630,7 @@ do_trans(SV *sv)
 }
 
 void
-do_join(register SV *sv, SV *del, register SV **mark, register SV **sp)
+Perl_do_join(pTHX_ register SV *sv, SV *del, register SV **mark, register SV **sp)
 {
     SV **oldmark = mark;
     register I32 items = sp - mark;
@@ -697,7 +685,7 @@ do_join(register SV *sv, SV *del, register SV **mark, register SV **sp)
 }
 
 void
-do_sprintf(SV *sv, I32 len, SV **sarg)
+Perl_do_sprintf(pTHX_ SV *sv, I32 len, SV **sarg)
 {
     STRLEN patlen;
     char *pat = SvPV(*sarg, patlen);
@@ -709,14 +697,146 @@ do_sprintf(SV *sv, I32 len, SV **sarg)
        SvTAINTED_on(sv);
 }
 
+UV
+Perl_do_vecget(pTHX_ SV *sv, I32 offset, I32 size)
+{
+    STRLEN srclen, len;
+    unsigned char *s = (unsigned char *) SvPV(sv, srclen);
+    UV retnum = 0;
+
+    if (offset < 0)
+       return retnum;
+    if (size < 1 || (size & (size-1))) /* size < 1 or not a power of two */ 
+       Perl_croak(aTHX_ "Illegal number of bits in vec");
+    offset *= size;    /* turn into bit offset */
+    len = (offset + size + 7) / 8;     /* required number of bytes */
+    if (len > srclen) {
+       if (size <= 8)
+           retnum = 0;
+       else {
+           offset >>= 3;       /* turn into byte offset */
+           if (size == 16) {
+               if (offset >= srclen)
+                   retnum = 0;
+               else
+                   retnum = (UV) s[offset] <<  8;
+           }
+           else if (size == 32) {
+               if (offset >= srclen)
+                   retnum = 0;
+               else if (offset + 1 >= srclen)
+                   retnum =
+                       ((UV) s[offset    ] << 24);
+               else if (offset + 2 >= srclen)
+                   retnum =
+                       ((UV) s[offset    ] << 24) +
+                       ((UV) s[offset + 1] << 16);
+               else
+                   retnum =
+                       ((UV) s[offset    ] << 24) +
+                       ((UV) s[offset + 1] << 16) +
+                       (     s[offset + 2] <<  8);
+           }
+#ifdef UV_IS_QUAD
+           else if (size == 64) {
+               dTHR;
+               if (ckWARN(WARN_PORTABLE))
+                   Perl_warner(aTHX_ WARN_PORTABLE,
+                               "Bit vector size > 32 non-portable");
+               if (offset >= srclen)
+                   retnum = 0;
+               else if (offset + 1 >= srclen)
+                   retnum =
+                       (UV) s[offset     ] << 56;
+               else if (offset + 2 >= srclen)
+                   retnum =
+                       ((UV) s[offset    ] << 56) +
+                       ((UV) s[offset + 1] << 48);
+               else if (offset + 3 >= srclen)
+                   retnum =
+                       ((UV) s[offset    ] << 56) +
+                       ((UV) s[offset + 1] << 48) +
+                       ((UV) s[offset + 2] << 40);
+               else if (offset + 4 >= srclen)
+                   retnum =
+                       ((UV) s[offset    ] << 56) +
+                       ((UV) s[offset + 1] << 48) +
+                       ((UV) s[offset + 2] << 40) +
+                       ((UV) s[offset + 3] << 32);
+               else if (offset + 5 >= srclen)
+                   retnum =
+                       ((UV) s[offset    ] << 56) +
+                       ((UV) s[offset + 1] << 48) +
+                       ((UV) s[offset + 2] << 40) +
+                       ((UV) s[offset + 3] << 32) +
+                       (     s[offset + 4] << 24);
+               else if (offset + 6 >= srclen)
+                   retnum =
+                       ((UV) s[offset    ] << 56) +
+                       ((UV) s[offset + 1] << 48) +
+                       ((UV) s[offset + 2] << 40) +
+                       ((UV) s[offset + 3] << 32) +
+                       ((UV) s[offset + 4] << 24) +
+                       ((UV) s[offset + 5] << 16);
+               else
+                   retnum = 
+                       ((UV) s[offset    ] << 56) +
+                       ((UV) s[offset + 1] << 48) +
+                       ((UV) s[offset + 2] << 40) +
+                       ((UV) s[offset + 3] << 32) +
+                       ((UV) s[offset + 4] << 24) +
+                       ((UV) s[offset + 5] << 16) +
+                       (     s[offset + 6] <<  8);
+           }
+#endif
+       }
+    }
+    else if (size < 8)
+       retnum = (s[offset >> 3] >> (offset & 7)) & ((1 << size) - 1);
+    else {
+       offset >>= 3;   /* turn into byte offset */
+       if (size == 8)
+           retnum = s[offset];
+       else if (size == 16)
+           retnum =
+               ((UV) s[offset] <<      8) +
+                     s[offset + 1];
+       else if (size == 32)
+           retnum =
+               ((UV) s[offset    ] << 24) +
+               ((UV) s[offset + 1] << 16) +
+               (     s[offset + 2] <<  8) +
+                     s[offset + 3];
+#ifdef UV_IS_QUAD
+       else if (size == 64) {
+           dTHR;
+           if (ckWARN(WARN_PORTABLE))
+               Perl_warner(aTHX_ WARN_PORTABLE,
+                           "Bit vector size > 32 non-portable");
+           retnum =
+               ((UV) s[offset    ] << 56) +
+               ((UV) s[offset + 1] << 48) +
+               ((UV) s[offset + 2] << 40) +
+               ((UV) s[offset + 3] << 32) +
+               ((UV) s[offset + 4] << 24) +
+               ((UV) s[offset + 5] << 16) +
+               (     s[offset + 6] <<  8) +
+                     s[offset + 7];
+       }
+#endif
+    }
+
+    return retnum;
+}
+
 void
-do_vecset(SV *sv)
+Perl_do_vecset(pTHX_ SV *sv)
 {
     SV *targ = LvTARG(sv);
     register I32 offset;
     register I32 size;
     register unsigned char *s;
-    register unsigned long lval;
+    register UV lval;
     I32 mask;
     STRLEN targlen;
     STRLEN len;
@@ -724,11 +844,14 @@ do_vecset(SV *sv)
     if (!targ)
        return;
     s = (unsigned char*)SvPV_force(targ, targlen);
-    lval = U_L(SvNV(sv));
+    lval = SvUV(sv);
     offset = LvTARGOFF(sv);
     size = LvTARGLEN(sv);
+    if (size < 1 || (size & (size-1))) /* size < 1 or not a power of two */ 
+       Perl_croak(aTHX_ "Illegal number of bits in vec");
     
-    len = (offset + size + 7) / 8;
+    offset *= size;                    /* turn into bit offset */
+    len = (offset + size + 7) / 8;     /* required number of bytes */
     if (len > targlen) {
        s = (unsigned char*)SvGROW(targ, len + 1);
        (void)memzero(s + targlen, len - targlen + 1);
@@ -739,29 +862,46 @@ do_vecset(SV *sv)
        mask = (1 << size) - 1;
        size = offset & 7;
        lval &= mask;
-       offset >>= 3;
+       offset >>= 3;                   /* turn into byte offset */
        s[offset] &= ~(mask << size);
        s[offset] |= lval << size;
     }
     else {
-       offset >>= 3;
+       offset >>= 3;                   /* turn into byte offset */
        if (size == 8)
-           s[offset] = lval & 255;
+           s[offset  ] = lval         & 0xff;
        else if (size == 16) {
-           s[offset] = (lval >> 8) & 255;
-           s[offset+1] = lval & 255;
+           s[offset  ] = (lval >>  8) & 0xff;
+           s[offset+1] = lval         & 0xff;
        }
        else if (size == 32) {
-           s[offset] = (lval >> 24) & 255;
-           s[offset+1] = (lval >> 16) & 255;
-           s[offset+2] = (lval >> 8) & 255;
-           s[offset+3] = lval & 255;
+           s[offset  ] = (lval >> 24) & 0xff;
+           s[offset+1] = (lval >> 16) & 0xff;
+           s[offset+2] = (lval >>  8) & 0xff;
+           s[offset+3] =  lval        & 0xff;
+       }
+#ifdef UV_IS_QUAD
+       else if (size == 64) {
+           dTHR;
+           if (ckWARN(WARN_PORTABLE))
+               Perl_warner(aTHX_ WARN_PORTABLE,
+                           "Bit vector size > 32 non-portable");
+           s[offset  ] = (lval >> 56) & 0xff;
+           s[offset+1] = (lval >> 48) & 0xff;
+           s[offset+2] = (lval >> 40) & 0xff;
+           s[offset+3] = (lval >> 32) & 0xff;
+           s[offset+4] = (lval >> 24) & 0xff;
+           s[offset+5] = (lval >> 16) & 0xff;
+           s[offset+6] = (lval >>  8) & 0xff;
+           s[offset+7] =  lval        & 0xff;
        }
+#endif
     }
+    SvSETMAGIC(targ);
 }
 
 void
-do_chop(register SV *astr, register SV *sv)
+Perl_do_chop(pTHX_ register SV *astr, register SV *sv)
 {
     STRLEN len;
     char *s;
@@ -789,42 +929,43 @@ do_chop(register SV *astr, register SV *sv)
         return;
     }
     else if (SvREADONLY(sv))
-       croak(PL_no_modify);
+       Perl_croak(aTHX_ PL_no_modify);
     s = SvPV(sv, len);
     if (len && !SvPOK(sv))
        s = SvPV_force(sv, len);
-    if (IN_UTF8) {
+    if (DO_UTF8(sv)) {
        if (s && len) {
            char *send = s + len;
            char *start = s;
            s = send - 1;
            while ((*s & 0xc0) == 0x80)
                --s;
-           if (UTF8SKIP(s) != send - s)
-               warn("Malformed UTF-8 character");
+           if (UTF8SKIP(s) != send - s && ckWARN_d(WARN_UTF8))
+               Perl_warner(aTHX_ WARN_UTF8, "Malformed UTF-8 character");
            sv_setpvn(astr, s, send - s);
            *s = '\0';
            SvCUR_set(sv, s - start);
            SvNIOK_off(sv);
+           SvUTF8_on(astr);
        }
        else
            sv_setpvn(astr, "", 0);
     }
-    else
-    if (s && len) {
+    else if (s && len) {
        s += --len;
        sv_setpvn(astr, s, 1);
        *s = '\0';
        SvCUR_set(sv, len);
+       SvUTF8_off(sv);
        SvNIOK_off(sv);
     }
     else
        sv_setpvn(astr, "", 0);
     SvSETMAGIC(sv);
-} 
+}
 
 I32
-do_chomp(register SV *sv)
+Perl_do_chomp(pTHX_ register SV *sv)
 {
     dTHR;
     register I32 count;
@@ -858,7 +999,7 @@ do_chomp(register SV *sv)
         return count;
     }
     else if (SvREADONLY(sv))
-       croak(PL_no_modify);
+       Perl_croak(aTHX_ PL_no_modify);
     s = SvPV(sv, len);
     if (len && !SvPOKp(sv))
        s = SvPV_force(sv, len);
@@ -902,7 +1043,7 @@ do_chomp(register SV *sv)
 } 
 
 void
-do_vop(I32 optype, SV *sv, SV *left, SV *right)
+Perl_do_vop(pTHX_ I32 optype, SV *sv, SV *left, SV *right)
 {
     dTHR;      /* just for taint */
 #ifdef LIBERAL
@@ -919,6 +1060,13 @@ do_vop(I32 optype, SV *sv, SV *left, SV *right)
     I32 lensave;
     char *lsave;
     char *rsave;
+    bool left_utf = DO_UTF8(left);
+    bool right_utf = DO_UTF8(right);
+
+    if (left_utf && !right_utf)
+       sv_utf8_upgrade(right);
+    if (!left_utf && right_utf)
+       sv_utf8_upgrade(left);
 
     if (sv != left || (optype != OP_BIT_AND && !SvOK(sv) && !SvGMAGICAL(sv)))
        sv_setpvn(sv, "", 0);   /* avoid undef warning on |= and ^= */
@@ -943,6 +1091,66 @@ do_vop(I32 optype, SV *sv, SV *left, SV *right)
     }
     SvCUR_set(sv, len);
     (void)SvPOK_only(sv);
+    if (left_utf || right_utf) {
+       UV duc, luc, ruc;
+       STRLEN lulen = leftlen;
+       STRLEN rulen = rightlen;
+       STRLEN dulen = 0;
+       I32 ulen;
+
+       switch (optype) {
+       case OP_BIT_AND:
+           while (lulen && rulen) {
+               luc = utf8_to_uv((U8*)lc, &ulen);
+               lc += ulen;
+               lulen -= ulen;
+               ruc = utf8_to_uv((U8*)rc, &ulen);
+               rc += ulen;
+               rulen -= ulen;
+               duc = luc & ruc;
+               dc = (char*)uv_to_utf8((U8*)dc, duc);
+           }
+           dulen = dc - SvPVX(sv);
+           SvCUR_set(sv, dulen);
+           break;
+       case OP_BIT_XOR:
+           while (lulen && rulen) {
+               luc = utf8_to_uv((U8*)lc, &ulen);
+               lc += ulen;
+               lulen -= ulen;
+               ruc = utf8_to_uv((U8*)rc, &ulen);
+               rc += ulen;
+               rulen -= ulen;
+               duc = luc ^ ruc;
+               dc = (char*)uv_to_utf8((U8*)dc, duc);
+           }
+           goto mop_up_utf;
+       case OP_BIT_OR:
+           while (lulen && rulen) {
+               luc = utf8_to_uv((U8*)lc, &ulen);
+               lc += ulen;
+               lulen -= ulen;
+               ruc = utf8_to_uv((U8*)rc, &ulen);
+               rc += ulen;
+               rulen -= ulen;
+               duc = luc | ruc;
+               dc = (char*)uv_to_utf8((U8*)dc, duc);
+           }
+         mop_up_utf:
+           dulen = dc - SvPVX(sv);
+           SvCUR_set(sv, dulen);
+           if (rulen)
+               sv_catpvn(sv, rc, rulen);
+           else if (lulen)
+               sv_catpvn(sv, lc, lulen);
+           else
+               *SvEND(sv) = '\0';
+           break;
+       }
+       SvUTF8_on(sv);
+       goto finish;
+    }
+    else
 #ifdef LIBERAL
     if (len >= sizeof(long)*4 &&
        !((long)dc % sizeof(long)) &&
@@ -1013,11 +1221,12 @@ do_vop(I32 optype, SV *sv, SV *left, SV *right)
            break;
        }
     }
+finish:
     SvTAINT(sv);
 }
 
 OP *
-do_kv(ARGSproto)
+Perl_do_kv(pTHX)
 {
     djSP;
     HV *hv = (HV*)POPs;
@@ -1089,7 +1298,7 @@ do_kv(ARGSproto)
            PUTBACK;
            tmpstr = realhv ?
                     hv_iterval(hv,entry) : avhv_iterval((AV*)hv,entry);
-           DEBUG_H(sv_setpvf(tmpstr, "%lu%%%d=%lu",
+           DEBUG_H(Perl_sv_setpvf(aTHX_ tmpstr, "%lu%%%d=%lu",
                            (unsigned long)HeHASH(entry),
                            HvMAX(keys)+1,
                            (unsigned long)(HeHASH(entry) & HvMAX(keys))));