Support for op in global register (still buggy)
[p5sagit/p5-mst-13.2.git] / pp_ctl.c
index 4f41374..317ed70 100644 (file)
--- a/pp_ctl.c
+++ b/pp_ctl.c
@@ -27,7 +27,7 @@
 
 static OP *docatch _((OP *o));
 static OP *doeval _((int gimme));
-static OP *dofindlabel _((OP *op, char *label, OP **opstack));
+static OP *dofindlabel _((OP *o, char *label, OP **opstack, OP **oplimit));
 static void doparseform _((SV *sv));
 static I32 dopoptoeval _((I32 startingblock));
 static I32 dopoptolabel _((char *label));
@@ -94,7 +94,7 @@ PP(pp_regcomp) {
        pm->op_pmflags |= PMf_WHITE;
 
     if (pm->op_pmflags & PMf_KEEP) {
-       pm->op_pmflags &= ~PMf_RUNTIME; /* no point compiling again */
+       pm->op_private &= ~OPpRUNTIME;  /* no point compiling again */
        hoistmust(pm);
        cLOGOP->op_first->op_next = op->op_next;
     }
@@ -112,6 +112,8 @@ PP(pp_substcont)
     char *orig = cx->sb_orig;
     register REGEXP *rx = cx->sb_rx;
 
+    rxres_restore(&cx->sb_rxres, rx);
+
     if (cx->sb_iters++) {
        if (cx->sb_iters > cx->sb_maxiters)
            DIE("Substitution loop");
@@ -119,9 +121,6 @@ PP(pp_substcont)
        if (!cx->sb_rxtainted)
            cx->sb_rxtainted = SvTAINTED(TOPs);
        sv_catsv(dstr, POPs);
-       if (rx->subbase)
-           Safefree(rx->subbase);
-       rx->subbase = cx->sb_subbase;
 
        /* Are we done */
        if (cx->sb_once || !pregexec(rx, s, cx->sb_strend, orig,
@@ -139,10 +138,10 @@ PP(pp_substcont)
            SvLEN_set(targ, SvLEN(dstr));
            SvPVX(dstr) = 0;
            sv_free(dstr);
-
            (void)SvPOK_only(targ);
            SvSETMAGIC(targ);
            SvTAINT(targ);
+
            PUSHs(sv_2mortal(newSViv((I32)cx->sb_iters - 1)));
            LEAVE_SCOPE(cx->sb_oldsave);
            POPSUBST(cx);
@@ -159,13 +158,76 @@ PP(pp_substcont)
     cx->sb_m = m = rx->startp[0];
     sv_catpvn(dstr, s, m-s);
     cx->sb_s = rx->endp[0];
-    cx->sb_subbase = rx->subbase;
     cx->sb_rxtainted |= rx->exec_tainted;
-
-    rx->subbase = Nullch;      /* so recursion works */
+    rxres_save(&cx->sb_rxres, rx);
     RETURNOP(pm->op_pmreplstart);
 }
 
+void
+rxres_save(rsp, rx)
+void **rsp;
+REGEXP *rx;
+{
+    UV *p = (UV*)*rsp;
+    U32 i;
+
+    if (!p || p[1] < rx->nparens) {
+       i = 6 + rx->nparens * 2;
+       if (!p)
+           New(501, p, i, UV);
+       else
+           Renew(p, i, UV);
+       *rsp = (void*)p;
+    }
+
+    *p++ = (UV)rx->subbase;
+    rx->subbase = Nullch;
+
+    *p++ = rx->nparens;
+
+    *p++ = (UV)rx->subbeg;
+    *p++ = (UV)rx->subend;
+    for (i = 0; i <= rx->nparens; ++i) {
+       *p++ = (UV)rx->startp[i];
+       *p++ = (UV)rx->endp[i];
+    }
+}
+
+void
+rxres_restore(rsp, rx)
+void **rsp;
+REGEXP *rx;
+{
+    UV *p = (UV*)*rsp;
+    U32 i;
+
+    Safefree(rx->subbase);
+    rx->subbase = (char*)(*p);
+    *p++ = 0;
+
+    rx->nparens = *p++;
+
+    rx->subbeg = (char*)(*p++);
+    rx->subend = (char*)(*p++);
+    for (i = 0; i <= rx->nparens; ++i) {
+       rx->startp[i] = (char*)(*p++);
+       rx->endp[i] = (char*)(*p++);
+    }
+}
+
+void
+rxres_free(rsp)
+void **rsp;
+{
+    UV *p = (UV*)*rsp;
+
+    if (p) {
+       Safefree((char*)(*p));
+       Safefree(p);
+       *rsp = Null(void*);
+    }
+}
+
 PP(pp_formline)
 {
     dSP; dMARK; dORIGMARK;
@@ -471,8 +533,8 @@ PP(pp_grepstart)
        RETURNOP(op->op_next->op_next);
     }
     stack_sp = stack_base + *markstack_ptr + 1;
-    pp_pushmark();                             /* push dst */
-    pp_pushmark();                             /* push src */
+    pp_pushmark(ARGS);                         /* push dst */
+    pp_pushmark(ARGS);                         /* push src */
     ENTER;                                     /* enter outer scope */
 
     SAVETMPS;
@@ -487,7 +549,7 @@ PP(pp_grepstart)
 
     PUTBACK;
     if (op->op_type == OP_MAPSTART)
-       pp_pushmark();                          /* push top */
+       pp_pushmark(ARGS);                      /* push top */
     return ((LOGOP*)op->op_next)->op_other;
 }
 
@@ -607,7 +669,7 @@ PP(pp_sort)
            sortcop = CvSTART(cv);
            SAVESPTR(CvROOT(cv)->op_ppaddr);
            CvROOT(cv)->op_ppaddr = ppaddr[OP_NULL];
-           
+
            SAVESPTR(curpad);
            curpad = AvARRAY((AV*)AvARRAY(CvPADLIST(cv))[1]);
        }
@@ -636,7 +698,7 @@ PP(pp_sort)
            bool oldcatch = CATCH_GET;
 
            SAVETMPS;
-           SAVESPTR(op);
+           SAVEOP();
 
            oldstack = curstack;
            if (!sortstack) {
@@ -654,7 +716,16 @@ PP(pp_sort)
 
            SAVESPTR(GvSV(firstgv));
            SAVESPTR(GvSV(secondgv));
+
            PUSHBLOCK(cx, CXt_NULL, stack_base);
+           if (!(op->op_flags & OPf_SPECIAL)) {
+               bool hasargs = FALSE;
+               cx->cx_type = CXt_SUB;
+               cx->blk_gimme = G_SCALAR;
+               PUSHSUB(cx);
+               if (!CvDEPTH(cv))
+                   SvREFCNT_inc(cv);   /* in preparation for POPSUB */
+           }
            sortcxix = cxstack_ix;
 
            qsort((char*)(myorigmark+1), max, sizeof(SV*), sortcv);
@@ -778,6 +849,7 @@ static I32
 dopoptolabel(label)
 char *label;
 {
+    dTHR;
     register I32 i;
     register CONTEXT *cx;
 
@@ -824,11 +896,12 @@ dowantarray()
 I32
 block_gimme()
 {
+    dTHR;
     I32 cxix;
 
     cxix = dopoptosub(cxstack_ix);
     if (cxix < 0)
-       return G_SCALAR;
+       return G_VOID;
 
     switch (cxstack[cxix].blk_gimme) {
     case G_VOID:
@@ -846,6 +919,7 @@ static I32
 dopoptosub(startingblock)
 I32 startingblock;
 {
+    dTHR;
     I32 i;
     register CONTEXT *cx;
     for (i = startingblock; i >= 0; i--) {
@@ -866,6 +940,7 @@ static I32
 dopoptoeval(startingblock)
 I32 startingblock;
 {
+    dTHR;
     I32 i;
     register CONTEXT *cx;
     for (i = startingblock; i >= 0; i--) {
@@ -885,6 +960,7 @@ static I32
 dopoptoloop(startingblock)
 I32 startingblock;
 {
+    dTHR;
     I32 i;
     register CONTEXT *cx;
     for (i = startingblock; i >= 0; i--) {
@@ -918,16 +994,20 @@ void
 dounwind(cxix)
 I32 cxix;
 {
+    dTHR;
     register CONTEXT *cx;
     SV **newsp;
     I32 optype;
 
     while (cxstack_ix > cxix) {
-       cx = &cxstack[cxstack_ix--];
-       DEBUG_l(PerlIO_printf(Perl_debug_log, "Unwinding block %ld, type %s\n", (long) cxstack_ix+1,
-                   block_type[cx->cx_type]));
+       cx = &cxstack[cxstack_ix];
+       DEBUG_l(PerlIO_printf(Perl_debug_log, "Unwinding block %ld, type %s\n",
+                             (long) cxstack_ix+1, block_type[cx->cx_type]));
        /* Note: we don't need to restore the base context info till the end. */
        switch (cx->cx_type) {
+       case CXt_SUBST:
+           POPSUBST(cx);
+           continue;  /* not break */
        case CXt_SUB:
            POPSUB(cx);
            break;
@@ -938,9 +1018,9 @@ I32 cxix;
            POPLOOP(cx);
            break;
        case CXt_NULL:
-       case CXt_SUBST:
            break;
        }
+       cxstack_ix--;
     }
 }
 
@@ -948,6 +1028,7 @@ OP *
 die_where(message)
 char *message;
 {
+    dTHR;
     if (in_eval) {
        I32 cxix;
        register CONTEXT *cx;
@@ -994,8 +1075,10 @@ char *message;
 
            LEAVE;
 
-           if (optype == OP_REQUIRE)
-               DIE("%s", SvPVx(GvSV(errgv), na));
+           if (optype == OP_REQUIRE) {
+               char* msg = SvPVx(GvSV(errgv), na);
+               DIE("%s", *msg ? msg : "Compilation failed in require");
+           }
            return pop_return();
        }
     }
@@ -1044,7 +1127,7 @@ PP(pp_entersubr)
        mark++;
     }
     *sp = cv;
-    return pp_entersub();
+    return pp_entersub(ARGS);
 }
 #endif
 
@@ -1150,6 +1233,7 @@ sortcv(a, b)
 const void *a;
 const void *b;
 {
+    dTHR;
     SV * const *str1 = (SV * const *)a;
     SV * const *str2 = (SV * const *)b;
     I32 oldsaveix = savestack_ix;
@@ -1188,9 +1272,54 @@ const void *b;
     return sv_cmp_locale(*(SV * const *)a, *(SV * const *)b);
 }
 
+#ifdef USE_THREADS
+static void
+unlock_condpair(svv)
+void *svv;
+{
+    dTHR;
+    MAGIC *mg = mg_find((SV*)svv, 'm');
+    
+    if (!mg)
+       croak("panic: unlock_condpair unlocking non-mutex");
+    MUTEX_LOCK(MgMUTEXP(mg));
+    if (MgOWNER(mg) != thr)
+       croak("panic: unlock_condpair unlocking mutex that we don't own");
+    MgOWNER(mg) = 0;
+    COND_SIGNAL(MgOWNERCONDP(mg));
+    MUTEX_UNLOCK(MgMUTEXP(mg));
+}
+#endif /* USE_THREADS */
+
 PP(pp_reset)
 {
     dSP;
+#ifdef USE_THREADS
+    dTOPss;
+    MAGIC *mg;
+    
+    if (MAXARG < 1)
+       croak("reset requires mutex argument with USE_THREADS");
+    if (SvROK(sv)) {
+       /*
+        * Kludge to allow lock of real objects without requiring
+        * to pass in every type of argument by explicit reference.
+        */
+       sv = SvRV(sv);
+    }
+    mg = condpair_magic(sv);
+    MUTEX_LOCK(MgMUTEXP(mg));
+    if (MgOWNER(mg) == thr)
+       MUTEX_UNLOCK(MgMUTEXP(mg));
+    else {
+       while (MgOWNER(mg))
+           COND_WAIT(MgOWNERCONDP(mg), MgMUTEXP(mg));
+       MgOWNER(mg) = thr;
+       MUTEX_UNLOCK(MgMUTEXP(mg));
+       save_destructor(unlock_condpair, sv);
+    }
+    RETURN;
+#else
     char *tmps;
 
     if (MAXARG < 1)
@@ -1200,6 +1329,7 @@ PP(pp_reset)
     sv_reset(tmps, curcop->cop_stash);
     PUSHs(&sv_yes);
     RETURN;
+#endif /* USE_THREADS */
 }
 
 PP(pp_lineseq)
@@ -1320,6 +1450,7 @@ PP(pp_leaveloop)
     mark = newsp;
     POPLOOP1(cx);      /* Delay POPLOOP2 until stack values are safe */
 
+    TAINT_NOT;
     if (gimme == G_VOID)
        ; /* do nothing */
     else if (gimme == G_SCALAR) {
@@ -1329,8 +1460,10 @@ PP(pp_leaveloop)
            *++newsp = &sv_undef;
     }
     else {
-       while (mark < SP)
+       while (mark < SP) {
            *++newsp = sv_mortalcopy(*++mark);
+           TAINT_NOT;          /* Each item is independent */
+       }
     }
     SP = newsp;
     PUTBACK;
@@ -1357,7 +1490,7 @@ PP(pp_return)
     I32 optype = 0;
 
     if (curstack == sortstack) {
-       if (cxstack_ix == sortcxix || dopoptosub(cxstack_ix) < sortcxix) {
+       if (cxstack_ix == sortcxix || dopoptosub(cxstack_ix) <= sortcxix) {
            if (cxstack_ix > sortcxix)
                dounwind(sortcxix);
            AvARRAY(curstack)[1] = *SP;
@@ -1393,6 +1526,7 @@ PP(pp_return)
        DIE("panic: return");
     }
 
+    TAINT_NOT;
     if (gimme == G_SCALAR) {
        if (MARK < SP)
            *++newsp = (popsub2 && SvTEMP(*SP))
@@ -1401,9 +1535,11 @@ PP(pp_return)
            *++newsp = &sv_undef;
     }
     else if (gimme == G_ARRAY) {
-       while (++MARK <= SP)
+       while (++MARK <= SP) {
            *++newsp = (popsub2 && SvTEMP(*MARK))
                        ? *MARK : sv_mortalcopy(*MARK);
+           TAINT_NOT;          /* Each item is independent */
+       }
     }
     stack_sp = newsp;
 
@@ -1465,6 +1601,7 @@ PP(pp_last)
        DIE("panic: last");
     }
 
+    TAINT_NOT;
     if (gimme == G_SCALAR) {
        if (MARK < SP)
            *++newsp = ((pop2 == CXt_SUB) && SvTEMP(*SP))
@@ -1473,9 +1610,11 @@ PP(pp_last)
            *++newsp = &sv_undef;
     }
     else if (gimme == G_ARRAY) {
-       while (++MARK <= SP)
+       while (++MARK <= SP) {
            *++newsp = ((pop2 == CXt_SUB) && SvTEMP(*MARK))
                        ? *MARK : sv_mortalcopy(*MARK);
+           TAINT_NOT;          /* Each item is independent */
+       }
     }
     SP = newsp;
     PUTBACK;
@@ -1549,40 +1688,45 @@ PP(pp_redo)
 static OP* lastgotoprobe;
 
 static OP *
-dofindlabel(op,label,opstack)
-OP *op;
+dofindlabel(o,label,opstack,oplimit)
+OP *o;
 char *label;
 OP **opstack;
+OP **oplimit;
 {
     OP *kid;
     OP **ops = opstack;
-
-    if (op->op_type == OP_LEAVE ||
-       op->op_type == OP_SCOPE ||
-       op->op_type == OP_LEAVELOOP ||
-       op->op_type == OP_LEAVETRY)
-           *ops++ = cUNOP->op_first;
+    static char too_deep[] = "Target of goto is too deeply nested";
+
+    if (ops >= oplimit)
+       croak(too_deep);
+    if (o->op_type == OP_LEAVE ||
+       o->op_type == OP_SCOPE ||
+       o->op_type == OP_LEAVELOOP ||
+       o->op_type == OP_LEAVETRY)
+    {
+       *ops++ = cUNOPo->op_first;
+       if (ops >= oplimit)
+           croak(too_deep);
+    }
     *ops = 0;
-    if (op->op_flags & OPf_KIDS) {
+    if (o->op_flags & OPf_KIDS) {
        /* First try all the kids at this level, since that's likeliest. */
-       for (kid = cUNOP->op_first; kid; kid = kid->op_sibling) {
+       for (kid = cUNOPo->op_first; kid; kid = kid->op_sibling) {
            if ((kid->op_type == OP_NEXTSTATE || kid->op_type == OP_DBSTATE) &&
                    kCOP->cop_label && strEQ(kCOP->cop_label, label))
                return kid;
        }
-       for (kid = cUNOP->op_first; kid; kid = kid->op_sibling) {
+       for (kid = cUNOPo->op_first; kid; kid = kid->op_sibling) {
            if (kid == lastgotoprobe)
                continue;
-           if (kid->op_type == OP_NEXTSTATE || kid->op_type == OP_DBSTATE) {
-               if (ops > opstack &&
-                 (ops[-1]->op_type == OP_NEXTSTATE ||
-                  ops[-1]->op_type == OP_DBSTATE))
-                   *ops = kid;
-               else
-                   *ops++ = kid;
-           }
-           if (op = dofindlabel(kid,label,ops))
-               return op;
+           if ((kid->op_type == OP_NEXTSTATE || kid->op_type == OP_DBSTATE) &&
+               (ops == opstack ||
+                (ops[-1]->op_type != OP_NEXTSTATE &&
+                 ops[-1]->op_type != OP_DBSTATE)))
+               *ops++ = kid;
+           if (o = dofindlabel(kid, label, ops, oplimit))
+               return o;
        }
     }
     *ops = 0;
@@ -1601,7 +1745,8 @@ PP(pp_goto)
     OP *retop = 0;
     I32 ix;
     register CONTEXT *cx;
-    OP *enterops[64];
+#define GOTO_DEPTH 64
+    OP *enterops[GOTO_DEPTH];
     char *label;
     int do_dump = (op->op_type == OP_DUMP);
 
@@ -1792,9 +1937,6 @@ PP(pp_goto)
        for (ix = cxstack_ix; ix >= 0; ix--) {
            cx = &cxstack[ix];
            switch (cx->cx_type) {
-           case CXt_SUB:
-               gotoprobe = CvROOT(cx->blk_sub.cv);
-               break;
            case CXt_EVAL:
                gotoprobe = eval_root; /* XXX not good for nested eval */
                break;
@@ -1809,6 +1951,12 @@ PP(pp_goto)
                else
                    gotoprobe = main_root;
                break;
+           case CXt_SUB:
+               if (CvDEPTH(cx->blk_sub.cv)) {
+                   gotoprobe = CvROOT(cx->blk_sub.cv);
+                   break;
+               }
+               /* FALL THROUGH */
            case CXt_NULL:
                DIE("Can't \"goto\" outside a block");
            default:
@@ -1817,7 +1965,8 @@ PP(pp_goto)
                gotoprobe = main_root;
                break;
            }
-           retop = dofindlabel(gotoprobe, label, enterops);
+           retop = dofindlabel(gotoprobe, label,
+                               enterops, enterops + GOTO_DEPTH);
            if (retop)
                break;
            lastgotoprobe = gotoprobe;
@@ -1844,7 +1993,7 @@ PP(pp_goto)
            OP *oldop = op;
            for (ix = 1; enterops[ix]; ix++) {
                op = enterops[ix];
-               (*op->op_ppaddr)();
+               (*op->op_ppaddr)(ARGS);
            }
            op = oldop;
        }
@@ -1962,6 +2111,7 @@ static OP *
 docatch(o)
 OP *o;
 {
+    dTHR;
     int ret;
     I32 oldrunlevel = runlevel;
     OP *oldop = op;
@@ -2002,12 +2152,21 @@ static OP *
 doeval(gimme)
 int gimme;
 {
+    dTHR;
     dSP;
     OP *saveop = op;
     HV *newstash;
     CV *caller;
     AV* comppadlist;
 
+#ifdef USE_THREADS
+    MUTEX_LOCK(&eval_mutex);
+    if (eval_owner && eval_owner != thr)
+       while (eval_owner)
+           COND_WAIT(&eval_cond, &eval_mutex);
+    eval_owner = thr;
+    MUTEX_UNLOCK(&eval_mutex);
+#endif /* USE_THREADS */
     in_eval = 1;
 
     PUSHMARK(SP);
@@ -2027,10 +2186,20 @@ int gimme;
     compcv = (CV*)NEWSV(1104,0);
     sv_upgrade((SV *)compcv, SVt_PVCV);
     CvUNIQUE_on(compcv);
+#ifdef USE_THREADS
+    CvOWNER(compcv) = 0;
+    New(666, CvMUTEXP(compcv), 1, pthread_mutex_t);
+    MUTEX_INIT(CvMUTEXP(compcv));
+    New(666, CvCONDP(compcv), 1, pthread_cond_t);
+    COND_INIT(CvCONDP(compcv));
+#endif /* USE_THREADS */
 
     comppad = newAV();
     comppad_name = newAV();
     comppad_name_fill = 0;
+#ifdef USE_THREADS
+    av_store(comppad_name, 0, newSVpv("@_", 2));
+#endif /* USE_THREADS */
     min_intro_pending = 0;
     av_push(comppad, Nullsv);
     curpad = AvARRAY(comppad);
@@ -2087,8 +2256,10 @@ int gimme;
        pop_return();
        lex_end();
        LEAVE;
-       if (optype == OP_REQUIRE)
-           DIE("%s", SvPVx(GvSV(errgv), na));
+       if (optype == OP_REQUIRE) {
+           char* msg = SvPVx(GvSV(errgv), na);
+           DIE("%s", *msg ? msg : "Compilation failed in require");
+       }
        SvREFCNT_dec(rs);
        rs = SvREFCNT_inc(nrs);
        RETPUSHUNDEF;
@@ -2121,8 +2292,14 @@ int gimme;
     /* compiled okay, so do it */
 
     CvDEPTH(compcv) = 1;
-
     SP = stack_base + POPMARK;         /* pop original mark */
+#ifdef USE_THREADS
+    MUTEX_LOCK(&eval_mutex);
+    eval_owner = 0;
+    COND_SIGNAL(&eval_cond);
+    MUTEX_UNLOCK(&eval_mutex);
+#endif /* USE_THREADS */
+
     RETURNOP(eval_start);
 }
 
@@ -2132,7 +2309,8 @@ PP(pp_require)
     register CONTEXT *cx;
     SV *sv;
     char *name;
-    char *tmpname;
+    char *tryname;
+    SV *namesv = Nullsv;
     SV** svp;
     I32 gimme = G_SCALAR;
     PerlIO *tryrsfp = 0;
@@ -2156,61 +2334,63 @@ PP(pp_require)
 
     /* prepare to compile file */
 
-    tmpname = savepv(name);
-    if (*tmpname == '/' ||
-       (*tmpname == '.' && 
-           (tmpname[1] == '/' ||
-            (tmpname[1] == '.' && tmpname[2] == '/')))
+    if (*name == '/' ||
+       (*name == '.' && 
+           (name[1] == '/' ||
+            (name[1] == '.' && name[2] == '/')))
 #ifdef DOSISH
-      || (tmpname[0] && tmpname[1] == ':')
+      || (name[0] && name[1] == ':')
 #endif
 #ifdef VMS
-       || (strchr(tmpname,':')  || ((*tmpname == '[' || *tmpname == '<') &&
-           (isALNUM(tmpname[1]) || strchr("$-_]>",tmpname[1]))))
+       || (strchr(name,':')  || ((*name == '[' || *name == '<') &&
+           (isALNUM(name[1]) || strchr("$-_]>",name[1]))))
 #endif
     )
     {
-       tryrsfp = PerlIO_open(tmpname,"r");
+       tryname = name;
+       tryrsfp = PerlIO_open(name,"r");
     }
     else {
        AV *ar = GvAVn(incgv);
        I32 i;
 #ifdef VMS
-       char unixified[256];
-       if (tounixspec_ts(tmpname,unixified) != NULL)
-         for (i = 0; i <= AvFILL(ar); i++) {
-           if (tounixpath_ts(SvPVx(*av_fetch(ar, i, TRUE), na),buf) == NULL)
-               continue;
-           strcat(buf,unixified);
+       char *unixname;
+       if ((unixname = tounixspec(name, Nullch)) != Nullch)
+#endif
+       {
+           namesv = NEWSV(806, 0);
+           for (i = 0; i <= AvFILL(ar); i++) {
+               char *dir = SvPVx(*av_fetch(ar, i, TRUE), na);
+#ifdef VMS
+               char *unixdir;
+               if ((unixdir = tounixpath(dir, Nullch)) == Nullch)
+                   continue;
+               sv_setpv(namesv, unixdir);
+               sv_catpv(namesv, unixname);
 #else
-       for (i = 0; i <= AvFILL(ar); i++) {
-           (void)sprintf(buf, "%s/%s",
-               SvPVx(*av_fetch(ar, i, TRUE), na), name);
+               sv_setpvf(namesv, "%s/%s", dir, name);
 #endif
-           tryrsfp = PerlIO_open(buf, "r");
-           if (tryrsfp) {
-               char *s = buf;
-
-               if (*s == '.' && s[1] == '/')
-                   s += 2;
-               Safefree(tmpname);
-               tmpname = savepv(s);
-               break;
+               tryname = SvPVX(namesv);
+               tryrsfp = PerlIO_open(tryname, "r");
+               if (tryrsfp) {
+                   if (tryname[0] == '.' && tryname[1] == '/')
+                       tryname += 2;
+                   break;
+               }
            }
        }
     }
     SAVESPTR(compiling.cop_filegv);
-    compiling.cop_filegv = gv_fetchfile(tmpname);
-    Safefree(tmpname);
-    tmpname = Nullch;
+    compiling.cop_filegv = gv_fetchfile(tryrsfp ? tryname : name);
+    SvREFCNT_dec(namesv);
     if (!tryrsfp) {
        if (op->op_type == OP_REQUIRE) {
-           sprintf(tokenbuf,"Can't locate %s in @INC", name);
-           if (instr(tokenbuf,".h "))
-               strcat(tokenbuf," (change .h to .ph maybe?)");
-           if (instr(tokenbuf,".ph "))
-               strcat(tokenbuf," (did you run h2ph?)");
-           DIE("%s",tokenbuf);
+           SV *msg = sv_2mortal(newSVpvf("Can't locate %s in @INC", name));
+           if (instr(SvPVX(msg), ".h "))
+               sv_catpv(msg, " (change .h to .ph maybe?)");
+           if (instr(SvPVX(msg), ".ph "))
+               sv_catpv(msg, " (did you run h2ph?)");
+           DIE("%_", msg);
        }
 
        RETPUSHUNDEF;
@@ -2257,7 +2437,8 @@ PP(pp_entereval)
     register CONTEXT *cx;
     dPOPss;
     I32 gimme = GIMME_V, was = sub_generation;
-    char tmpbuf[32], *safestr;
+    char tmpbuf[TYPE_DIGITS(long) + 12];
+    char *safestr;
     STRLEN len;
     OP *ret;
 
@@ -2317,6 +2498,7 @@ PP(pp_leaveeval)
     POPEVAL(cx);
     retop = pop_return();
 
+    TAINT_NOT;
     if (gimme == G_VOID)
        MARK = newsp;
     else if (gimme == G_SCALAR) {
@@ -2333,10 +2515,13 @@ PP(pp_leaveeval)
        }
     }
     else {
-       for (mark = newsp + 1; mark <= SP; mark++)
-           if (!(SvFLAGS(*mark) & SVs_TEMP))
+       /* in case LEAVE wipes old return values */
+       for (mark = newsp + 1; mark <= SP; mark++) {
+           if (!(SvFLAGS(*mark) & SVs_TEMP)) {
                *mark = sv_mortalcopy(*mark);
-               /* in case LEAVE wipes old return values */
+               TAINT_NOT;      /* Each item is independent */
+           }
+       }
     }
     curpm = newpm;     /* Don't pop $1 et al till now */
 
@@ -2397,6 +2582,7 @@ PP(pp_leavetry)
     POPEVAL(cx);
     pop_return();
 
+    TAINT_NOT;
     if (gimme == G_VOID)
        SP = newsp;
     else if (gimme == G_SCALAR) {
@@ -2414,10 +2600,13 @@ PP(pp_leavetry)
        SP = MARK;
     }
     else {
-       for (mark = newsp + 1; mark <= SP; mark++)
-           if (!(SvFLAGS(*mark) & (SVs_PADTMP|SVs_TEMP)))
+       /* in case LEAVE wipes old return values */
+       for (mark = newsp + 1; mark <= SP; mark++) {
+           if (!(SvFLAGS(*mark) & (SVs_PADTMP|SVs_TEMP))) {
                *mark = sv_mortalcopy(*mark);
-               /* in case LEAVE wipes old return values */
+               TAINT_NOT;      /* Each item is independent */
+           }
+       }
     }
     curpm = newpm;     /* Don't pop $1 et al till now */