This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
More tests for the 3-arg open
[perl5.git] / pp_hot.c
index 77e070f..3ff6dc6 100644 (file)
--- a/pp_hot.c
+++ b/pp_hot.c
@@ -1,6 +1,6 @@
 /*    pp_hot.c
  *
- *    Copyright (c) 1991-2001, Larry Wall
+ *    Copyright (c) 1991-2002, 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.
@@ -72,14 +72,7 @@ PP(pp_pushmark)
 PP(pp_stringify)
 {
     dSP; dTARGET;
-    STRLEN len;
-    char *s;
-    s = SvPV(TOPs,len);
-    sv_setpvn(TARG,s,len);
-    if (SvUTF8(TOPs))
-       SvUTF8_on(TARG);
-    else
-       SvUTF8_off(TARG);
+    sv_copypv(TARG,TOPs);
     SETTARG;
     RETURN;
 }
@@ -177,7 +170,7 @@ PP(pp_concat)
        if (llen >= 2 && lpv[llen - 2] == '1' && lpv[llen - 1] == '9'
            && (llen == 2 || !isDIGIT(lpv[llen - 3])))
        {
-           Perl_warner(aTHX_ WARN_Y2K, "Possible Y2K bug: %s",
+           Perl_warner(aTHX_ packWARN(WARN_Y2K), "Possible Y2K bug: %s",
                        "about to append an integer to '19'");
        }
     }
@@ -237,7 +230,8 @@ PP(pp_eq)
     dSP; tryAMAGICbinSET(eq,0);
 #ifndef NV_PRESERVES_UV
     if (SvROK(TOPs) && SvROK(TOPm1s)) {
-       SETs(boolSV(SvRV(TOPs) == SvRV(TOPm1s)));
+        SP--;
+       SETs(boolSV(SvRV(TOPs) == SvRV(TOPp1s)));
        RETURN;
     }
 #endif
@@ -252,49 +246,40 @@ PP(pp_eq)
            bool auvok = SvUOK(TOPm1s);
            bool buvok = SvUOK(TOPs);
        
-           if (!auvok && !buvok) { /* ## IV == IV ## */
-               IV aiv = SvIVX(TOPm1s);
-               IV biv = SvIVX(TOPs);
-               
-               SP--;
-               SETs(boolSV(aiv == biv));
-               RETURN;
-           }
-           if (auvok && buvok) { /* ## UV == UV ## */
-               UV auv = SvUVX(TOPm1s);
-               UV buv = SvUVX(TOPs);
+           if (auvok == buvok) { /* ## IV == IV or UV == UV ## */
+                /* Casting IV to UV before comparison isn't going to matter
+                   on 2s complement. On 1s complement or sign&magnitude
+                   (if we have any of them) it could to make negative zero
+                   differ from normal zero. As I understand it. (Need to
+                   check - is negative zero implementation defined behaviour
+                   anyway?). NWC  */
+               UV buv = SvUVX(POPs);
+               UV auv = SvUVX(TOPs);
                
-               SP--;
                SETs(boolSV(auv == buv));
                RETURN;
            }
            {                   /* ## Mixed IV,UV ## */
+                SV *ivp, *uvp;
                IV iv;
-               UV uv;
                
-               /* == is commutative so swap if needed (save code) */
+               /* == is commutative so doesn't matter which is left or right */
                if (auvok) {
-                   /* swap. top of stack (b) is the iv */
-                   iv = SvIVX(TOPs);
-                   SP--;
-                   if (iv < 0) {
-                       /* As (a) is a UV, it's >0, so it cannot be == */
-                       SETs(&PL_sv_no);
-                       RETURN;
-                   }
-                   uv = SvUVX(TOPs);
-               } else {
-                   iv = SvIVX(TOPm1s);
-                   SP--;
-                   if (iv < 0) {
-                       /* As (b) is a UV, it's >0, so it cannot be == */
-                       SETs(&PL_sv_no);
-                       RETURN;
-                   }
-                   uv = SvUVX(*(SP+1)); /* Do I want TOPp1s() ? */
-               }
+                   /* top of stack (b) is the iv */
+                    ivp = *SP;
+                    uvp = *--SP;
+                } else {
+                    uvp = *SP;
+                    ivp = *--SP;
+                }
+                iv = SvIVX(ivp);
+                if (iv < 0) {
+                    /* As uv is a UV, it's >0, so it cannot be == */
+                    SETs(&PL_sv_no);
+                    RETURN;
+                }
                /* we know iv is >= 0 */
-               SETs(boolSV((UV)iv == uv));
+               SETs(boolSV((UV)iv == SvUVX(uvp)));
                RETURN;
            }
        }
@@ -310,10 +295,10 @@ PP(pp_eq)
 PP(pp_preinc)
 {
     dSP;
-    if (SvREADONLY(TOPs) || SvTYPE(TOPs) > SVt_PVLV)
+    if (SvTYPE(TOPs) > SVt_PVLV)
        DIE(aTHX_ PL_no_modify);
-    if (SvIOK_notUV(TOPs) && !SvNOK(TOPs) && !SvPOK(TOPs) &&
-       SvIVX(TOPs) != IV_MAX)
+    if (!SvREADONLY(TOPs) && SvIOK_notUV(TOPs) && !SvNOK(TOPs) && !SvPOK(TOPs)
+        && SvIVX(TOPs) != IV_MAX)
     {
        ++SvIVX(TOPs);
        SvFLAGS(TOPs) &= ~(SVp_NOK|SVp_POK);
@@ -436,7 +421,7 @@ PP(pp_add)
                    buv = (UV)-biv;
            }
            /* ?uvok if value is >= 0. basically, flagged as UV if it's +ve,
-              else "IV" now, independant of how it came in.
+              else "IV" now, independent of how it came in.
               if a, b represents positive, A, B negative, a maps to -A etc
               a + b =>  (a + b)
               A + b => -(a - b)
@@ -942,11 +927,11 @@ S_do_oddball(pTHX_ HV *hash, SV **relem, SV **firstrelem)
                (SvTYPE(SvRV(*relem)) == SVt_PVAV ||
                 SvTYPE(SvRV(*relem)) == SVt_PVHV))
            {
-               Perl_warner(aTHX_ WARN_MISC,
+               Perl_warner(aTHX_ packWARN(WARN_MISC),
                            "Reference found where even-sized list expected");
            }
            else
-               Perl_warner(aTHX_ WARN_MISC,
+               Perl_warner(aTHX_ packWARN(WARN_MISC),
                            "Odd number of elements in hash assignment");
        }
        if (SvTYPE(hash) == SVt_PVAV) {
@@ -1199,6 +1184,7 @@ PP(pp_match)
 {
     dSP; dTARG;
     register PMOP *pm = cPMOP;
+    PMOP *dynpm = pm;
     register char *t;
     register char *s;
     char *strend;
@@ -1232,6 +1218,7 @@ PP(pp_match)
 
     PL_reg_match_utf8 = DO_UTF8(TARG);
 
+    /* PMdf_USED is set after a ?? matches once */
     if (pm->op_pmdynflags & PMdf_USED) {
       failure:
        if (gimme == G_ARRAY)
@@ -1239,16 +1226,19 @@ PP(pp_match)
        RETPUSHNO;
     }
 
+    /* empty pattern special-cased to use last successful pattern if possible */
     if (!rx->prelen && PL_curpm) {
        pm = PL_curpm;
        rx = PM_GETRE(pm);
     }
-    if (rx->minlen > len) goto failure;
+
+    if (rx->minlen > len)
+       goto failure;
 
     truebase = t = s;
 
     /* XXXX What part of this is needed with true \G-support? */
-    if ((global = pm->op_pmflags & PMf_GLOBAL)) {
+    if ((global = dynpm->op_pmflags & PMf_GLOBAL)) {
        rx->startp[0] = -1;
        if (SvTYPE(TARG) >= SVt_PVMG && SvMAGIC(TARG)) {
            MAGIC* mg = mg_find(TARG, PERL_MAGIC_regex_global);
@@ -1264,7 +1254,9 @@ PP(pp_match)
            }
        }
     }
-    r_flags |= REXEC_COPY_STR;
+    if ((!global && rx->nparens)
+           || SvTEMP(TARG) || PL_sawampersand)
+       r_flags |= REXEC_COPY_STR;
     if (SvSCREAM(TARG))
        r_flags |= REXEC_SCREAM;
 
@@ -1289,7 +1281,7 @@ play_it_again:
        if (!s)
            goto nope;
        if ( (rx->reganch & ROPT_CHECK_ALL)
-            && !((rx->reganch & ROPT_SEOL_SEEN) && PL_multiline)
+            && !PL_sawampersand
             && ((rx->reganch & ROPT_NOSCAN)
                 || !((rx->reganch & RE_INTUIT_TAIL)
                      && (r_flags & REXEC_SCREAM)))
@@ -1299,8 +1291,8 @@ play_it_again:
     if (CALLREGEXEC(aTHX_ rx, s, strend, truebase, minmatch, TARG, NULL, r_flags))
     {
        PL_curpm = pm;
-       if (pm->op_pmflags & PMf_ONCE)
-           pm->op_pmdynflags |= PMdf_USED;
+       if (dynpm->op_pmflags & PMf_ONCE)
+           dynpm->op_pmdynflags |= PMdf_USED;
        goto gotcha;
     }
     else
@@ -1327,6 +1319,9 @@ play_it_again:
            /*SUPPRESS 560*/
            if ((rx->startp[i] != -1) && rx->endp[i] != -1 ) {
                len = rx->endp[i] - rx->startp[i];
+               if (rx->endp[i] < 0 || rx->startp[i] < 0 ||
+                   len < 0 || len > strend - s)
+                   DIE(aTHX_ "panic: pp_match start/end pointers");
                s = rx->startp[i] + truebase;
                sv_setpvn(*SP, s, len);
                if (DO_UTF8(TARG) && is_utf8_string((U8*)s, len))
@@ -1334,7 +1329,7 @@ play_it_again:
            }
        }
        if (global) {
-           if (pm->op_pmflags & PMf_CONTINUE) {
+           if (dynpm->op_pmflags & PMf_CONTINUE) {
                MAGIC* mg = 0;
                if (SvTYPE(TARG) >= SVt_PVMG && SvMAGIC(TARG))
                    mg = mg_find(TARG, PERL_MAGIC_regex_global);
@@ -1387,8 +1382,8 @@ yup:                                      /* Confirmed by INTUIT */
        RX_MATCH_TAINTED_on(rx);
     TAINT_IF(RX_MATCH_TAINTED(rx));
     PL_curpm = pm;
-    if (pm->op_pmflags & PMf_ONCE)
-       pm->op_pmdynflags |= PMdf_USED;
+    if (dynpm->op_pmflags & PMf_ONCE)
+       dynpm->op_pmdynflags |= PMdf_USED;
     if (RX_MATCH_COPIED(rx))
        Safefree(rx->subbeg);
     RX_MATCH_COPIED_off(rx);
@@ -1406,19 +1401,26 @@ yup:                                    /* Confirmed by INTUIT */
        rx->sublen = strend - truebase;
        goto gotcha;
     }
+    if (PL_sawampersand) {
+       I32 off;
 
-    rx->sublen = strend - t;
-    rx->subbeg = savepvn(t, rx->sublen);
-    RX_MATCH_COPIED_on(rx);
-    rx->startp[0] = s - truebase;
-    rx->endp[0] = s - truebase + rx->minlen;
+       rx->subbeg = savepvn(t, strend - t);
+       rx->sublen = strend - t;
+       RX_MATCH_COPIED_on(rx);
+       off = rx->startp[0] = s - t;
+       rx->endp[0] = off + rx->minlen;
+    }
+    else {                     /* startp/endp are used by @- @+. */
+       rx->startp[0] = s - truebase;
+       rx->endp[0] = s - truebase + rx->minlen;
+    }
     rx->nparens = rx->lastparen = 0;   /* used by @- and @+ */
     LEAVE_SCOPE(oldsave);
     RETPUSHYES;
 
 nope:
 ret_no:
-    if (global && !(pm->op_pmflags & PMf_CONTINUE)) {
+    if (global && !(dynpm->op_pmflags & PMf_CONTINUE)) {
        if (SvTYPE(TARG) >= SVt_PVMG && SvMAGIC(TARG)) {
            MAGIC* mg = mg_find(TARG, PERL_MAGIC_regex_global);
            if (mg)
@@ -1490,7 +1492,7 @@ Perl_do_readline(pTHX)
        if (ckWARN2(WARN_GLOB, WARN_CLOSED)
                && (!io || !(IoFLAGS(io) & IOf_START))) {
            if (type == OP_GLOB)
-               Perl_warner(aTHX_ WARN_GLOB,
+               Perl_warner(aTHX_ packWARN(WARN_GLOB),
                            "glob failed (can't start child: %s)",
                            Strerror(errno));
            else
@@ -1547,7 +1549,7 @@ Perl_do_readline(pTHX)
            }
            else if (type == OP_GLOB) {
                if (!do_close(PL_last_in_gv, FALSE) && ckWARN(WARN_GLOB)) {
-                   Perl_warner(aTHX_ WARN_GLOB,
+                   Perl_warner(aTHX_ packWARN(WARN_GLOB),
                           "glob failed (child exited with status %d%s)",
                           (int)(STATUS_CURRENT >> 8),
                           (STATUS_CURRENT & 0x80) ? ", core dumped" : "");
@@ -1890,6 +1892,7 @@ PP(pp_subst)
     int force_on_match = 0;
     I32 oldsave = PL_savestack_ix;
     STRLEN slen;
+    bool doutf8 = FALSE;
 
     /* known replacement string? */
     dstr = (pm->op_pmflags & PMf_CONST) ? POPs : Nullsv;
@@ -1962,8 +1965,15 @@ PP(pp_subst)
     once = !(rpm->op_pmflags & PMf_GLOBAL);
 
     /* known replacement string? */
-    c = dstr ? SvPV(dstr, clen) : Nullch;
-
+    if (dstr) {
+        c = SvPV(dstr, clen);
+       doutf8 = DO_UTF8(dstr);
+    }
+    else {
+        c = Nullch;
+       doutf8 = FALSE;
+    }
+    
     /* can do inplace substitution? */
     if (c && clen <= rx->minlen && (once || !(r_flags & REXEC_COPY_STR))
        && !(rx->reganch & ROPT_LOOKBEHIND_SEEN)) {
@@ -2069,8 +2079,6 @@ PP(pp_subst)
     if (CALLREGEXEC(aTHX_ rx, s, strend, orig, 0, TARG, NULL,
                    r_flags | REXEC_CHECKED))
     {
-       bool isutf8;
-
        if (force_on_match) {
            force_on_match = 0;
            s = SvPV_force(TARG, len);
@@ -2116,7 +2124,7 @@ PP(pp_subst)
        SvPVX(TARG) = SvPVX(dstr);
        SvCUR_set(TARG, SvCUR(dstr));
        SvLEN_set(TARG, SvLEN(dstr));
-       isutf8 = DO_UTF8(dstr);
+       doutf8 |= DO_UTF8(dstr);
        SvPVX(dstr) = 0;
        sv_free(dstr);
 
@@ -2125,7 +2133,7 @@ PP(pp_subst)
        PUSHs(sv_2mortal(newSViv((I32)iters)));
 
        (void)SvPOK_only(TARG);
-       if (isutf8)
+       if (doutf8)
            SvUTF8_on(TARG);
        TAINT_IF(rxtainted);
        SvSETMAGIC(TARG);
@@ -2881,11 +2889,11 @@ void
 Perl_sub_crush_depth(pTHX_ CV *cv)
 {
     if (CvANON(cv))
-       Perl_warner(aTHX_ WARN_RECURSION, "Deep recursion on anonymous subroutine");
+       Perl_warner(aTHX_ packWARN(WARN_RECURSION), "Deep recursion on anonymous subroutine");
     else {
        SV* tmpstr = sv_newmortal();
        gv_efullname3(tmpstr, CvGV(cv), Nullch);
-       Perl_warner(aTHX_ WARN_RECURSION, "Deep recursion on subroutine \"%s\"",
+       Perl_warner(aTHX_ packWARN(WARN_RECURSION), "Deep recursion on subroutine \"%s\"",
                SvPVX(tmpstr));
     }
 }
@@ -2902,7 +2910,7 @@ PP(pp_aelem)
     SV *sv;
 
     if (SvROK(elemsv) && !SvGAMAGIC(elemsv) && ckWARN(WARN_MISC))
-       Perl_warner(aTHX_ WARN_MISC, "Use of reference \"%s\" as array index", SvPV_nolen(elemsv));
+       Perl_warner(aTHX_ packWARN(WARN_MISC), "Use of reference \"%s\" as array index", SvPV_nolen(elemsv));
     if (elem > 0)
        elem -= PL_curcop->cop_arybase;
     if (SvTYPE(av) != SVt_PVAV)