summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGisle Aas <gisle@activestate.com>2006-02-07 17:32:50 +0000
committerGisle Aas <gisle@activestate.com>2006-02-07 17:32:50 +0000
commitd4ac975eac140a6fda54f99664f15120fd97e7be (patch)
treefde462215af5bd354dbcb674446cfe6d9b55c28b
parent71302fe379907f97d78296ec5f7430559d3a05ca (diff)
downloadperl-d4ac975eac140a6fda54f99664f15120fd97e7be.tar.gz
Allow bareword file handle as argument to chdir().
This copies the mechanism used by truncate(). Fixes bug #38457. p4raw-id: //depot/perl@27125
-rw-r--r--embed.h2
-rw-r--r--op.c16
-rw-r--r--opcode.h2
-rwxr-xr-xopcode.pl3
-rw-r--r--pp.sym1
-rw-r--r--pp_proto.h1
-rw-r--r--pp_sys.c5
-rw-r--r--t/op/chdir.t19
8 files changed, 44 insertions, 5 deletions
diff --git a/embed.h b/embed.h
index d5c4f209c7..e586939eb5 100644
--- a/embed.h
+++ b/embed.h
@@ -1701,6 +1701,7 @@
#endif
#define ck_anoncode Perl_ck_anoncode
#define ck_bitop Perl_ck_bitop
+#define ck_chdir Perl_ck_chdir
#define ck_concat Perl_ck_concat
#define ck_defined Perl_ck_defined
#define ck_delete Perl_ck_delete
@@ -3753,6 +3754,7 @@
#endif
#define ck_anoncode(a) Perl_ck_anoncode(aTHX_ a)
#define ck_bitop(a) Perl_ck_bitop(aTHX_ a)
+#define ck_chdir(a) Perl_ck_chdir(aTHX_ a)
#define ck_concat(a) Perl_ck_concat(aTHX_ a)
#define ck_defined(a) Perl_ck_defined(aTHX_ a)
#define ck_delete(a) Perl_ck_delete(aTHX_ a)
diff --git a/op.c b/op.c
index 54c56c4a65..32927d33c6 100644
--- a/op.c
+++ b/op.c
@@ -6760,6 +6760,22 @@ Perl_ck_svconst(pTHX_ OP *o)
}
OP *
+Perl_ck_chdir(pTHX_ OP *o)
+{
+ if (o->op_flags & OPf_KIDS) {
+ SVOP *kid = (SVOP*)cUNOPo->op_first;
+
+ if (kid && kid->op_type == OP_CONST &&
+ (kid->op_private & OPpCONST_BARE))
+ {
+ o->op_flags |= OPf_SPECIAL;
+ kid->op_private &= ~OPpCONST_STRICT;
+ }
+ }
+ return ck_fun(o);
+}
+
+OP *
Perl_ck_trunc(pTHX_ OP *o)
{
if (o->op_flags & OPf_KIDS) {
diff --git a/opcode.h b/opcode.h
index 95510146df..849b7d2318 100644
--- a/opcode.h
+++ b/opcode.h
@@ -1427,7 +1427,7 @@ EXT Perl_check_t PL_check[] /* or perlvars.h */
MEMBER_TO_FPTR(Perl_ck_ftst), /* fttty */
MEMBER_TO_FPTR(Perl_ck_ftst), /* fttext */
MEMBER_TO_FPTR(Perl_ck_ftst), /* ftbinary */
- MEMBER_TO_FPTR(Perl_ck_fun), /* chdir */
+ MEMBER_TO_FPTR(Perl_ck_chdir), /* chdir */
MEMBER_TO_FPTR(Perl_ck_fun), /* chown */
MEMBER_TO_FPTR(Perl_ck_fun), /* chroot */
MEMBER_TO_FPTR(Perl_ck_fun), /* unlink */
diff --git a/opcode.pl b/opcode.pl
index fdf07c17be..61ab824d24 100755
--- a/opcode.pl
+++ b/opcode.pl
@@ -907,7 +907,8 @@ ftbinary -B ck_ftst isu- F-
# File calls.
-chdir chdir ck_fun isT% S?
+# chdir really behaves as if it had both "S?" and "F?"
+chdir chdir ck_chdir isT% S?
chown chown ck_fun imsT@ L
chroot chroot ck_fun isTu% S?
unlink unlink ck_fun imsTu@ L
diff --git a/pp.sym b/pp.sym
index 1d1b876181..2ca789f18d 100644
--- a/pp.sym
+++ b/pp.sym
@@ -7,6 +7,7 @@
Perl_ck_anoncode
Perl_ck_bitop
+Perl_ck_chdir
Perl_ck_concat
Perl_ck_defined
Perl_ck_delete
diff --git a/pp_proto.h b/pp_proto.h
index a64e335f61..1a368cdf5c 100644
--- a/pp_proto.h
+++ b/pp_proto.h
@@ -6,6 +6,7 @@
PERL_CKDEF(Perl_ck_anoncode)
PERL_CKDEF(Perl_ck_bitop)
+PERL_CKDEF(Perl_ck_chdir)
PERL_CKDEF(Perl_ck_concat)
PERL_CKDEF(Perl_ck_defined)
PERL_CKDEF(Perl_ck_delete)
diff --git a/pp_sys.c b/pp_sys.c
index fdda73034f..1659888abe 100644
--- a/pp_sys.c
+++ b/pp_sys.c
@@ -3293,7 +3293,10 @@ PP(pp_chdir)
if( MAXARG == 1 ) {
SV * const sv = POPs;
- if (SvTYPE(sv) == SVt_PVGV) {
+ if (PL_op->op_flags & OPf_SPECIAL) {
+ gv = gv_fetchsv(sv, 0, SVt_PVIO);
+ }
+ else if (SvTYPE(sv) == SVt_PVGV) {
gv = (GV*)sv;
}
else if (SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PVGV) {
diff --git a/t/op/chdir.t b/t/op/chdir.t
index cb24da86c6..5b5ca3ff43 100644
--- a/t/op/chdir.t
+++ b/t/op/chdir.t
@@ -9,7 +9,7 @@ BEGIN {
use Config;
require "test.pl";
-plan(tests => 38);
+plan(tests => 41);
my $IsVMS = $^O eq 'VMS';
my $IsMacOS = $^O eq 'MacOS';
@@ -43,7 +43,7 @@ SKIP: {
$Cwd = abs_path;
SKIP: {
- skip("no fchdir", 6) unless ($Config{d_fchdir} || "") eq "define";
+ skip("no fchdir", 9) unless ($Config{d_fchdir} || "") eq "define";
ok(opendir(my $dh, "."), "opendir .");
ok(open(my $fh, "<", "op"), "open op");
ok(chdir($fh), "fchdir op");
@@ -56,6 +56,21 @@ SKIP: {
like($@, qr/^The dirfd function is unimplemented at/, "dirfd is unimplemented");
chdir "..";
}
+
+ # same with bareword file handles
+ no warnings 'once';
+ *DH = $dh;
+ *FH = $fh;
+ ok(chdir FH, "fchdir op bareword");
+ ok(-f "chdir.t", "verify that we are in op");
+ if (($Config{d_dirfd} || "") eq "define") {
+ ok(chdir DH, "fchdir back bareword");
+ }
+ else {
+ eval { chdir(DH); };
+ like($@, qr/^The dirfd function is unimplemented at/, "dirfd is unimplemented");
+ chdir "..";
+ }
ok(-d "op", "verify that we are back");
}