This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Revert change 23843.
[perl5.git] / pp_ctl.c
index ec21e69..829b655 100644 (file)
--- a/pp_ctl.c
+++ b/pp_ctl.c
@@ -1,7 +1,7 @@
 /*    pp_ctl.c
  *
  *    Copyright (C) 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
- *    2000, 2001, 2002, 2003, 2004, by Larry Wall and others
+ *    2000, 2001, 2002, 2003, 2004, 2005, by Larry Wall and others
  *
  *    You may distribute under the terms of either the GNU General Public
  *    License or the Artistic License, as specified in the README file.
  * And whither then?  I cannot say.
  */
 
+/* This file contains control-oriented pp ("push/pop") functions that
+ * execute the opcodes that make up a perl program. A typical pp function
+ * expects to find its arguments on the stack, and usually pushes its
+ * results onto the stack, hence the 'pp' terminology. Each OP structure
+ * contains a pointer to the relevant pp_foo() function.
+ *
+ * Control-oriented means things like pp_enteriter() and pp_next(), which
+ * alter the flow of control of the program.
+ */
+
+
 #include "EXTERN.h"
 #define PERL_IN_PP_CTL_C
 #include "perl.h"
@@ -72,13 +83,40 @@ PP(pp_regcomp)
     STRLEN len;
     MAGIC *mg = Null(MAGIC*);
     
-    tmpstr = POPs;
-
     /* prevent recompiling under /o and ithreads. */
 #if defined(USE_ITHREADS)
-    if (pm->op_pmflags & PMf_KEEP && PM_GETRE(pm))
-        RETURN;
+    if (pm->op_pmflags & PMf_KEEP && PM_GETRE(pm)) {
+       if (PL_op->op_flags & OPf_STACKED) {
+           dMARK;
+           SP = MARK;
+       }
+       else
+           (void)POPs;
+       RETURN;
+    }
 #endif
+    if (PL_op->op_flags & OPf_STACKED) {
+       /* multiple args; concatentate them */
+       dMARK; dORIGMARK;
+       tmpstr = PAD_SV(ARGTARG);
+       sv_setpvn(tmpstr, "", 0);
+       while (++MARK <= SP) {
+           if (PL_amagic_generation) {
+               SV *sv;
+               if ((SvAMAGIC(tmpstr) || SvAMAGIC(*MARK)) &&
+                   (sv = amagic_call(tmpstr, *MARK, concat_amg, AMGf_assign)))
+               {
+                  sv_setsv(tmpstr, sv);
+                  continue;
+               }
+           }
+           sv_catsv(tmpstr, *MARK);
+       }
+       SvSETMAGIC(tmpstr);
+       SP = ORIGMARK;
+    }
+    else
+       tmpstr = POPs;
 
     if (SvROK(tmpstr)) {
        SV *sv = SvRV(tmpstr);
@@ -187,10 +225,13 @@ PP(pp_substcont)
        {
            SV *targ = cx->sb_targ;
 
-           if (DO_UTF8(dstr) && !SvUTF8(targ))
-               sv_catpvn_utf8_upgrade(dstr, s, cx->sb_strend - s, nsv);
-           else
-               sv_catpvn(dstr, s, cx->sb_strend - s);
+           assert(cx->sb_strend >= s);
+           if(cx->sb_strend > s) {
+                if (DO_UTF8(dstr) && !SvUTF8(targ))
+                     sv_catpvn_utf8_upgrade(dstr, s, cx->sb_strend - s, nsv);
+                else
+                     sv_catpvn(dstr, s, cx->sb_strend - s);
+           }
            cx->sb_rxtainted |= RX_MATCH_TAINTED(rx);
 
 #ifdef PERL_COPY_ON_WRITE
@@ -199,7 +240,7 @@ PP(pp_substcont)
            } else
 #endif
            {
-               (void)SvOOK_off(targ);
+               SvOOK_off(targ);
                if (SvLEN(targ))
                    Safefree(SvPVX(targ));
            }
@@ -365,7 +406,8 @@ PP(pp_formline)
     NV value;
     bool gotsome = FALSE;
     STRLEN len;
-    STRLEN fudge = SvCUR(tmpForm) * (IN_BYTES ? 1 : 3) + 1;
+    STRLEN fudge = SvPOK(tmpForm)
+                       ? (SvCUR(tmpForm) * (IN_BYTES ? 1 : 3) + 1) : 0;
     bool item_is_utf8 = FALSE;
     bool targ_is_utf8 = FALSE;
     SV * nsv = Nullsv;
@@ -1431,7 +1473,8 @@ Perl_die_where(pTHX_ char *message, STRLEN msglen)
                DIE(aTHX_ "%sCompilation failed in require",
                    *msg ? msg : "Unknown error\n");
            }
-           return pop_return();
+           assert(CxTYPE(cx) == CXt_EVAL);
+           return cx->blk_eval.retop;
        }
     }
     if (!message)
@@ -1725,9 +1768,9 @@ PP(pp_dbstate)
        hasargs = 0;
        SPAGAIN;
 
-       push_return(PL_op->op_next);
        PUSHBLOCK(cx, CXt_SUB, SP);
        PUSHSUB_DB(cx);
+       cx->blk_sub.retop = PL_op->op_next;
        CvDEPTH(cv)++;
        PAD_SET_CUR(CvPADLIST(cv),1);
        RETURNOP(CvSTART(cv));
@@ -1807,11 +1850,22 @@ PP(pp_enteriter)
                (void) SvPV(right,n_a);
            }
        }
+       else if (PL_op->op_private & OPpITER_REVERSED) {
+           cx->blk_loop.itermax = -1;
+           cx->blk_loop.iterix = AvFILL(cx->blk_loop.iterary);
+
+       }
     }
     else {
        cx->blk_loop.iterary = PL_curstack;
        AvFILLp(PL_curstack) = SP - PL_stack_base;
-       cx->blk_loop.iterix = MARK - PL_stack_base;
+       if (PL_op->op_private & OPpITER_REVERSED) {
+           cx->blk_loop.itermax = MARK - PL_stack_base;
+           cx->blk_loop.iterix = cx->blk_oldsp;
+       }
+       else {
+           cx->blk_loop.iterix = MARK - PL_stack_base;
+       }
     }
 
     RETURN;
@@ -1885,6 +1939,7 @@ PP(pp_return)
     PMOP *newpm;
     I32 optype = 0;
     SV *sv;
+    OP *retop;
 
     if (PL_curstackinfo->si_type == PERLSI_SORT) {
        if (cxstack_ix == PL_sortcxix
@@ -1908,12 +1963,14 @@ PP(pp_return)
     switch (CxTYPE(cx)) {
     case CXt_SUB:
        popsub2 = TRUE;
+       retop = cx->blk_sub.retop;
        cxstack_ix++; /* preserve cx entry on stack for use by POPSUB */
        break;
     case CXt_EVAL:
        if (!(PL_in_eval & EVAL_KEEPERR))
            clear_errsv = TRUE;
        POPEVAL(cx);
+       retop = cx->blk_eval.retop;
        if (CxTRYBLOCK(cx))
            break;
        lex_end();
@@ -1928,6 +1985,7 @@ PP(pp_return)
        break;
     case CXt_FORMAT:
        POPFORMAT(cx);
+       retop = cx->blk_sub.retop;
        break;
     default:
        DIE(aTHX_ "panic: return");
@@ -1981,7 +2039,7 @@ PP(pp_return)
     LEAVESUB(sv);
     if (clear_errsv)
        sv_setpv(ERRSV,"");
-    return pop_return();
+    return retop;
 }
 
 PP(pp_last)
@@ -2022,15 +2080,15 @@ PP(pp_last)
        break;
     case CXt_SUB:
        pop2 = CXt_SUB;
-       nextop = pop_return();
+       nextop = cx->blk_sub.retop;
        break;
     case CXt_EVAL:
        POPEVAL(cx);
-       nextop = pop_return();
+       nextop = cx->blk_eval.retop;
        break;
     case CXt_FORMAT:
        POPFORMAT(cx);
-       nextop = pop_return();
+       nextop = cx->blk_sub.retop;
        break;
     default:
        DIE(aTHX_ "panic: last");
@@ -2190,7 +2248,6 @@ PP(pp_goto)
     char *label;
     int do_dump = (PL_op->op_type == OP_DUMP);
     static char must_have_label[] = "goto must have label";
-    AV *oldav = Nullav;
 
     label = 0;
     if (PL_op->op_flags & OPf_STACKED) {
@@ -2205,6 +2262,7 @@ PP(pp_goto)
            SV** mark;
            I32 items = 0;
            I32 oldsave;
+           bool reified = 0;
 
        retry:
            if (!CvROOT(cv) && !CvXSUB(cv)) {
@@ -2237,38 +2295,35 @@ PP(pp_goto)
            TOPBLOCK(cx);
            if (CxREALEVAL(cx))
                DIE(aTHX_ "Can't goto subroutine from an eval-string");
-           mark = PL_stack_sp;
            if (CxTYPE(cx) == CXt_SUB && cx->blk_sub.hasargs) {
                /* put @_ back onto stack */
                AV* av = cx->blk_sub.argarray;
                
                items = AvFILLp(av) + 1;
-               PL_stack_sp++;
-               EXTEND(PL_stack_sp, items); /* @_ could have been extended. */
-               Copy(AvARRAY(av), PL_stack_sp, items, SV*);
-               PL_stack_sp += items;
+               EXTEND(SP, items+1); /* @_ could have been extended. */
+               Copy(AvARRAY(av), SP + 1, items, SV*);
                SvREFCNT_dec(GvAV(PL_defgv));
                GvAV(PL_defgv) = cx->blk_sub.savearray;
+               CLEAR_ARGARRAY(av);
                /* abandon @_ if it got reified */
                if (AvREAL(av)) {
-                   oldav = av; /* delay until return */
+                   reified = 1;
+                   SvREFCNT_dec(av);
                    av = newAV();
                    av_extend(av, items-1);
                    AvFLAGS(av) = AVf_REIFY;
                    PAD_SVl(0) = (SV*)(cx->blk_sub.argarray = av);
                }
-               else
-                   CLEAR_ARGARRAY(av);
            }
            else if (CvXSUB(cv)) {      /* put GvAV(defgv) back onto stack */
                AV* av;
                av = GvAV(PL_defgv);
                items = AvFILLp(av) + 1;
-               PL_stack_sp++;
-               EXTEND(PL_stack_sp, items); /* @_ could have been extended. */
-               Copy(AvARRAY(av), PL_stack_sp, items, SV*);
-               PL_stack_sp += items;
+               EXTEND(SP, items+1); /* @_ could have been extended. */
+               Copy(AvARRAY(av), SP + 1, items, SV*);
            }
+           mark = SP;
+           SP += items;
            if (CxTYPE(cx) == CXt_SUB &&
                !(CvDEPTH(cx->blk_sub.cv) = cx->blk_sub.olddepth))
                SvREFCNT_dec(cx->blk_sub.cv);
@@ -2277,11 +2332,13 @@ PP(pp_goto)
 
            /* Now do some callish stuff. */
            SAVETMPS;
-           /* For reified @_, delay freeing till return from new sub */
-           if (oldav)
-               SAVEFREESV((SV*)oldav);
            SAVEFREESV(cv); /* later, undo the 'avoid premature free' hack */
            if (CvXSUB(cv)) {
+               if (reified) {
+                   I32 index;
+                   for (index=0; index<items; index++)
+                       sv_2mortal(SP[-index]);
+               }
 #ifdef PERL_XSUB_OLDSTYLE
                if (CvOLDSTYLE(cv)) {
                    I32 (*fp3)(int,int,int);
@@ -2301,16 +2358,17 @@ PP(pp_goto)
                    SV **newsp;
                    I32 gimme;
 
-                   PL_stack_sp--;              /* There is no cv arg. */
                    /* Push a mark for the start of arglist */
                    PUSHMARK(mark);
+                   PUTBACK;
                    (void)(*CvXSUB(cv))(aTHX_ cv);
                    /* Pop the current context like a decent sub should */
                    POPBLOCK(cx, PL_curpm);
                    /* Do _not_ use PUTBACK, keep the XSUB's return stack! */
                }
                LEAVE;
-               return pop_return();
+               assert(CxTYPE(cx) == CXt_SUB);
+               return cx->blk_sub.retop;
            }
            else {
                AV* padlist = CvPADLIST(cv);
@@ -2329,7 +2387,7 @@ PP(pp_goto)
                else {
                    if (CvDEPTH(cv) == 100 && ckWARN(WARN_RECURSION))
                        sub_crush_depth(cv);
-                   pad_push(padlist, CvDEPTH(cv), cx->blk_sub.hasargs);
+                   pad_push(padlist, CvDEPTH(cv), 1);
                }
                PAD_SET_CUR(padlist, CvDEPTH(cv));
                if (cx->blk_sub.hasargs)
@@ -2341,7 +2399,6 @@ PP(pp_goto)
                    GvAV(PL_defgv) = (AV*)SvREFCNT_inc(av);
                    CX_CURPAD_SAVE(cx->blk_sub);
                    cx->blk_sub.argarray = av;
-                   ++mark;
 
                    if (items >= AvMAX(av) + 1) {
                        ary = AvALLOC(av);
@@ -2356,9 +2413,15 @@ PP(pp_goto)
                            SvPVX(av) = (char*)ary;
                        }
                    }
+                   ++mark;
                    Copy(mark,AvARRAY(av),items,SV*);
                    AvFILLp(av) = items - 1;
                    assert(!AvREAL(av));
+                   if (reified) {
+                       /* transfer 'ownership' of refcnts to new @_ */
+                       AvREAL_on(av);
+                       AvREIFY_off(av);
+                   }
                    while (items--) {
                        if (*mark)
                            SvTEMP_off(*mark);
@@ -2611,14 +2674,6 @@ S_save_lines(pTHX_ AV *array, SV *sv)
     }
 }
 
-#ifdef PERL_FLEXIBLE_EXCEPTIONS
-STATIC void *
-S_docatch_body(pTHX_ va_list args)
-{
-    return docatch_body();
-}
-#endif
-
 STATIC void *
 S_docatch_body(pTHX)
 {
@@ -2645,21 +2700,16 @@ S_docatch(pTHX_ OP *o)
      * the op to Nullop, we force an exit from the inner runops()
      * loop. DAPM.
      */
-    retop = pop_return();
-    push_return(Nullop);
+    assert(cxstack_ix >= 0);
+    assert(CxTYPE(&cxstack[cxstack_ix]) == CXt_EVAL);
+    retop = cxstack[cxstack_ix].blk_eval.retop;
+    cxstack[cxstack_ix].blk_eval.retop = Nullop;
 
-#ifdef PERL_FLEXIBLE_EXCEPTIONS
- redo_body:
-    CALLPROTECT(aTHX_ pcur_env, &ret, MEMBER_TO_FPTR(S_docatch_body));
-#else
     JMPENV_PUSH(ret);
-#endif
     switch (ret) {
     case 0:
-#ifndef PERL_FLEXIBLE_EXCEPTIONS
  redo_body:
        docatch_body();
-#endif
        break;
     case 3:
        /* die caught by an inner eval - continue inner loop */
@@ -2778,7 +2828,7 @@ Locate the CV corresponding to the currently executing sub or eval.
 If db_seqp is non_null, skip CVs that are in the DB package and populate
 *db_seqp with the cop sequence number at the point that the DB:: code was
 entered. (allows debuggers to eval in the scope of the breakpoint rather
-than in in the scope of the debuger itself).
+than in in the scope of the debugger itself).
 
 =cut
 */
@@ -2884,7 +2934,6 @@ S_doeval(pTHX_ int gimme, OP** startop, CV* outside, U32 seq)
        if (!startop) {
            POPBLOCK(cx,PL_curpm);
            POPEVAL(cx);
-           pop_return();
        }
        lex_end();
        LEAVE;
@@ -3015,66 +3064,19 @@ PP(pp_require)
     OP *op;
 
     sv = POPs;
-    if (SvNIOKp(sv) && PL_op->op_type != OP_DOFILE) {
-       if (SvPOK(sv) && SvNOK(sv) && SvNV(sv)) {               /* require v5.6.1 */
-           UV rev = 0, ver = 0, sver = 0;
-           STRLEN len;
-           U8 *s = (U8*)SvPVX(sv);
-           U8 *end = (U8*)SvPVX(sv) + SvCUR(sv);
-           if (s < end) {
-               rev = utf8n_to_uvchr(s, end - s, &len, 0);
-               s += len;
-               if (s < end) {
-                   ver = utf8n_to_uvchr(s, end - s, &len, 0);
-                   s += len;
-                   if (s < end)
-                       sver = utf8n_to_uvchr(s, end - s, &len, 0);
-               }
-           }
-           if (PERL_REVISION < rev
-               || (PERL_REVISION == rev
-                   && (PERL_VERSION < ver
-                       || (PERL_VERSION == ver
-                           && PERL_SUBVERSION < sver))))
-           {
-               DIE(aTHX_ "Perl v%"UVuf".%"UVuf".%"UVuf" required--this is only "
-                   "v%d.%d.%d, stopped", rev, ver, sver, PERL_REVISION,
-                   PERL_VERSION, PERL_SUBVERSION);
-           }
-           if (ckWARN(WARN_PORTABLE))
+    if ( (SvNIOKp(sv) || SvVOK(sv)) && PL_op->op_type != OP_DOFILE) {
+       if ( SvVOK(sv) && ckWARN(WARN_PORTABLE) )       /* require v5.6.1 */
                Perl_warner(aTHX_ packWARN(WARN_PORTABLE),
                         "v-string in use/require non-portable");
+
+       sv = new_version(sv);
+       if (!sv_derived_from(PL_patchlevel, "version"))
+           (void *)upg_version(PL_patchlevel);
+       if ( vcmp(sv,PL_patchlevel) > 0 )
+           DIE(aTHX_ "Perl v%"SVf" required--this is only v%"SVf", stopped",
+               vstringify(sv), vstringify(PL_patchlevel));
+
            RETPUSHYES;
-       }
-       else if (!SvPOKp(sv)) {                 /* require 5.005_03 */
-           if ((NV)PERL_REVISION + ((NV)PERL_VERSION/(NV)1000)
-               + ((NV)PERL_SUBVERSION/(NV)1000000)
-               + 0.00000099 < SvNV(sv))
-           {
-               NV nrev = SvNV(sv);
-               UV rev = (UV)nrev;
-               NV nver = (nrev - rev) * 1000;
-               UV ver = (UV)(nver + 0.0009);
-               NV nsver = (nver - ver) * 1000;
-               UV sver = (UV)(nsver + 0.0009);
-
-               /* help out with the "use 5.6" confusion */
-               if (sver == 0 && (rev > 5 || (rev == 5 && ver >= 100))) {
-                   DIE(aTHX_ "Perl v%"UVuf".%"UVuf".%"UVuf" required"
-                       " (did you mean v%"UVuf".%03"UVuf"?)--"
-                       "this is only v%d.%d.%d, stopped",
-                       rev, ver, sver, rev, ver/100,
-                       PERL_REVISION, PERL_VERSION, PERL_SUBVERSION);
-               }
-               else {
-                   DIE(aTHX_ "Perl v%"UVuf".%"UVuf".%"UVuf" required--"
-                       "this is only v%d.%d.%d, stopped",
-                       rev, ver, sver, PERL_REVISION, PERL_VERSION,
-                       PERL_SUBVERSION);
-               }
-           }
-           RETPUSHYES;
-       }
     }
     name = SvPV(sv, len);
     if (!(name && len > 0 && *name))
@@ -3342,9 +3344,9 @@ PP(pp_require)
     }
 
     /* switch to eval mode */
-    push_return(PL_op->op_next);
     PUSHBLOCK(cx, CXt_EVAL, SP);
     PUSHEVAL(cx, name, Nullgv);
+    cx->blk_eval.retop = PL_op->op_next;
 
     SAVECOPLINE(&PL_compiling);
     CopLINE_set(&PL_compiling, 0);
@@ -3435,9 +3437,9 @@ PP(pp_entereval)
      * to do the dirty work for us */
     runcv = find_runcv(&seq);
 
-    push_return(PL_op->op_next);
     PUSHBLOCK(cx, (CXt_EVAL|CXp_REAL), SP);
     PUSHEVAL(cx, 0, Nullgv);
+    cx->blk_eval.retop = PL_op->op_next;
 
     /* prepare to compile string */
 
@@ -3466,7 +3468,7 @@ PP(pp_leaveeval)
 
     POPBLOCK(cx,newpm);
     POPEVAL(cx);
-    retop = pop_return();
+    retop = cx->blk_eval.retop;
 
     TAINT_NOT;
     if (gimme == G_VOID)
@@ -3529,9 +3531,9 @@ PP(pp_entertry)
     ENTER;
     SAVETMPS;
 
-    push_return(cLOGOP->op_other->op_next);
     PUSHBLOCK(cx, (CXt_EVAL|CXp_TRYBLOCK), SP);
     PUSHEVAL(cx, 0, 0);
+    cx->blk_eval.retop = cLOGOP->op_other->op_next;
 
     PL_in_eval = EVAL_INEVAL;
     sv_setpv(ERRSV,"");
@@ -3552,7 +3554,7 @@ PP(pp_leavetry)
 
     POPBLOCK(cx,newpm);
     POPEVAL(cx);
-    retop = pop_return();
+    retop = cx->blk_eval.retop;
 
     TAINT_NOT;
     if (gimme == G_VOID)
@@ -3924,3 +3926,13 @@ S_path_is_absolute(pTHX_ char *name)
     else
        return FALSE;
 }
+
+/*
+ * Local variables:
+ * c-indentation-style: bsd
+ * c-basic-offset: 4
+ * indent-tabs-mode: t
+ * End:
+ *
+ * vim: shiftwidth=4:
+*/