Change to use $^O and &Cwd:cwd
[p5sagit/p5-mst-13.2.git] / pp.c
diff --git a/pp.c b/pp.c
index 446ddb0..54433af 100644 (file)
--- a/pp.c
+++ b/pp.c
@@ -126,13 +126,13 @@ PP(pp_rv2gv)
        GP *ogp = GvGP(sv);
 
        SSCHECK(3);
-       SSPUSHPTR(sv);
+       SSPUSHPTR(SvREFCNT_inc(sv));
        SSPUSHPTR(ogp);
        SSPUSHINT(SAVEt_GP);
 
        if (op->op_flags & OPf_SPECIAL) {
            GvGP(sv)->gp_refcnt++;              /* will soon be assigned */
-           GvFLAGS(sv) |= GVf_INTRO;
+           GvINTRO_on(sv);
        }
        else {
            GP *gp;
@@ -148,14 +148,6 @@ PP(pp_rv2gv)
     RETURN;
 }
 
-PP(pp_sv2len)
-{
-    dSP; dTARGET;
-    dPOPss;
-    PUSHi(sv_len(sv));
-    RETURN;
-}
-
 PP(pp_rv2sv)
 {
     dSP; dTOPss;
@@ -196,17 +188,8 @@ 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)) {
-           if (SvGMAGICAL(sv))
-               mg_get(sv);
-           if (!SvOK(sv)) {
-               (void)SvUPGRADE(sv, SVt_RV);
-               SvRV(sv) = (op->op_private & OPpDEREF_HV ?
-                           (SV*)newHV() : (SV*)newAV());
-               SvROK_on(sv);
-               SvSETMAGIC(sv);
-           }
-       }
+       else if (op->op_private & (OPpDEREF_HV|OPpDEREF_AV))
+           provide_ref(op, sv);
     }
     SETs(sv);
     RETURN;
@@ -256,22 +239,42 @@ PP(pp_rv2cv)
     GV *gv;
     HV *stash;
 
-    /* We always try to add a non-existent subroutine in case of AUTOLOAD. */
-    CV *cv = sv_2cv(TOPs, &stash, &gv, TRUE);
+    /* 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)
+       cv = (CV*)&sv_undef;
     SETs((SV*)cv);
     RETURN;
 }
 
+PP(pp_prototype)
+{
+    dSP;
+    CV *cv;
+    HV *stash;
+    GV *gv;
+    SV *ret;
+
+    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)));
+    }
+    SETs(ret);
+    RETURN;
+}
+
 PP(pp_anoncode)
 {
     dSP;
     CV* cv = (CV*)cSVOP->op_sv;
     EXTEND(SP,1);
 
-    if (SvFLAGS(cv) & SVpcv_CLONE) {
+    if (CvCLONE(cv))
        cv = (CV*)sv_2mortal((SV*)cv_clone(cv));
-    }
 
     PUSHs((SV*)cv);
     RETURN;
@@ -329,7 +332,7 @@ PP(pp_ref)
 
     sv = POPs;
     if (!sv || !SvROK(sv))
-       RETPUSHUNDEF;
+       RETPUSHNO;
 
     sv = SvRV(sv);
     pv = sv_reftype(sv,TRUE);
@@ -355,7 +358,7 @@ PP(pp_bless)
 
 PP(pp_study)
 {
-    dSP; dTARGET;
+    dSP; dPOPss;
     register unsigned char *s;
     register I32 pos;
     register I32 ch;
@@ -364,11 +367,17 @@ PP(pp_study)
     I32 retval;
     STRLEN len;
 
-    s = (unsigned char*)(SvPV(TARG, len));
+    s = (unsigned char*)(SvPV(sv, len));
     pos = len;
-    if (lastscream)
-       SvSCREAM_off(lastscream);
-    lastscream = TARG;
+    if (sv == lastscream)
+       SvSCREAM_off(sv);
+    else {
+       if (lastscream) {
+           SvSCREAM_off(lastscream);
+           SvREFCNT_dec(lastscream);
+       }
+       lastscream = SvREFCNT_inc(sv);
+    }
     if (pos <= 0) {
        retval = 0;
        goto ret;
@@ -411,7 +420,8 @@ PP(pp_study)
            sfirst[fold[ch]] = pos;
     }
 
-    SvSCREAM_on(TARG);
+    SvSCREAM_on(sv);
+    sv_magic(sv, Nullsv, 'g', Nullch, 0);      /* piggyback on m//g magic */
     retval = 1;
   ret:
     XPUSHs(sv_2mortal(newSViv((I32)retval)));
@@ -539,16 +549,14 @@ PP(pp_undef)
             break;
         }
     default:
-       if (sv != GvSV(defgv)) {
-           if (SvPOK(sv) && SvLEN(sv)) {
-               (void)SvOOK_off(sv);
-               Safefree(SvPVX(sv));
-               SvPV_set(sv, Nullch);
-               SvLEN_set(sv, 0);
-           }
-           (void)SvOK_off(sv);
-           SvSETMAGIC(sv);
+       if (SvPOK(sv) && SvLEN(sv)) {
+           (void)SvOOK_off(sv);
+           Safefree(SvPVX(sv));
+           SvPV_set(sv, Nullch);
+           SvLEN_set(sv, 0);
        }
+       (void)SvOK_off(sv);
+       SvSETMAGIC(sv);
     }
 
     RETPUSHUNDEF;
@@ -890,7 +898,7 @@ PP(pp_bit_and) {
     dSP; dATARGET; tryAMAGICbin(band,opASSIGN); 
     {
       dPOPTOPssrl;
-      if (SvNIOK(left) || SvNIOK(right)) {
+      if (SvNIOKp(left) || SvNIOKp(right)) {
        unsigned long value = U_L(SvNV(left));
        value = value & U_L(SvNV(right));
        SETn((double)value);
@@ -908,7 +916,7 @@ PP(pp_bit_xor)
     dSP; dATARGET; tryAMAGICbin(bxor,opASSIGN); 
     {
       dPOPTOPssrl;
-      if (SvNIOK(left) || SvNIOK(right)) {
+      if (SvNIOKp(left) || SvNIOKp(right)) {
        unsigned long value = U_L(SvNV(left));
        value = value ^ U_L(SvNV(right));
        SETn((double)value);
@@ -926,7 +934,7 @@ PP(pp_bit_or)
     dSP; dATARGET; tryAMAGICbin(bor,opASSIGN); 
     {
       dPOPTOPssrl;
-      if (SvNIOK(left) || SvNIOK(right)) {
+      if (SvNIOKp(left) || SvNIOKp(right)) {
        unsigned long value = U_L(SvNV(left));
        value = value | U_L(SvNV(right));
        SETn((double)value);
@@ -944,9 +952,11 @@ PP(pp_negate)
     dSP; dTARGET; tryAMAGICun(neg);
     {
        dTOPss;
-       if (SvNIOK(sv))
+       if (SvGMAGICAL(sv))
+           mg_get(sv);
+       if (SvNIOKp(sv))
            SETn(-SvNV(sv));
-       else if (SvPOK(sv)) {
+       else if (SvPOKp(sv)) {
            STRLEN len;
            char *s = SvPV(sv, len);
            if (isALPHA(*s) || *s == '_') {
@@ -961,6 +971,8 @@ PP(pp_negate)
                sv_setnv(TARG, -SvNV(sv));
            SETTARG;
        }
+       else
+           SETn(-SvNV(sv));
     }
     RETURN;
 }
@@ -981,7 +993,7 @@ PP(pp_complement)
       dTOPss;
       register I32 anum;
 
-      if (SvNIOK(sv)) {
+      if (SvNIOKp(sv)) {
        IV iv = ~SvIV(sv);
        if (iv < 0)
            SETn( (double) ~U_L(SvNV(sv)) );
@@ -1307,28 +1319,38 @@ PP(pp_hex)
 {
     dSP; dTARGET;
     char *tmps;
+    unsigned long value;
     I32 argtype;
 
     tmps = POPp;
-    XPUSHi( scan_hex(tmps, 99, &argtype) );
+    value = scan_hex(tmps, 99, &argtype);
+    if ((IV)value >= 0)
+       XPUSHi(value);
+    else
+       XPUSHn(U_V(value));
     RETURN;
 }
 
 PP(pp_oct)
 {
     dSP; dTARGET;
-    I32 value;
+    unsigned long value;
     I32 argtype;
     char *tmps;
 
     tmps = POPp;
-    while (*tmps && (isSPACE(*tmps) || *tmps == '0'))
+    while (*tmps && isSPACE(*tmps))
+       tmps++;
+    if (*tmps == '0')
        tmps++;
     if (*tmps == 'x')
-       value = (I32)scan_hex(++tmps, 99, &argtype);
+       value = scan_hex(++tmps, 99, &argtype);
     else
-       value = (I32)scan_oct(tmps, 99, &argtype);
-    XPUSHi(value);
+       value = scan_oct(tmps, 99, &argtype);
+    if ((IV)value >= 0)
+       XPUSHi(value);
+    else
+       XPUSHn(U_V(value));
     RETURN;
 }
 
@@ -1379,7 +1401,8 @@ PP(pp_substr)
            rem = len;
        sv_setpvn(TARG, tmps, rem);
        if (lvalue) {                   /* it's an lvalue! */
-           (void)SvPOK_only(sv);
+           if (!SvGMAGICAL(sv))
+               (void)SvPOK_only(sv);
            if (SvTYPE(TARG) < SVt_PVLV) {
                sv_upgrade(TARG, SVt_PVLV);
                sv_magic(TARG, Nullsv, 'x', Nullch, 0);
@@ -1697,7 +1720,7 @@ PP(pp_quotemeta)
 
     if (len) {
        (void)SvUPGRADE(TARG, SVt_PV);
-       SvGROW(TARG, len * 2);
+       SvGROW(TARG, (len * 2) + 1);
        d = SvPVX(TARG);
        while (len--) {
            if (!isALNUM(*s))
@@ -1765,18 +1788,24 @@ PP(pp_each)
 {
     dSP; dTARGET;
     HV *hash = (HV*)POPs;
-    HE *entry = hv_iternext(hash);
+    HE *entry;
     I32 i;
     char *tmps;
+    
+    PUTBACK;
+    entry = hv_iternext(hash);                        /* might clobber stack_sp */
+    SPAGAIN;
 
     EXTEND(SP, 2);
     if (entry) {
-       tmps = hv_iterkey(entry, &i);
+       tmps = hv_iterkey(entry, &i);                 /* won't clobber stack_sp */
        if (!i)
            tmps = "";
        PUSHs(sv_2mortal(newSVpv(tmps, i)));
        if (GIMME == G_ARRAY) {
-           sv_setsv(TARG, hv_iterval(hash, entry));
+           PUTBACK;
+           sv_setsv(TARG, hv_iterval(hash, entry));  /* might clobber stack_sp */
+           SPAGAIN;
            PUSHs(TARG);
        }
     }
@@ -1885,6 +1914,8 @@ PP(pp_lslice)
     SV **firstlelem = stack_base + POPMARK + 1;
     register SV **firstrelem = lastlelem + 1;
     I32 arybase = curcop->cop_arybase;
+    I32 lval = op->op_flags & OPf_MOD;
+    I32 is_something_there = lval;
 
     register I32 max = lastrelem - lastlelem;
     register SV **lelem;
@@ -1923,8 +1954,13 @@ PP(pp_lslice)
            if (ix >= max || !(*lelem = firstrelem[ix]))
                *lelem = &sv_undef;
        }
+       if (!is_something_there && (SvOKp(*lelem) || SvGMAGICAL(*lelem)))
+           is_something_there = TRUE;
     }
-    SP = lastlelem;
+    if (is_something_there)
+       SP = lastlelem;
+    else
+       SP = firstlelem - 1;
     RETURN;
 }
 
@@ -1947,8 +1983,6 @@ PP(pp_anonhash)
        SV* key = *++MARK;
        char *tmps;
        SV *val = NEWSV(46, 0);
-        if (dowarn && key && SvROK(key))  /* Tom's gripe */
-            warn("Attempt to use reference as hash key");
        if (MARK < SP)
            sv_setsv(val, *++MARK);
        else
@@ -3293,6 +3327,7 @@ PP(pp_split)
     AV *oldstack = stack;
     register REGEXP *rx = pm->op_pmregexp;
     I32 gimme = GIMME;
+    I32 oldsave = savestack_ix;
 
     if (!pm || !s)
        DIE("panic: do_split");
@@ -3320,6 +3355,11 @@ PP(pp_split)
        while (isSPACE(*s))
            s++;
     }
+    if (pm->op_pmflags & (PMf_MULTILINE|PMf_SINGLELINE)) {
+       SAVEINT(multiline);
+       multiline = pm->op_pmflags & PMf_MULTILINE;
+    }
+
     if (!limit)
        limit = maxiters + 2;
     if (pm->op_pmflags & PMf_WHITE) {
@@ -3431,6 +3471,7 @@ PP(pp_split)
            s = rx->endp[0];
        }
     }
+    LEAVE_SCOPE(oldsave);
     iters = (SP - stack_base) - base;
     if (iters > maxiters)
        DIE("Split loop");