fixing eval in the compiler
[p5sagit/p5-mst-13.2.git] / pp.c
diff --git a/pp.c b/pp.c
index 44114e7..1b9ebdd 100644 (file)
--- a/pp.c
+++ b/pp.c
@@ -1,6 +1,6 @@
 /*    pp.c
  *
- *    Copyright (c) 1991-1997, Larry Wall
+ *    Copyright (c) 1991-1999, 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.
@@ -78,6 +78,13 @@ typedef unsigned UBW;
 #define SIZE16 2
 #define SIZE32 4
 
+/* CROSSCOMPILE and MULTIARCH are going to affect pp_pack() and pp_unpack().
+   --jhi Feb 1999 */
+
+#if SHORTSIZE != SIZE16 || LONGSIZE != SIZE32
+#   define PERL_NATINT_PACK
+#endif
+
 #if BYTEORDER > 0xFFFF && defined(_CRAY) && !defined(_CRAYMPP)
 #  if BYTEORDER == 0x12345678
 #    define OFF16(p)   (char*)(p)
@@ -92,11 +99,13 @@ typedef unsigned UBW;
 #  endif
 #  define COPY16(s,p)  (*(p) = 0, Copy(s, OFF16(p), SIZE16, char))
 #  define COPY32(s,p)  (*(p) = 0, Copy(s, OFF32(p), SIZE32, char))
+#  define COPYNN(s,p,n) (*(p) = 0, Copy(s, (char *)(p), n, char))
 #  define CAT16(sv,p)  sv_catpvn(sv, OFF16(p), SIZE16)
 #  define CAT32(sv,p)  sv_catpvn(sv, OFF32(p), SIZE32)
 #else
 #  define COPY16(s,p)  Copy(s, p, SIZE16, char)
 #  define COPY32(s,p)  Copy(s, p, SIZE32, char)
+#  define COPYNN(s,p,n) Copy(s, (char *)(p), n, char)
 #  define CAT16(sv,p)  sv_catpvn(sv, (char*)(p), SIZE16)
 #  define CAT32(sv,p)  sv_catpvn(sv, (char*)(p), SIZE32)
 #endif
@@ -107,8 +116,6 @@ static SV* refto _((SV* sv));
 static U32 seed _((void));
 #endif
 
-static bool srand_called = FALSE;
-
 /* variations on pp_null */
 
 #ifdef I_UNISTD
@@ -207,7 +214,7 @@ PP(pp_padany)
 
 PP(pp_rv2gv)
 {
-    djSP; dTOPss;
+    djSP; dTOPss;  
 
     if (SvROK(sv)) {
       wasref:
@@ -220,7 +227,8 @@ PP(pp_rv2gv)
            GvIOp(gv) = (IO *)sv;
            (void)SvREFCNT_inc(sv);
            sv = (SV*) gv;
-       } else if (SvTYPE(sv) != SVt_PVGV)
+       }
+       else if (SvTYPE(sv) != SVt_PVGV)
            DIE("Not a GLOB reference");
     }
     else {
@@ -234,6 +242,24 @@ PP(pp_rv2gv)
                    goto wasref;
            }
            if (!SvOK(sv)) {
+               /* If this is a 'my' scalar and flag is set then vivify 
+                * NI-S 1999/05/07
+                */ 
+               if (PL_op->op_private & OPpDEREF) {
+                   GV *gv = (GV *) newSV(0);
+                   STRLEN len = 0;
+                   char *name = "";
+                   if (cUNOP->op_first->op_type == OP_PADSV) {
+                       SV *padname = *av_fetch(PL_comppad_name, cUNOP->op_first->op_targ, 4);
+                       name = SvPV(padname,len);                                                    
+                   }
+                   gv_init(gv, PL_curcop->cop_stash, name, len, 0);
+                   sv_upgrade(sv, SVt_RV);
+                   SvRV(sv) = (SV *) gv;
+                   SvROK_on(sv);
+                   SvSETMAGIC(sv);
+                   goto wasref;
+               }  
                if (PL_op->op_flags & OPf_REF ||
                    PL_op->op_private & HINT_STRICT_REFS)
                    DIE(PL_no_usym, "a symbol");
@@ -242,9 +268,18 @@ PP(pp_rv2gv)
                RETSETUNDEF;
            }
            sym = SvPV(sv, n_a);
-           if (PL_op->op_private & HINT_STRICT_REFS)
-               DIE(PL_no_symref, sym, "a symbol");
-           sv = (SV*)gv_fetchpv(sym, TRUE, SVt_PVGV);
+           if ((PL_op->op_flags & OPf_SPECIAL) &&
+               !(PL_op->op_flags & OPf_MOD))
+           {
+               sv = (SV*)gv_fetchpv(sym, FALSE, SVt_PVGV);
+               if (!sv)
+                   RETSETUNDEF;
+           }
+           else {
+               if (PL_op->op_private & HINT_STRICT_REFS)
+                   DIE(PL_no_symref, sym, "a symbol");
+               sv = (SV*)gv_fetchpv(sym, TRUE, SVt_PVGV);
+           }
        }
     }
     if (PL_op->op_private & OPpLVAL_INTRO)
@@ -289,9 +324,18 @@ PP(pp_rv2sv)
                RETSETUNDEF;
            }
            sym = SvPV(sv, n_a);
-           if (PL_op->op_private & HINT_STRICT_REFS)
-               DIE(PL_no_symref, sym, "a SCALAR");
-           gv = (GV*)gv_fetchpv(sym, TRUE, SVt_PV);
+           if ((PL_op->op_flags & OPf_SPECIAL) &&
+               !(PL_op->op_flags & OPf_MOD))
+           {
+               gv = (GV*)gv_fetchpv(sym, FALSE, SVt_PV);
+               if (!gv)
+                   RETSETUNDEF;
+           }
+           else {
+               if (PL_op->op_private & HINT_STRICT_REFS)
+                   DIE(PL_no_symref, sym, "a SCALAR");
+               gv = (GV*)gv_fetchpv(sym, TRUE, SVt_PV);
+           }
        }
        sv = GvSV(gv);
     }
@@ -410,7 +454,8 @@ PP(pp_prototype)
                    if (oa & OA_OPTIONAL) {
                        seen_question = 1;
                        str[n++] = ';';
-                   } else if (seen_question) 
+                   }
+                   else if (seen_question) 
                        goto set;       /* XXXX system, exec */
                    if ((oa & (OA_OPTIONAL - 1)) >= OA_AVREF 
                        && (oa & (OA_OPTIONAL - 1)) <= OA_HVREF) {
@@ -421,18 +466,19 @@ PP(pp_prototype)
                    oa = oa >> 4;
                }
                str[n++] = '\0';
-               ret = sv_2mortal(newSVpv(str, n - 1));
-           } else if (code)            /* Non-Overridable */
+               ret = sv_2mortal(newSVpvn(str, n - 1));
+           }
+           else if (code)              /* Non-Overridable */
                goto set;
            else {                      /* None such */
              nonesuch:
-               croak("Cannot find an opnumber for \"%s\"", s+6);
+               croak("Can't find an opnumber for \"%s\"", s+6);
            }
        }
     }
     cv = sv_2cv(TOPs, &stash, &gv, FALSE);
     if (cv && SvPOK(cv))
-       ret = sv_2mortal(newSVpv(SvPVX(cv), SvCUR(cv)));
+       ret = sv_2mortal(newSVpvn(SvPVX(cv), SvCUR(cv)));
   set:
     SETs(ret);
     RETURN;
@@ -484,6 +530,8 @@ refto(SV *sv)
            vivify_defelem(sv);
        if (!(sv = LvTARG(sv)))
            sv = &PL_sv_undef;
+       else
+           (void)SvREFCNT_inc(sv);
     }
     else if (SvPADTMP(sv))
        sv = newSVsv(sv);
@@ -581,7 +629,7 @@ PP(pp_gelem)
        break;
     case 'N':
        if (strEQ(elem, "NAME"))
-           sv = newSVpv(GvNAME(gv), GvNAMELEN(gv));
+           sv = newSVpvn(GvNAME(gv), GvNAMELEN(gv));
        break;
     case 'P':
        if (strEQ(elem, "PACKAGE"))
@@ -607,7 +655,6 @@ PP(pp_gelem)
 PP(pp_study)
 {
     djSP; dPOPss;
-    register UNOP *unop = cUNOP;
     register unsigned char *s;
     register I32 pos;
     register I32 ch;
@@ -764,15 +811,8 @@ PP(pp_undef)
     if (!sv)
        RETPUSHUNDEF;
 
-    if (SvTHINKFIRST(sv)) {
-       if (SvREADONLY(sv)) {
-           dTHR;
-           if (PL_curcop != &PL_compiling)
-               croak(PL_no_modify);
-       }
-       if (SvROK(sv))
-           sv_unref(sv);
-    }
+    if (SvTHINKFIRST(sv))
+       sv_force_normal(sv);
 
     switch (SvTYPE(sv)) {
     case SVt_NULL:
@@ -789,9 +829,12 @@ PP(pp_undef)
                 CvANON((CV*)sv) ? "(anonymous)" : GvENAME(CvGV((CV*)sv)));
        /* FALL THROUGH */
     case SVt_PVFM:
-       { GV* gv = (GV*)SvREFCNT_inc(CvGV((CV*)sv));
-         cv_undef((CV*)sv);
-         CvGV((CV*)sv) = gv; }   /* let user-undef'd sub keep its identity */
+       {
+           /* let user-undef'd sub keep its identity */
+           GV* gv = (GV*)SvREFCNT_inc(CvGV((CV*)sv));
+           cv_undef((CV*)sv);
+           CvGV((CV*)sv) = gv;
+       }
        break;
     case SVt_PVGV:
        if (SvFAKE(sv))
@@ -826,7 +869,7 @@ PP(pp_predec)
     djSP;
     if (SvREADONLY(TOPs) || SvTYPE(TOPs) > SVt_PVLV)
        croak(PL_no_modify);
-    if (SvIOK(TOPs) && !SvNOK(TOPs) && !SvPOK(TOPs) &&
+    if (SvIOK_notUV(TOPs) && !SvNOK(TOPs) && !SvPOK(TOPs) &&
        SvIVX(TOPs) != IV_MIN)
     {
        --SvIVX(TOPs);
@@ -844,7 +887,7 @@ PP(pp_postinc)
     if (SvREADONLY(TOPs) || SvTYPE(TOPs) > SVt_PVLV)
        croak(PL_no_modify);
     sv_setsv(TARG, TOPs);
-    if (SvIOK(TOPs) && !SvNOK(TOPs) && !SvPOK(TOPs) &&
+    if (SvIOK_notUV(TOPs) && !SvNOK(TOPs) && !SvPOK(TOPs) &&
        SvIVX(TOPs) != IV_MAX)
     {
        ++SvIVX(TOPs);
@@ -865,7 +908,7 @@ PP(pp_postdec)
     if(SvREADONLY(TOPs) || SvTYPE(TOPs) > SVt_PVLV)
        croak(PL_no_modify);
     sv_setsv(TARG, TOPs);
-    if (SvIOK(TOPs) && !SvNOK(TOPs) && !SvPOK(TOPs) &&
+    if (SvIOK_notUV(TOPs) && !SvNOK(TOPs) && !SvPOK(TOPs) &&
        SvIVX(TOPs) != IV_MIN)
     {
        --SvIVX(TOPs);
@@ -916,7 +959,8 @@ PP(pp_divide)
            (double)I_V(right) == right &&
            (k = I_V(left)/I_V(right))*I_V(right) == I_V(left)) {
            value = k;
-       } else {
+       }
+       else {
            value = left / right;
        }
       }
@@ -932,48 +976,99 @@ PP(pp_modulo)
 {
     djSP; dATARGET; tryAMAGICbin(modulo,opASSIGN);
     {
-      UV left;
-      UV right;
-      bool left_neg;
-      bool right_neg;
-      UV ans;
-
-      if (SvIOK(TOPs) && !SvNOK(TOPs) && !SvPOK(TOPs)) {
-       IV i = SvIVX(POPs);
-       right = (right_neg = (i < 0)) ? -i : i;
-      }
-      else {
-       double n = POPn;
-       right = U_V((right_neg = (n < 0)) ? -n : n);
-      }
+       UV left;
+       UV right;
+       bool left_neg;
+       bool right_neg;
+       bool use_double = 0;
+       double dright;
+       double dleft;
+
+       if (SvIOK(TOPs) && !SvNOK(TOPs) && !SvPOK(TOPs)) {
+           IV i = SvIVX(POPs);
+           right = (right_neg = (i < 0)) ? -i : i;
+       }
+       else {
+           dright = POPn;
+           use_double = 1;
+           right_neg = dright < 0;
+           if (right_neg)
+               dright = -dright;
+       }
 
-      if (SvIOK(TOPs) && !SvNOK(TOPs) && !SvPOK(TOPs)) {
-       IV i = SvIVX(POPs);
-       left = (left_neg = (i < 0)) ? -i : i;
-      }
-      else {
-       double n = POPn;
-       left = U_V((left_neg = (n < 0)) ? -n : n);
-      }
+       if (!use_double && SvIOK(TOPs) && !SvNOK(TOPs) && !SvPOK(TOPs)) {
+           IV i = SvIVX(POPs);
+           left = (left_neg = (i < 0)) ? -i : i;
+       }
+       else {
+           dleft = POPn;
+           if (!use_double) {
+               use_double = 1;
+               dright = right;
+           }
+           left_neg = dleft < 0;
+           if (left_neg)
+               dleft = -dleft;
+       }
 
-      if (!right)
-       DIE("Illegal modulus zero");
+       if (use_double) {
+           double dans;
 
-      ans = left % right;
-      if ((left_neg != right_neg) && ans)
-       ans = right - ans;
-      if (right_neg) {
-       /* 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);
-      }
-      else
-       sv_setuv(TARG, ans);
-      PUSHTARG;
-      RETURN;
+#if 1
+/* Somehow U_V is pessimized even if CASTFLAGS is 0 */
+#  if CASTFLAGS & 2
+#    define CAST_D2UV(d) U_V(d)
+#  else
+#    define CAST_D2UV(d) ((UV)(d))
+#  endif
+           /* Tried to do this only in the case DOUBLESIZE <= UV_SIZE,
+            * or, in other words, precision of UV more than of NV.
+            * But in fact the approach below turned out to be an
+            * optimization - floor() may be slow */
+           if (dright <= UV_MAX && dleft <= UV_MAX) {
+               right = CAST_D2UV(dright);
+               left  = CAST_D2UV(dleft);
+               goto do_uv;
+           }
+#endif
+
+           /* Backward-compatibility clause: */
+           dright = floor(dright + 0.5);
+           dleft  = floor(dleft + 0.5);
+
+           if (!dright)
+               DIE("Illegal modulus zero");
+
+           dans = fmod(dleft, dright);
+           if ((left_neg != right_neg) && dans)
+               dans = dright - dans;
+           if (right_neg)
+               dans = -dans;
+           sv_setnv(TARG, dans);
+       }
+       else {
+           UV ans;
+
+       do_uv:
+           if (!right)
+               DIE("Illegal modulus zero");
+
+           ans = left % right;
+           if ((left_neg != right_neg) && ans)
+               ans = right - ans;
+           if (right_neg) {
+               /* 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);
+           }
+           else
+               sv_setuv(TARG, ans);
+       }
+       PUSHTARG;
+       RETURN;
     }
 }
 
@@ -1008,12 +1103,6 @@ PP(pp_repeat)
        STRLEN len;
 
        tmpstr = POPs;
-       if (TARG == tmpstr && SvTHINKFIRST(tmpstr)) {
-           if (SvREADONLY(tmpstr) && PL_curcop != &PL_compiling)
-               DIE("Can't x= to readonly value");
-           if (SvROK(tmpstr))
-               sv_unref(tmpstr);
-       }
        SvSetSV(TARG, tmpstr);
        SvPV_force(TARG, len);
        if (count != 1) {
@@ -1345,9 +1434,7 @@ PP(pp_negate)
 
 PP(pp_not)
 {
-#ifdef OVERLOAD
     djSP; tryAMAGICunSET(not);
-#endif /* OVERLOAD */
     *PL_stack_sp = boolSV(!SvTRUE(*PL_stack_sp));
     return NORMAL;
 }
@@ -1596,9 +1683,9 @@ PP(pp_rand)
        value = POPn;
     if (value == 0.0)
        value = 1.0;
-    if (!srand_called) {
+    if (!PL_srand_called) {
        (void)seedDrand01((Rand_seed_t)seed());
-       srand_called = TRUE;
+       PL_srand_called = TRUE;
     }
     value *= Drand01();
     XPUSHn(value);
@@ -1614,7 +1701,7 @@ PP(pp_srand)
     else
        anum = POPu;
     (void)seedDrand01((Rand_seed_t)anum);
-    srand_called = TRUE;
+    PL_srand_called = TRUE;
     EXTEND(SP, 1);
     RETPUSHYES;
 }
@@ -2638,10 +2725,12 @@ PP(pp_exists)
     if (SvTYPE(hv) == SVt_PVHV) {
        if (hv_exists_ent(hv, tmpsv, 0))
            RETPUSHYES;
-    } else if (SvTYPE(hv) == SVt_PVAV) {
+    }
+    else if (SvTYPE(hv) == SVt_PVAV) {
        if (avhv_exists_ent((AV*)hv, tmpsv, 0))
            RETPUSHYES;
-    } else {
+    }
+    else {
        DIE("Not a HASH reference");
     }
     RETPUSHNO;
@@ -2664,7 +2753,8 @@ PP(pp_hslice)
            if (realhv) {
                HE *he = hv_fetch_ent(hv, keysv, lval, 0);
                svp = he ? &HeVAL(he) : 0;
-           } else {
+           }
+           else {
                svp = avhv_fetch_ent((AV*)hv, keysv, lval, 0);
            }
            if (lval) {
@@ -2737,20 +2827,17 @@ PP(pp_lslice)
 
     for (lelem = firstlelem; lelem <= lastlelem; lelem++) {
        ix = SvIVx(*lelem);
-       if (ix < 0) {
+       if (ix < 0)
            ix += max;
-           if (ix < 0)
-               *lelem = &PL_sv_undef;
-           else if (!(*lelem = firstrelem[ix]))
-               *lelem = &PL_sv_undef;
-       }
-       else {
+       else 
            ix -= arybase;
-           if (ix >= max || !(*lelem = firstrelem[ix]))
+       if (ix < 0 || ix >= max)
+           *lelem = &PL_sv_undef;
+       else {
+           is_something_there = TRUE;
+           if (!(*lelem = firstrelem[ix]))
                *lelem = &PL_sv_undef;
        }
-       if (!is_something_there && (SvOK(*lelem) || SvGMAGICAL(*lelem)))
-           is_something_there = TRUE;
     }
     if (is_something_there)
        SP = lastlelem;
@@ -2853,12 +2940,8 @@ 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 (newlen && !AvREAL(ary) && AvREIFY(ary))
+       av_reify(ary);
 
     if (diff < 0) {                            /* shrinking the area */
        if (newlen) {
@@ -3155,7 +3238,7 @@ mul128(SV *sv, U8 m)
   U32             i = 0;
 
   if (!strnEQ(s, "0000", 4)) {  /* need to grow sv */
-    SV             *tmpNew = newSVpv("0000000000", 10);
+    SV             *tmpNew = newSVpvn("0000000000", 10);
 
     sv_catsv(tmpNew, sv);
     SvREFCNT_dec(sv);          /* free old sv */
@@ -3175,9 +3258,6 @@ mul128(SV *sv, U8 m)
 
 /* Explosives and implosives. */
 
-static const char uuemap[] =
-    "`!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_";
-static char uudmap[256];        /* Initialised on first use */
 #if 'I' == 73 && 'J' == 74
 /* On an ASCII/ISO kind of system */
 #define ISUUCHAR(ch)    ((ch) >= ' ' && (ch) < 'a')
@@ -3186,7 +3266,7 @@ static char uudmap[256];        /* Initialised on first use */
   Some other sort of character set - use memchr() so we don't match
   the null byte.
  */
-#define ISUUCHAR(ch)    (memchr(uuemap, (ch), sizeof(uuemap)-1) || (ch) == ' ')
+#define ISUUCHAR(ch)    (memchr(PL_uuemap, (ch), sizeof(PL_uuemap)-1) || (ch) == ' ')
 #endif
 
 PP(pp_unpack)
@@ -3226,13 +3306,16 @@ PP(pp_unpack)
     I32 checksum = 0;
     register U32 culong;
     double cdouble;
-    static char* bitcount = 0;
     int commas = 0;
+#ifdef PERL_NATINT_PACK
+    int natint;                /* native integer */
+    int unatint;       /* unsigned native integer */
+#endif
 
     if (gimme != G_ARRAY) {            /* arrange to do first one only */
        /*SUPPRESS 530*/
        for (patend = pat; !isALPHA(*patend) || *patend == 'x'; patend++) ;
-       if (strchr("aAbBhHP", *patend) || *pat == '%') {
+       if (strchr("aAZbBhHP", *patend) || *pat == '%') {
            patend++;
            while (isDIGIT(*patend) || *patend == '*')
                patend++;
@@ -3243,8 +3326,23 @@ PP(pp_unpack)
     while (pat < patend) {
       reparse:
        datumtype = *pat++ & 0xFF;
+#ifdef PERL_NATINT_PACK
+       natint = 0;
+#endif
        if (isSPACE(datumtype))
            continue;
+       if (*pat == '!') {
+           char *natstr = "sSiIlL";
+
+           if (strchr(natstr, datumtype)) {
+#ifdef PERL_NATINT_PACK
+               natint = 1;
+#endif
+               pat++;
+           }
+           else
+               croak("'!' allowed only after types %s", natstr);
+       }
        if (pat >= patend)
            len = 1;
        else if (*pat == '*') {
@@ -3290,6 +3388,7 @@ PP(pp_unpack)
            s += len;
            break;
        case 'A':
+       case 'Z':
        case 'a':
            if (len > strend - s)
                len = strend - s;
@@ -3298,12 +3397,19 @@ PP(pp_unpack)
            sv = NEWSV(35, len);
            sv_setpvn(sv, s, len);
            s += len;
-           if (datumtype == 'A') {
+           if (datumtype == 'A' || datumtype == 'Z') {
                aptr = s;       /* borrow register */
-               s = SvPVX(sv) + len - 1;
-               while (s >= SvPVX(sv) && (!*s || isSPACE(*s)))
-                   s--;
-               *++s = '\0';
+               if (datumtype == 'Z') { /* 'Z' strips stuff after first null */
+                   s = SvPVX(sv);
+                   while (*s)
+                       s++;
+               }
+               else {          /* 'A' strips both nulls and spaces */
+                   s = SvPVX(sv) + len - 1;
+                   while (s >= SvPVX(sv) && (!*s || isSPACE(*s)))
+                       s--;
+                   *++s = '\0';
+               }
                SvCUR_set(sv, s - SvPVX(sv));
                s = aptr;       /* unborrow register */
            }
@@ -3314,21 +3420,21 @@ PP(pp_unpack)
            if (pat[-1] == '*' || len > (strend - s) * 8)
                len = (strend - s) * 8;
            if (checksum) {
-               if (!bitcount) {
-                   Newz(601, bitcount, 256, char);
+               if (!PL_bitcount) {
+                   Newz(601, PL_bitcount, 256, char);
                    for (bits = 1; bits < 256; bits++) {
-                       if (bits & 1)   bitcount[bits]++;
-                       if (bits & 2)   bitcount[bits]++;
-                       if (bits & 4)   bitcount[bits]++;
-                       if (bits & 8)   bitcount[bits]++;
-                       if (bits & 16)  bitcount[bits]++;
-                       if (bits & 32)  bitcount[bits]++;
-                       if (bits & 64)  bitcount[bits]++;
-                       if (bits & 128) bitcount[bits]++;
+                       if (bits & 1)   PL_bitcount[bits]++;
+                       if (bits & 2)   PL_bitcount[bits]++;
+                       if (bits & 4)   PL_bitcount[bits]++;
+                       if (bits & 8)   PL_bitcount[bits]++;
+                       if (bits & 16)  PL_bitcount[bits]++;
+                       if (bits & 32)  PL_bitcount[bits]++;
+                       if (bits & 64)  PL_bitcount[bits]++;
+                       if (bits & 128) PL_bitcount[bits]++;
                    }
                }
                while (len >= 8) {
-                   culong += bitcount[*(unsigned char*)s++];
+                   culong += PL_bitcount[*(unsigned char*)s++];
                    len -= 8;
                }
                if (len) {
@@ -3481,66 +3587,136 @@ PP(pp_unpack)
            }
            break;
        case 's':
+#if SHORTSIZE == SIZE16
            along = (strend - s) / SIZE16;
+#else
+           along = (strend - s) / (natint ? sizeof(short) : SIZE16);
+#endif
            if (len > along)
                len = along;
            if (checksum) {
-               while (len-- > 0) {
-                   COPY16(s, &ashort);
-                   s += SIZE16;
-                   culong += ashort;
+#if SHORTSIZE != SIZE16
+               if (natint) {
+                   while (len-- > 0) {
+                       COPYNN(s, &ashort, sizeof(short));
+                       s += sizeof(short);
+                       culong += ashort;
+
+                   }
+               }
+               else
+#endif
+                {
+                   while (len-- > 0) {
+                       COPY16(s, &ashort);
+#if SHORTSIZE > SIZE16
+                       if (ashort > 32767)
+                         ashort -= 65536;
+#endif
+                       s += SIZE16;
+                       culong += ashort;
+                   }
                }
            }
            else {
                EXTEND(SP, len);
                EXTEND_MORTAL(len);
-               while (len-- > 0) {
-                   COPY16(s, &ashort);
-                   s += SIZE16;
-                   sv = NEWSV(38, 0);
-                   sv_setiv(sv, (IV)ashort);
-                   PUSHs(sv_2mortal(sv));
+#if SHORTSIZE != SIZE16
+               if (natint) {
+                   while (len-- > 0) {
+                       COPYNN(s, &ashort, sizeof(short));
+                       s += sizeof(short);
+                       sv = NEWSV(38, 0);
+                       sv_setiv(sv, (IV)ashort);
+                       PUSHs(sv_2mortal(sv));
+                   }
+               }
+               else
+#endif
+                {
+                   while (len-- > 0) {
+                       COPY16(s, &ashort);
+#if SHORTSIZE > SIZE16
+                       if (ashort > 32767)
+                         ashort -= 65536;
+#endif
+                       s += SIZE16;
+                       sv = NEWSV(38, 0);
+                       sv_setiv(sv, (IV)ashort);
+                       PUSHs(sv_2mortal(sv));
+                   }
                }
            }
            break;
        case 'v':
        case 'n':
        case 'S':
+#if SHORTSIZE == SIZE16
            along = (strend - s) / SIZE16;
+#else
+           unatint = natint && datumtype == 'S';
+           along = (strend - s) / (unatint ? sizeof(unsigned short) : SIZE16);
+#endif
            if (len > along)
                len = along;
            if (checksum) {
-               while (len-- > 0) {
-                   COPY16(s, &aushort);
-                   s += SIZE16;
+#if SHORTSIZE != SIZE16
+               if (unatint) {
+                   while (len-- > 0) {
+                       COPYNN(s, &aushort, sizeof(unsigned short));
+                       s += sizeof(unsigned short);
+                       culong += aushort;
+                   }
+               }
+               else
+#endif
+                {
+                   while (len-- > 0) {
+                       COPY16(s, &aushort);
+                       s += SIZE16;
 #ifdef HAS_NTOHS
-                   if (datumtype == 'n')
-                       aushort = PerlSock_ntohs(aushort);
+                       if (datumtype == 'n')
+                           aushort = PerlSock_ntohs(aushort);
 #endif
 #ifdef HAS_VTOHS
-                   if (datumtype == 'v')
-                       aushort = vtohs(aushort);
+                       if (datumtype == 'v')
+                           aushort = vtohs(aushort);
 #endif
-                   culong += aushort;
+                       culong += aushort;
+                   }
                }
            }
            else {
                EXTEND(SP, len);
                EXTEND_MORTAL(len);
-               while (len-- > 0) {
-                   COPY16(s, &aushort);
-                   s += SIZE16;
-                   sv = NEWSV(39, 0);
+#if SHORTSIZE != SIZE16
+               if (unatint) {
+                   while (len-- > 0) {
+                       COPYNN(s, &aushort, sizeof(unsigned short));
+                       s += sizeof(unsigned short);
+                       sv = NEWSV(39, 0);
+                       sv_setiv(sv, (UV)aushort);
+                       PUSHs(sv_2mortal(sv));
+                   }
+               }
+               else
+#endif
+                {
+                   while (len-- > 0) {
+                       COPY16(s, &aushort);
+                       s += SIZE16;
+                       sv = NEWSV(39, 0);
 #ifdef HAS_NTOHS
-                   if (datumtype == 'n')
-                       aushort = PerlSock_ntohs(aushort);
+                       if (datumtype == 'n')
+                           aushort = PerlSock_ntohs(aushort);
 #endif
 #ifdef HAS_VTOHS
-                   if (datumtype == 'v')
-                       aushort = vtohs(aushort);
+                       if (datumtype == 'v')
+                           aushort = vtohs(aushort);
 #endif
-                   sv_setiv(sv, (IV)aushort);
-                   PUSHs(sv_2mortal(sv));
+                       sv_setiv(sv, (UV)aushort);
+                       PUSHs(sv_2mortal(sv));
+                   }
                }
            }
            break;
@@ -3568,7 +3744,25 @@ PP(pp_unpack)
 #ifdef __osf__
                     /* Without the dummy below unpack("i", pack("i",-1))
                      * return 0xFFffFFff instead of -1 for Digital Unix V4.0
-                     * cc with optimization turned on */
+                     * cc with optimization turned on.
+                    *
+                    * The bug was detected in
+                    * DEC C V5.8-009 on Digital UNIX V4.0 (Rev. 1091) (V4.0E)
+                    * with optimization (-O4) turned on.
+                    * DEC C V5.2-040 on Digital UNIX V4.0 (Rev. 564) (V4.0B)
+                    * does not have this problem even with -O4.
+                    *
+                    * This bug was reported as DECC_BUGS 1431
+                    * and tracked internally as GEM_BUGS 7775.
+                    *
+                    * The bug is fixed in
+                    * Tru64 UNIX V5.0:      Compaq C V6.1-006 or later
+                    * UNIX V4.0F support:   DEC C V5.9-006 or later
+                    * UNIX V4.0E support:   DEC C V5.8-011 or later
+                    * and also in DTK.
+                    *
+                    * See also few lines later for the same bug.
+                    */
                     (aint) ?
                        sv_setiv(sv, (IV)aint) :
 #endif
@@ -3598,78 +3792,160 @@ PP(pp_unpack)
                    Copy(s, &auint, 1, unsigned int);
                    s += sizeof(unsigned int);
                    sv = NEWSV(41, 0);
+#ifdef __osf__
+                    /* Without the dummy below unpack("I", pack("I",0xFFFFFFFF))
+                     * returns 1.84467440737096e+19 instead of 0xFFFFFFFF.
+                    * See details few lines earlier. */
+                    (auint) ?
+                       sv_setuv(sv, (UV)auint) :
+#endif
                    sv_setuv(sv, (UV)auint);
                    PUSHs(sv_2mortal(sv));
                }
            }
            break;
        case 'l':
+#if LONGSIZE == SIZE32
            along = (strend - s) / SIZE32;
+#else
+           along = (strend - s) / (natint ? sizeof(long) : SIZE32);
+#endif
            if (len > along)
                len = along;
            if (checksum) {
-               while (len-- > 0) {
-                   COPY32(s, &along);
-                   s += SIZE32;
-                   if (checksum > 32)
-                       cdouble += (double)along;
-                   else
-                       culong += along;
+#if LONGSIZE != SIZE32
+               if (natint) {
+                   while (len-- > 0) {
+                       COPYNN(s, &along, sizeof(long));
+                       s += sizeof(long);
+                       if (checksum > 32)
+                           cdouble += (double)along;
+                       else
+                           culong += along;
+                   }
+               }
+               else
+#endif
+                {
+                   while (len-- > 0) {
+                       COPY32(s, &along);
+#if LONGSIZE > SIZE32
+                       if (along > 2147483647)
+                         along -= 4294967296;
+#endif
+                       s += SIZE32;
+                       if (checksum > 32)
+                           cdouble += (double)along;
+                       else
+                           culong += along;
+                   }
                }
            }
            else {
                EXTEND(SP, len);
                EXTEND_MORTAL(len);
-               while (len-- > 0) {
-                   COPY32(s, &along);
-                   s += SIZE32;
-                   sv = NEWSV(42, 0);
-                   sv_setiv(sv, (IV)along);
-                   PUSHs(sv_2mortal(sv));
+#if LONGSIZE != SIZE32
+               if (natint) {
+                   while (len-- > 0) {
+                       COPYNN(s, &along, sizeof(long));
+                       s += sizeof(long);
+                       sv = NEWSV(42, 0);
+                       sv_setiv(sv, (IV)along);
+                       PUSHs(sv_2mortal(sv));
+                   }
+               }
+               else
+#endif
+                {
+                   while (len-- > 0) {
+                       COPY32(s, &along);
+#if LONGSIZE > SIZE32
+                       if (along > 2147483647)
+                         along -= 4294967296;
+#endif
+                       s += SIZE32;
+                       sv = NEWSV(42, 0);
+                       sv_setiv(sv, (IV)along);
+                       PUSHs(sv_2mortal(sv));
+                   }
                }
            }
            break;
        case 'V':
        case 'N':
        case 'L':
+#if LONGSIZE == SIZE32
            along = (strend - s) / SIZE32;
+#else
+           unatint = natint && datumtype == 'L';
+           along = (strend - s) / (unatint ? sizeof(unsigned long) : SIZE32);
+#endif
            if (len > along)
                len = along;
            if (checksum) {
-               while (len-- > 0) {
-                   COPY32(s, &aulong);
-                   s += SIZE32;
+#if LONGSIZE != SIZE32
+               if (unatint) {
+                   while (len-- > 0) {
+                       COPYNN(s, &aulong, sizeof(unsigned long));
+                       s += sizeof(unsigned long);
+                       if (checksum > 32)
+                           cdouble += (double)aulong;
+                       else
+                           culong += aulong;
+                   }
+               }
+               else
+#endif
+                {
+                   while (len-- > 0) {
+                       COPY32(s, &aulong);
+                       s += SIZE32;
 #ifdef HAS_NTOHL
-                   if (datumtype == 'N')
-                       aulong = PerlSock_ntohl(aulong);
+                       if (datumtype == 'N')
+                           aulong = PerlSock_ntohl(aulong);
 #endif
 #ifdef HAS_VTOHL
-                   if (datumtype == 'V')
-                       aulong = vtohl(aulong);
+                       if (datumtype == 'V')
+                           aulong = vtohl(aulong);
 #endif
-                   if (checksum > 32)
-                       cdouble += (double)aulong;
-                   else
-                       culong += aulong;
+                       if (checksum > 32)
+                           cdouble += (double)aulong;
+                       else
+                           culong += aulong;
+                   }
                }
            }
            else {
                EXTEND(SP, len);
                EXTEND_MORTAL(len);
-               while (len-- > 0) {
-                   COPY32(s, &aulong);
-                   s += SIZE32;
+#if LONGSIZE != SIZE32
+               if (unatint) {
+                   while (len-- > 0) {
+                       COPYNN(s, &aulong, sizeof(unsigned long));
+                       s += sizeof(unsigned long);
+                       sv = NEWSV(43, 0);
+                       sv_setuv(sv, (UV)aulong);
+                       PUSHs(sv_2mortal(sv));
+                   }
+               }
+               else
+#endif
+                {
+                   while (len-- > 0) {
+                       COPY32(s, &aulong);
+                       s += SIZE32;
 #ifdef HAS_NTOHL
-                   if (datumtype == 'N')
-                       aulong = PerlSock_ntohl(aulong);
+                       if (datumtype == 'N')
+                           aulong = PerlSock_ntohl(aulong);
 #endif
 #ifdef HAS_VTOHL
-                   if (datumtype == 'V')
-                       aulong = vtohl(aulong);
+                       if (datumtype == 'V')
+                           aulong = vtohl(aulong);
 #endif
-                   sv = NEWSV(43, 0);
-                   sv_setuv(sv, (UV)aulong);
-                   PUSHs(sv_2mortal(sv));
+                       sv = NEWSV(43, 0);
+                       sv_setuv(sv, (UV)aulong);
+                       PUSHs(sv_2mortal(sv));
+                   }
                }
            }
            break;
@@ -3846,16 +4122,16 @@ PP(pp_unpack)
              * algorithm, the code will be character-set independent
              * (and just as fast as doing character arithmetic)
              */
-            if (uudmap['M'] == 0) {
+            if (PL_uudmap['M'] == 0) {
                 int i;
  
-                for (i = 0; i < sizeof(uuemap); i += 1)
-                    uudmap[uuemap[i]] = i;
+                for (i = 0; i < sizeof(PL_uuemap); i += 1)
+                    PL_uudmap[PL_uuemap[i]] = i;
                 /*
                  * Because ' ' and '`' map to the same value,
                  * we need to decode them both the same.
                  */
-                uudmap[' '] = 0;
+                PL_uudmap[' '] = 0;
             }
 
            along = (strend - s) * 3 / 4;
@@ -3867,22 +4143,22 @@ PP(pp_unpack)
                char hunk[4];
 
                hunk[3] = '\0';
-               len = uudmap[*s++] & 077;
+               len = PL_uudmap[*s++] & 077;
                while (len > 0) {
                    if (s < strend && ISUUCHAR(*s))
-                       a = uudmap[*s++] & 077;
+                       a = PL_uudmap[*s++] & 077;
                    else
                        a = 0;
                    if (s < strend && ISUUCHAR(*s))
-                       b = uudmap[*s++] & 077;
+                       b = PL_uudmap[*s++] & 077;
                    else
                        b = 0;
                    if (s < strend && ISUUCHAR(*s))
-                       c = uudmap[*s++] & 077;
+                       c = PL_uudmap[*s++] & 077;
                    else
                        c = 0;
                    if (s < strend && ISUUCHAR(*s))
-                       d = uudmap[*s++] & 077;
+                       d = PL_uudmap[*s++] & 077;
                    else
                        d = 0;
                    hunk[0] = (a << 2) | (b >> 4);
@@ -3943,34 +4219,34 @@ doencodes(register SV *sv, register char *s, register I32 len)
 {
     char hunk[5];
 
-    *hunk = uuemap[len];
+    *hunk = PL_uuemap[len];
     sv_catpvn(sv, hunk, 1);
     hunk[4] = '\0';
     while (len > 2) {
-       hunk[0] = uuemap[(077 & (*s >> 2))];
-       hunk[1] = uuemap[(077 & (((*s << 4) & 060) | ((s[1] >> 4) & 017)))];
-       hunk[2] = uuemap[(077 & (((s[1] << 2) & 074) | ((s[2] >> 6) & 03)))];
-       hunk[3] = uuemap[(077 & (s[2] & 077))];
+       hunk[0] = PL_uuemap[(077 & (*s >> 2))];
+       hunk[1] = PL_uuemap[(077 & (((*s << 4) & 060) | ((s[1] >> 4) & 017)))];
+       hunk[2] = PL_uuemap[(077 & (((s[1] << 2) & 074) | ((s[2] >> 6) & 03)))];
+       hunk[3] = PL_uuemap[(077 & (s[2] & 077))];
        sv_catpvn(sv, hunk, 4);
        s += 3;
        len -= 3;
     }
     if (len > 0) {
        char r = (len > 1 ? s[1] : '\0');
-       hunk[0] = uuemap[(077 & (*s >> 2))];
-       hunk[1] = uuemap[(077 & (((*s << 4) & 060) | ((r >> 4) & 017)))];
-       hunk[2] = uuemap[(077 & ((r << 2) & 074))];
-       hunk[3] = uuemap[0];
+       hunk[0] = PL_uuemap[(077 & (*s >> 2))];
+       hunk[1] = PL_uuemap[(077 & (((*s << 4) & 060) | ((r >> 4) & 017)))];
+       hunk[2] = PL_uuemap[(077 & ((r << 2) & 074))];
+       hunk[3] = PL_uuemap[0];
        sv_catpvn(sv, hunk, 4);
     }
     sv_catpvn(sv, "\n", 1);
 }
 
-STATIC SV      *
+STATIC SV *
 is_an_int(char *s, STRLEN l)
 {
   STRLEN        n_a;
-  SV             *result = newSVpv("", l);
+  SV             *result = newSVpvn(s, l);
   char           *result_c = SvPV(result, n_a);        /* convenience */
   char           *out = result_c;
   bool            skip = 1;
@@ -4074,6 +4350,9 @@ PP(pp_pack)
     float afloat;
     double adouble;
     int commas = 0;
+#ifdef PERL_NATINT_PACK
+    int natint;                /* native integer */
+#endif
 
     items = SP - MARK;
     MARK++;
@@ -4081,8 +4360,23 @@ PP(pp_pack)
     while (pat < patend) {
 #define NEXTFROM (items-- > 0 ? *MARK++ : &PL_sv_no)
        datumtype = *pat++ & 0xFF;
+#ifdef PERL_NATINT_PACK
+       natint = 0;
+#endif
        if (isSPACE(datumtype))
            continue;
+        if (*pat == '!') {
+           char *natstr = "sSiIlL";
+
+           if (strchr(natstr, datumtype)) {
+#ifdef PERL_NATINT_PACK
+               natint = 1;
+#endif
+               pat++;
+           }
+           else
+               croak("'!' allowed only after types %s", natstr);
+       }
        if (*pat == '*') {
            len = strchr("@Xxu", datumtype) ? 0 : items;
            pat++;
@@ -4127,6 +4421,7 @@ PP(pp_pack)
            sv_catpvn(cat, null10, len);
            break;
        case 'A':
+       case 'Z':
        case 'a':
            fromstr = NEXTFROM;
            aptr = SvPV(fromstr, fromlen);
@@ -4326,11 +4621,46 @@ PP(pp_pack)
            }
            break;
        case 'S':
+#if SHORTSIZE != SIZE16
+           if (natint) {
+               unsigned short aushort;
+
+               while (len-- > 0) {
+                   fromstr = NEXTFROM;
+                   aushort = SvUV(fromstr);
+                   sv_catpvn(cat, (char *)&aushort, sizeof(unsigned short));
+               }
+           }
+           else
+#endif
+            {
+               U16 aushort;
+
+               while (len-- > 0) {
+                   fromstr = NEXTFROM;
+                   aushort = (U16)SvUV(fromstr);
+                   CAT16(cat, &aushort);
+               }
+
+           }
+           break;
        case 's':
-           while (len-- > 0) {
-               fromstr = NEXTFROM;
-               ashort = (I16)SvIV(fromstr);
-               CAT16(cat, &ashort);
+#if SHORTSIZE != SIZE16
+           if (natint) {
+               while (len-- > 0) {
+                   fromstr = NEXTFROM;
+                   ashort = SvIV(fromstr);
+                   sv_catpvn(cat, (char *)&ashort, sizeof(short));
+               }
+           }
+           else
+#endif
+            {
+               while (len-- > 0) {
+                   fromstr = NEXTFROM;
+                   ashort = (I16)SvIV(fromstr);
+                   CAT16(cat, &ashort);
+               }
            }
            break;
        case 'I':
@@ -4362,7 +4692,7 @@ PP(pp_pack)
                {
                    char   buf[1 + sizeof(UV)];
                    char  *in = buf + sizeof(buf);
-                   UV     auv = U_V(adouble);;
+                   UV     auv = U_V(adouble);
 
                    do {
                        *--in = (auv & 0x7f) | 0x80;
@@ -4438,17 +4768,41 @@ PP(pp_pack)
            }
            break;
        case 'L':
-           while (len-- > 0) {
-               fromstr = NEXTFROM;
-               aulong = SvUV(fromstr);
-               CAT32(cat, &aulong);
+#if LONGSIZE != SIZE32
+           if (natint) {
+               while (len-- > 0) {
+                   fromstr = NEXTFROM;
+                   aulong = SvUV(fromstr);
+                   sv_catpvn(cat, (char *)&aulong, sizeof(unsigned long));
+               }
+           }
+           else
+#endif
+            {
+               while (len-- > 0) {
+                   fromstr = NEXTFROM;
+                   aulong = SvUV(fromstr);
+                   CAT32(cat, &aulong);
+               }
            }
            break;
        case 'l':
-           while (len-- > 0) {
-               fromstr = NEXTFROM;
-               along = SvIV(fromstr);
-               CAT32(cat, &along);
+#if LONGSIZE != SIZE32
+           if (natint) {
+               while (len-- > 0) {
+                   fromstr = NEXTFROM;
+                   along = SvIV(fromstr);
+                   sv_catpvn(cat, (char *)&along, sizeof(long));
+               }
+           }
+           else
+#endif
+            {
+               while (len-- > 0) {
+                   fromstr = NEXTFROM;
+                   along = SvIV(fromstr);
+                   CAT32(cat, &along);
+               }
            }
            break;
 #ifdef HAS_QUAD
@@ -4652,8 +5006,10 @@ PP(pp_split)
     else if (rx->check_substr && !rx->nparens
             && (rx->reganch & ROPT_CHECK_ALL)
             && !(rx->reganch & ROPT_ANCH)) {
+       int tail = SvTAIL(rx->check_substr) != 0;
+
        i = SvCUR(rx->check_substr);
-       if (i == 1 && !SvTAIL(rx->check_substr)) {
+       if (i == 1 && !tail) {
            i = *SvPVX(rx->check_substr);
            while (--limit) {
                /*SUPPRESS 530*/
@@ -4672,7 +5028,7 @@ PP(pp_split)
 #ifndef lint
            while (s < strend && --limit &&
              (m=fbm_instr((unsigned char*)s, (unsigned char*)strend,
-                   rx->check_substr, 0)) )
+                   rx->check_substr, PL_multiline ? FBMrf_MULTILINE : 0)) )
 #endif
            {
                dstr = NEWSV(31, m-s);
@@ -4680,7 +5036,7 @@ PP(pp_split)
                if (make_mortal)
                    sv_2mortal(dstr);
                XPUSHs(dstr);
-               s = m + i;
+               s = m + i - tail;       /* Fake \n at the end */
            }
        }
     }
@@ -4690,15 +5046,14 @@ PP(pp_split)
               CALLREGEXEC(rx, s, strend, orig, 1, sv, NULL, 0))
        {
            TAINT_IF(RX_MATCH_TAINTED(rx));
-           if (rx->subbase
-             && rx->subbase != orig) {
+           if (RX_MATCH_COPIED(rx) && rx->subbeg != orig) {
                m = s;
                s = orig;
-               orig = rx->subbase;
+               orig = rx->subbeg;
                s = orig + (m - s);
                strend = s + (strend - m);
            }
-           m = rx->startp[0];
+           m = rx->startp[0] + orig;
            dstr = NEWSV(32, m-s);
            sv_setpvn(dstr, s, m-s);
            if (make_mortal)
@@ -4706,8 +5061,8 @@ PP(pp_split)
            XPUSHs(dstr);
            if (rx->nparens) {
                for (i = 1; i <= rx->nparens; i++) {
-                   s = rx->startp[i];
-                   m = rx->endp[i];
+                   s = rx->startp[i] + orig;
+                   m = rx->endp[i] + orig;
                    if (m && s) {
                        dstr = NEWSV(33, m-s);
                        sv_setpvn(dstr, s, m-s);
@@ -4719,7 +5074,7 @@ PP(pp_split)
                    XPUSHs(dstr);
                }
            }
-           s = rx->endp[0];
+           s = rx->endp[0] + orig;
        }
     }