pack/unpack better in (network-)short-non-16-bits and
[p5sagit/p5-mst-13.2.git] / pp.c
diff --git a/pp.c b/pp.c
index 729d1e7..a9ced11 100644 (file)
--- a/pp.c
+++ b/pp.c
@@ -78,6 +78,10 @@ typedef unsigned UBW;
 #define SIZE16 2
 #define SIZE32 4
 
+#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 +96,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
@@ -218,7 +224,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 {
@@ -240,9 +247,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)
@@ -287,9 +303,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);
     }
@@ -408,7 +433,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) {
@@ -420,7 +446,8 @@ PP(pp_prototype)
                }
                str[n++] = '\0';
                ret = sv_2mortal(newSVpv(str, n - 1));
-           } else if (code)            /* Non-Overridable */
+           }
+           else if (code)              /* Non-Overridable */
                goto set;
            else {                      /* None such */
              nonesuch:
@@ -914,7 +941,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;
        }
       }
@@ -1343,9 +1371,7 @@ PP(pp_negate)
 
 PP(pp_not)
 {
-#ifdef OVERLOAD
     djSP; tryAMAGICunSET(not);
-#endif /* OVERLOAD */
     *PL_stack_sp = boolSV(!SvTRUE(*PL_stack_sp));
     return NORMAL;
 }
@@ -2636,10 +2662,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;
@@ -2662,7 +2690,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) {
@@ -3218,6 +3247,10 @@ PP(pp_unpack)
     register U32 culong;
     double cdouble;
     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*/
@@ -3233,8 +3266,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 == '*') {
@@ -3479,66 +3527,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;
@@ -3613,72 +3731,147 @@ PP(pp_unpack)
            }
            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;
@@ -4083,6 +4276,9 @@ PP(pp_pack)
     float afloat;
     double adouble;
     int commas = 0;
+#ifdef PERL_NATINT_PACK
+    int natint;                /* native integer */
+#endif
 
     items = SP - MARK;
     MARK++;
@@ -4090,8 +4286,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++;
@@ -4336,11 +4547,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':
@@ -4448,17 +4694,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