Add missing syms to global.sym; update magic doc
[p5sagit/p5-mst-13.2.git] / pp.c
diff --git a/pp.c b/pp.c
index 48ca9bb..d7725b8 100644 (file)
--- a/pp.c
+++ b/pp.c
 #include "EXTERN.h"
 #include "perl.h"
 
-static void doencodes _((SV *sv, char *s, I32 len));
+/*
+ * Types used in bitwise operations.
+ *
+ * Normally we'd just use IV and UV.  However, some hardware and
+ * software combinations (e.g. Alpha and current OSF/1) don't have a
+ * floating-point type to use for NV that has adequate bits to fully
+ * hold an IV/UV.  (In other words, sizeof(long) == sizeof(double).)
+ *
+ * It just so happens that "int" is the right size everywhere, at
+ * least today.
+ */
+typedef int IBW;
+typedef unsigned UBW;
+
+static SV* refto _((SV* sv));
+static void doencodes _((SV* sv, char* s, I32 len));
 
 /* variations on pp_null */
 
@@ -128,28 +143,8 @@ PP(pp_rv2gv)
            sv = (SV*)gv_fetchpv(sym, TRUE, SVt_PVGV);
        }
     }
-    if (op->op_private & OPpLVAL_INTRO) {
-       GP *ogp = GvGP(sv);
-
-       SSCHECK(3);
-       SSPUSHPTR(SvREFCNT_inc(sv));
-       SSPUSHPTR(ogp);
-       SSPUSHINT(SAVEt_GP);
-
-       if (op->op_flags & OPf_SPECIAL) {
-           GvGP(sv)->gp_refcnt++;              /* will soon be assigned */
-           GvINTRO_on(sv);
-       }
-       else {
-           GP *gp;
-           Newz(602,gp, 1, GP);
-           GvGP(sv) = gp;
-           GvREFCNT(sv) = 1;
-           GvSV(sv) = NEWSV(72,0);
-           GvLINE(sv) = curcop->cop_line;
-           GvEGV(sv) = (GV*)sv;
-       }
-    }
+    if (op->op_private & OPpLVAL_INTRO)
+       save_gp((GV*)sv, !(op->op_flags & OPf_SPECIAL));
     SETs(sv);
     RETURN;
 }
@@ -194,7 +189,7 @@ PP(pp_rv2sv)
     if (op->op_flags & OPf_MOD) {
        if (op->op_private & OPpLVAL_INTRO)
            sv = save_scalar((GV*)TOPs);
-       else if (op->op_private & (OPpDEREF_HV|OPpDEREF_AV))
+       else if (op->op_private & OPpDEREF)
            provide_ref(op, sv);
     }
     SETs(sv);
@@ -220,7 +215,12 @@ PP(pp_pos)
     dSP; dTARGET; dPOPss;
     
     if (op->op_flags & OPf_MOD) {
-       LvTYPE(TARG) = '<';
+       if (SvTYPE(TARG) < SVt_PVLV) {
+           sv_upgrade(TARG, SVt_PVLV);
+           sv_magic(TARG, Nullsv, '.', Nullch, 0);
+       }
+
+       LvTYPE(TARG) = '.';
        LvTARG(TARG) = sv;
        PUSHs(TARG);    /* no SvSETMAGIC */
        RETURN;
@@ -248,8 +248,11 @@ PP(pp_rv2cv)
     /* We usually try to add a non-existent subroutine in case of AUTOLOAD. */
     /* (But not in defined().) */
     CV *cv = sv_2cv(TOPs, &stash, &gv, !(op->op_flags & OPf_SPECIAL));
-
-    if (!cv)
+    if (cv) {
+       if (CvCLONE(cv))
+           cv = (CV*)sv_2mortal((SV*)cv_clone(cv));
+    }
+    else
        cv = (CV*)&sv_undef;
     SETs((SV*)cv);
     RETURN;
@@ -265,10 +268,8 @@ PP(pp_prototype)
 
     ret = &sv_undef;
     cv = sv_2cv(TOPs, &stash, &gv, FALSE);
-    if (cv && SvPOK(cv)) {
-       char *p = SvPVX(cv);
-       ret = sv_2mortal(newSVpv(p ? p : "", SvLEN(cv)));
-    }
+    if (cv && SvPOK(cv))
+       ret = sv_2mortal(newSVpv(SvPVX(cv), SvCUR(cv)));
     SETs(ret);
     RETURN;
 }
@@ -276,61 +277,59 @@ PP(pp_prototype)
 PP(pp_anoncode)
 {
     dSP;
-    CV* cv = (CV*)cSVOP->op_sv;
-    EXTEND(SP,1);
-
+    CV* cv = (CV*)curpad[op->op_targ];
     if (CvCLONE(cv))
        cv = (CV*)sv_2mortal((SV*)cv_clone(cv));
-
+    EXTEND(SP,1);
     PUSHs((SV*)cv);
     RETURN;
 }
 
 PP(pp_srefgen)
 {
-    dSP; dTOPss;
-    SV* rv;
-    rv = sv_newmortal();
-    sv_upgrade(rv, SVt_RV);
-    if (SvPADTMP(sv))
-       sv = newSVsv(sv);
-    else {
-       SvTEMP_off(sv);
-       (void)SvREFCNT_inc(sv);
-    }
-    SvRV(rv) = sv;
-    SvROK_on(rv);
-    SETs(rv);
+    dSP;
+    *SP = refto(*SP);
     RETURN;
 } 
 
 PP(pp_refgen)
 {
     dSP; dMARK;
-    SV* sv;
-    SV* rv;
     if (GIMME != G_ARRAY) {
        MARK[1] = *SP;
        SP = MARK + 1;
     }
     EXTEND_MORTAL(SP - MARK);
-    while (MARK < SP) {
-       sv = *++MARK;
-       rv = sv_newmortal();
-       sv_upgrade(rv, SVt_RV);
-       if (SvPADTMP(sv))
-           sv = newSVsv(sv);
-       else {
-           SvTEMP_off(sv);
-           (void)SvREFCNT_inc(sv);
-       }
-       SvRV(rv) = sv;
-       SvROK_on(rv);
-       *MARK = rv;
-    }
+    while (++MARK <= SP)
+       *MARK = refto(*MARK);
     RETURN;
 }
 
+static SV*
+refto(sv)
+SV* sv;
+{
+    SV* rv;
+
+    if (SvTYPE(sv) == SVt_PVLV && LvTYPE(sv) == 'y') {
+       if (LvTARGLEN(sv))
+           vivify_itervar(sv);
+       if (LvTARG(sv))
+           sv = LvTARG(sv);
+    }
+    else if (SvPADTMP(sv))
+       sv = newSVsv(sv);
+    else {
+       SvTEMP_off(sv);
+       (void)SvREFCNT_inc(sv);
+    }
+    rv = sv_newmortal();
+    sv_upgrade(rv, SVt_RV);
+    SvRV(rv) = sv;
+    SvROK_on(rv);
+    return rv;
+}
+
 PP(pp_ref)
 {
     dSP; dTARGET;
@@ -643,25 +642,24 @@ PP(pp_divide)
 {
     dSP; dATARGET; tryAMAGICbin(div,opASSIGN); 
     {
-      dPOPnv;
-      if (value == 0.0)
+      dPOPPOPnnrl;
+      double value;
+      if (right == 0.0)
        DIE("Illegal division by zero");
 #ifdef SLOPPYDIVIDE
       /* insure that 20./5. == 4. */
       {
-       double x;
-       I32    k;
-       x =  POPn;
-       if ((double)I_32(x)     == x &&
-           (double)I_32(value) == value &&
-           (k = I_32(x)/I_32(value))*I_32(value) == I_32(x)) {
+       IV k;
+       if ((double)I_V(left)  == left &&
+           (double)I_V(right) == right &&
+           (k = I_V(left)/I_V(right))*I_V(right) == I_V(left)) {
            value = k;
        } else {
-           value = x/value;
+           value = left / right;
        }
       }
 #else
-      value = POPn / value;
+      value = left / right;
 #endif
       PUSHn( value );
       RETURN;
@@ -672,19 +670,26 @@ PP(pp_modulo)
 {
     dSP; dATARGET; tryAMAGICbin(mod,opASSIGN);
     {
-      register IV value;
-      register UV uval;
+      register UV right;
 
-      uval = POPn;
-      if (!uval)
+      right = POPu;
+      if (!right)
        DIE("Illegal modulus zero");
-      value = TOPn;
-      if (value >= 0)
-       value = (UV)value % uval;
+
+      if (SvIOK(TOPs) && !SvNOK(TOPs) && !SvPOK(TOPs)) {
+       register IV left = SvIVX(TOPs);
+       if (left < 0)
+         SETu( (right - ((UV)(-left) - 1) % right) - 1 );
+       else
+         SETi( left % right );
+      }
       else {
-       value = (uval - ((UV)(-value - 1) % uval)) - 1;
+       register double left = TOPn;
+       if (left < 0.0)
+         SETu( (right - (U_V(-left) - 1) % right) - 1 );
+       else
+         SETu( U_V(left) % right );
       }
-      SETi(value);
       RETURN;
     }
 }
@@ -726,14 +731,19 @@ PP(pp_repeat)
            if (SvROK(tmpstr))
                sv_unref(tmpstr);
        }
-       SvSetSV(TARG, tmpstr);
-       SvPV_force(TARG, len);
-       if (count >= 1) {
-           SvGROW(TARG, (count * len) + 1);
-           if (count > 1)
-               repeatcpy(SvPVX(TARG) + len, SvPVX(TARG), len, count - 1);
-           SvCUR(TARG) *= count;
-           *SvEND(TARG) = '\0';
+       if (USE_LEFT(tmpstr) || SvTYPE(tmpstr) > SVt_PVMG) {
+           SvSetSV(TARG, tmpstr);
+           SvPV_force(TARG, len);
+           if (count != 1) {
+               if (count < 1)
+                   SvCUR_set(TARG, 0);
+               else {
+                   SvGROW(TARG, (count * len) + 1);
+                   repeatcpy(SvPVX(TARG) + len, SvPVX(TARG), len, count - 1);
+                   SvCUR(TARG) *= count;
+               }
+               *SvEND(TARG) = '\0';
+           }
            (void)SvPOK_only(TARG);
        }
        else
@@ -748,7 +758,7 @@ PP(pp_subtract)
 {
     dSP; dATARGET; tryAMAGICbin(subtr,opASSIGN); 
     {
-      dPOPTOPnnrl;
+      dPOPTOPnnrl_ul;
       SETn( left - right );
       RETURN;
     }
@@ -758,13 +768,13 @@ PP(pp_left_shift)
 {
     dSP; dATARGET; tryAMAGICbin(lshift,opASSIGN); 
     {
-      IV shift = POPi;
+      IBW shift = POPi;
       if (op->op_private & HINT_INTEGER) {
-       IV i = TOPi;
+       IBW i = TOPi;
        SETi( i << shift );
       }
       else {
-       UV u = TOPu;
+       UBW u = TOPu;
        SETu( u << shift );
       }
       RETURN;
@@ -775,13 +785,13 @@ PP(pp_right_shift)
 {
     dSP; dATARGET; tryAMAGICbin(rshift,opASSIGN); 
     {
-      IV shift = POPi;
+      IBW shift = POPi;
       if (op->op_private & HINT_INTEGER) {
-       IV i = TOPi;
+       IBW i = TOPi;
        SETi( i >> shift );
       }
       else {
-       UV u = TOPu;
+       UBW u = TOPu;
        SETu( u >> shift );
       }
       RETURN;
@@ -908,15 +918,22 @@ PP(pp_sge)
     }
 }
 
+PP(pp_seq)
+{
+    dSP; tryAMAGICbinSET(seq,0); 
+    {
+      dPOPTOPssrl;
+      SETs( sv_eq(left, right) ? &sv_yes : &sv_no );
+      RETURN;
+    }
+}
+
 PP(pp_sne)
 {
     dSP; tryAMAGICbinSET(sne,0); 
     {
       dPOPTOPssrl;
-      bool ne = ((op->op_private & OPpLOCALE)
-                ? (sv_cmp_locale(left, right) != 0)
-                : !sv_eq(left, right));
-      SETs( ne ? &sv_yes : &sv_no );
+      SETs( !sv_eq(left, right) ? &sv_yes : &sv_no );
       RETURN;
     }
 }
@@ -940,11 +957,14 @@ PP(pp_bit_and)
     {
       dPOPTOPssrl;
       if (SvNIOKp(left) || SvNIOKp(right)) {
-       UV value = SvUV(left) & SvUV(right); 
-       if (op->op_private & HINT_INTEGER)
-         SETi( (IV)value );
-       else
+       if (op->op_private & HINT_INTEGER) {
+         IBW value = SvIV(left) & SvIV(right); 
+         SETi( value );
+       }
+       else {
+         UBW value = SvUV(left) & SvUV(right); 
          SETu( value );
+       }
       }
       else {
        do_vop(op->op_type, TARG, left, right);
@@ -960,11 +980,14 @@ PP(pp_bit_xor)
     {
       dPOPTOPssrl;
       if (SvNIOKp(left) || SvNIOKp(right)) {
-       UV value = SvUV(left) ^ SvUV(right);
-       if (op->op_private & HINT_INTEGER)
-         SETi( (IV)value );
-       else
+       if (op->op_private & HINT_INTEGER) {
+         IBW value = SvIV(left) ^ SvIV(right); 
+         SETi( value );
+       }
+       else {
+         UBW value = SvUV(left) ^ SvUV(right); 
          SETu( value );
+       }
       }
       else {
        do_vop(op->op_type, TARG, left, right);
@@ -980,11 +1003,14 @@ PP(pp_bit_or)
     {
       dPOPTOPssrl;
       if (SvNIOKp(left) || SvNIOKp(right)) {
-       UV value = SvUV(left) | SvUV(right);
-       if (op->op_private & HINT_INTEGER)
-         SETi( (IV)value );
-       else
+       if (op->op_private & HINT_INTEGER) {
+         IBW value = SvIV(left) | SvIV(right); 
+         SETi( value );
+       }
+       else {
+         UBW value = SvUV(left) | SvUV(right); 
          SETu( value );
+       }
       }
       else {
        do_vop(op->op_type, TARG, left, right);
@@ -1041,11 +1067,14 @@ PP(pp_complement)
     {
       dTOPss;
       if (SvNIOKp(sv)) {
-       UV value = ~SvUV(sv);
-       if (op->op_private & HINT_INTEGER)
-         SETi( (IV)value );
-       else
+       if (op->op_private & HINT_INTEGER) {
+         IBW value = ~SvIV(sv);
+         SETi( value );
+       }
+       else {
+         UBW value = ~SvUV(sv);
          SETu( value );
+       }
       }
       else {
        register char *tmps;
@@ -1288,7 +1317,7 @@ PP(pp_srand)
        _ckvmssts(sys$gettim(when));
        anum = when[0] ^ when[1];
 #else
-#  if defined(I_SYS_TIME) && !defined(PLAN9)
+#  ifdef HAS_GETTIMEOFDAY
        struct timeval when;
        gettimeofday(&when,(struct timezone *) 0);
        anum = when.tv_sec ^ when.tv_usec;
@@ -1332,7 +1361,7 @@ PP(pp_log)
       double value;
       value = POPn;
       if (value <= 0.0) {
-       NUMERIC_STANDARD();
+       SET_NUMERIC_STANDARD();
        DIE("Can't take log of %g", value);
       }
       value = log(value);
@@ -1348,7 +1377,7 @@ PP(pp_sqrt)
       double value;
       value = POPn;
       if (value < 0.0) {
-       NUMERIC_STANDARD();
+       SET_NUMERIC_STANDARD();
        DIE("Can't take sqrt of %g", value);
       }
       value = sqrt(value);
@@ -1476,12 +1505,13 @@ PP(pp_substr)
                else
                    sv_setpvn(sv,"",0); /* avoid lexical reincarnation */
            }
+
            if (SvTYPE(TARG) < SVt_PVLV) {
                sv_upgrade(TARG, SVt_PVLV);
                sv_magic(TARG, Nullsv, 'x', Nullch, 0);
            }
 
-           LvTYPE(TARG) = 's';
+           LvTYPE(TARG) = 'x';
            LvTARG(TARG) = sv;
            LvTARGOFF(TARG) = pos;
            LvTARGLEN(TARG) = rem; 
@@ -1637,12 +1667,12 @@ PP(pp_rindex)
 PP(pp_sprintf)
 {
     dSP; dMARK; dORIGMARK; dTARGET;
-#ifdef LC_NUMERIC
+#ifdef USE_LOCALE_NUMERIC
     if (op->op_private & OPpLOCALE)
-       NUMERIC_LOCAL();
+       SET_NUMERIC_LOCAL();
     else
-       NUMERIC_STANDARD();
-#endif /* LC_NUMERIC */
+       SET_NUMERIC_STANDARD();
+#endif
     do_sprintf(TARG, SP-MARK, MARK+1);
     TAINT_IF(SvTAINTED(TARG));
     SP = ORIGMARK;
@@ -1934,17 +1964,35 @@ PP(pp_delete)
 {
     dSP;
     SV *sv;
-    SV *tmpsv = POPs;
-    HV *hv = (HV*)POPs;
-    STRLEN len;
-    if (SvTYPE(hv) != SVt_PVHV) {
-       DIE("Not a HASH reference");
+    HV *hv;
+
+    if (op->op_private & OPpSLICE) {
+       dMARK; dORIGMARK;
+       hv = (HV*)POPs;
+       if (SvTYPE(hv) != SVt_PVHV)
+           DIE("Not a HASH reference");
+       while (++MARK <= SP) {
+           sv = hv_delete_ent(hv, *MARK,
+                       (op->op_private & OPpLEAVE_VOID ? G_DISCARD : 0), 0);
+           *MARK = sv ? sv : &sv_undef;
+       }
+       if (GIMME != G_ARRAY) {
+           MARK = ORIGMARK;
+           *++MARK = *SP;
+           SP = MARK;
+       }
+    }
+    else {
+       SV *keysv = POPs;
+       hv = (HV*)POPs;
+       if (SvTYPE(hv) != SVt_PVHV)
+           DIE("Not a HASH reference");
+       sv = hv_delete_ent(hv, keysv,
+                       (op->op_private & OPpLEAVE_VOID ? G_DISCARD : 0), 0);
+       if (!sv)
+           sv = &sv_undef;
+       PUSHs(sv);
     }
-    sv = hv_delete_ent(hv, tmpsv,
-       (op->op_private & OPpLEAVE_VOID ? G_DISCARD : 0), 0);
-    if (!sv)
-       RETPUSHUNDEF;
-    PUSHs(sv);
     RETURN;
 }
 
@@ -2076,7 +2124,6 @@ PP(pp_anonlist)
 PP(pp_anonhash)
 {
     dSP; dMARK; dORIGMARK;
-    STRLEN len;
     HV* hv = (HV*)sv_2mortal((SV*)newHV());
 
     while (MARK < SP) {
@@ -2160,15 +2207,19 @@ PP(pp_splice)
            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 */
+               for (i = length, dst = MARK; i; i--) {
+                   if (!SvIMMORTAL(*dst))
+                       sv_2mortal(*dst);       /* free them eventualy */
+                   dst++;
+               }
            }
            MARK += length - 1;
        }
        else {
            *MARK = AvARRAY(ary)[offset+length-1];
            if (AvREAL(ary)) {
-               sv_2mortal(*MARK);
+               if (!SvIMMORTAL(*MARK))
+                   sv_2mortal(*MARK);
                for (i = length - 1, dst = &AvARRAY(ary)[offset]; i > 0; i--)
                    SvREFCNT_dec(*dst++);       /* free them now */
            }
@@ -2255,8 +2306,11 @@ PP(pp_splice)
                Copy(tmparyval, MARK, length, SV*);
                if (AvREAL(ary)) {
                    EXTEND_MORTAL(length);
-                   for (i = length, dst = MARK; i; i--)
-                       sv_2mortal(*dst++);     /* free them eventualy */
+                   for (i = length, dst = MARK; i; i--) {
+                       if (!SvIMMORTAL(*dst))
+                           sv_2mortal(*dst);   /* free them eventualy */
+                       dst++;
+                   }
                }
                Safefree(tmparyval);
            }
@@ -2265,7 +2319,8 @@ PP(pp_splice)
        else if (length--) {
            *MARK = tmparyval[length];
            if (AvREAL(ary)) {
-               sv_2mortal(*MARK);
+               if (!SvIMMORTAL(*MARK))
+                   sv_2mortal(*MARK);
                while (length-- > 0)
                    SvREFCNT_dec(tmparyval[length]);
            }
@@ -2300,7 +2355,7 @@ PP(pp_pop)
     dSP;
     AV *av = (AV*)POPs;
     SV *sv = av_pop(av);
-    if (sv != &sv_undef && AvREAL(av))
+    if (!SvIMMORTAL(sv) && AvREAL(av))
        (void)sv_2mortal(sv);
     PUSHs(sv);
     RETURN;
@@ -2314,7 +2369,7 @@ PP(pp_shift)
     EXTEND(SP, 1);
     if (!sv)
        RETPUSHUNDEF;
-    if (sv != &sv_undef && AvREAL(av))
+    if (!SvIMMORTAL(sv) && AvREAL(av))
        (void)sv_2mortal(sv);
     PUSHs(sv);
     RETURN;
@@ -2416,6 +2471,7 @@ PP(pp_unpack)
 {
     dSP;
     dPOPPOPssrl;
+    SV **oldsp = sp;
     SV *sv;
     STRLEN llen;
     STRLEN rlen;
@@ -3090,6 +3146,8 @@ PP(pp_unpack)
            checksum = 0;
        }
     }
+    if (sp == oldsp && GIMME != G_ARRAY)
+       PUSHs(&sv_undef);
     RETURN;
 }
 
@@ -3516,6 +3574,7 @@ PP(pp_pack)
                        *--in = div128(norm, &done) | 0x80;
                    result[len - 1] &= 0x7F; /* clear continue bit */
                    sv_catpvn(cat, in, (result + len) - in);
+                   Safefree(result);
                    SvREFCNT_dec(norm); /* free norm */
                 }
                else if (SvNOKp(fromstr)) {