summaryrefslogtreecommitdiff
path: root/doio.c
diff options
context:
space:
mode:
authorFather Chrysostomos <sprout@cpan.org>2012-01-23 23:36:29 -0800
committerFather Chrysostomos <sprout@cpan.org>2012-01-23 23:39:39 -0800
commit8db8f6b697e6f705eda3222828417099787adba4 (patch)
tree9443248f2134133a9a1adda030fdab3a70a96054 /doio.c
parent7e68c38b607a044ee5879e316bb8a7347284ec8e (diff)
downloadperl-8db8f6b697e6f705eda3222828417099787adba4.tar.gz
[perl #77388] Make stacked -t work
Up till now, -t was popping too much off the stack when stacked with other filetest operators. Since the special use of _ doesn’t apply to -t, we cannot simply have it use _ when stacked, but instead we pass the argument down from the previous op. To facilitate this, the whole stacked mechanism has to change. As before, in an expression like -r -w -x, -x and -w are flagged as ‘stacking’ ops (followed by another filetest), and -w and -r are flagged as stacked (preceded by another filetest). Stacking filetest ops no longer return a false value to the next op when a test fails, and stacked ops no longer check the truth of the value on the stack to determine whether to return early (if it’s false). The argument to the first filetest is now passed from one op to another. This is similar to the mechanism that overloaded objects were already using. Now it applies to any argument. Since it could be false, we cannot rely on the boolean value of the stack item. So, stacking ops, when they return false, now traverse the ->op_next pointers and find the op after the last stacked op. That op is returned to the runloop. This short-circuiting is proba- bly faster than calling every subsequent op (a separate function call for each). Filetest ops other than -t continue to use the last stat buffer when stacked, so the argument on the stack is ignored. But if the op is preceded by nothing other than -t (where preceded means on the right, since the ops are evaluated right-to-left), it *does* use the argument on the stack, since -t has not set the last stat buffer. The new OPpFT_AFTER_t flag indicates that a stacked op is preceded by nothing other than -t. In ‘-e -t foo’, the -e gets the flag, but not in ‘-e -t -r foo’, because -r will have saved the stat buffer, so -e can just use that.
Diffstat (limited to 'doio.c')
-rw-r--r--doio.c19
1 files changed, 11 insertions, 8 deletions
diff --git a/doio.c b/doio.c
index 08a15b71fb..081fdf2991 100644
--- a/doio.c
+++ b/doio.c
@@ -1292,14 +1292,15 @@ Perl_my_stat_flags(pTHX_ const U32 flags)
report_evil_fh(gv);
return -1;
}
- else if (PL_op->op_private & OPpFT_STACKED) {
- return PL_laststatval;
- }
else {
- SV* const sv = POPs;
+ SV* const sv = PL_op->op_private & OPpFT_STACKING ? TOPs : POPs;
+ PUTBACK;
+ if ((PL_op->op_private & (OPpFT_STACKED|OPpFT_AFTER_t))
+ == OPpFT_STACKED)
+ return PL_laststatval;
+ else {
const char *s;
STRLEN len;
- PUTBACK;
if ((gv = MAYBE_DEREF_GV_flags(sv,flags))) {
goto do_fstat;
}
@@ -1318,6 +1319,7 @@ Perl_my_stat_flags(pTHX_ const U32 flags)
if (PL_laststatval < 0 && ckWARN(WARN_NEWLINE) && strchr(s, '\n'))
Perl_warner(aTHX_ packWARN(WARN_NEWLINE), PL_warn_nl, "stat");
return PL_laststatval;
+ }
}
}
@@ -1345,7 +1347,10 @@ Perl_my_lstat_flags(pTHX_ const U32 flags)
}
return -1;
}
- else if (PL_op->op_private & OPpFT_STACKED) {
+ sv = PL_op->op_private & OPpFT_STACKING ? TOPs : POPs;
+ PUTBACK;
+ if ((PL_op->op_private & (OPpFT_STACKED|OPpFT_AFTER_t))
+ == OPpFT_STACKED) {
if (PL_laststype != OP_LSTAT)
Perl_croak(aTHX_ no_prev_lstat);
return PL_laststatval;
@@ -1353,8 +1358,6 @@ Perl_my_lstat_flags(pTHX_ const U32 flags)
PL_laststype = OP_LSTAT;
PL_statgv = NULL;
- sv = POPs;
- PUTBACK;
file = SvPV_flags_const_nolen(sv, flags);
sv_setpv(PL_statname,file);
PL_laststatval = PerlLIO_lstat(file,&PL_statcache);