else if (o->op_type == OP_CONST) {
if (o->op_private & OPpCONST_BARE)
sv_catpv(tmpsv, ",BARE");
+ if (o->op_private & OPpCONST_OCTAL)
+ sv_catpv(tmpsv, ",OCTAL");
if (o->op_private & OPpCONST_STRICT)
sv_catpv(tmpsv, ",STRICT");
if (o->op_private & OPpCONST_ARYBASE)
}
OP *
+Perl_ck_octmode(pTHX_ OP *o)
+{
+ OP *p;
+
+ if ((ckWARN(WARN_OCTMODE)
+ /* Add WARN_MKDIR instead of getting rid of WARN_{CHMOD,UMASK}.
+ Backwards compatibility and consistency are terrible things.
+ AMS 20010705 */
+ || (o->op_type == OP_CHMOD && ckWARN(WARN_CHMOD))
+ || (o->op_type == OP_UMASK && ckWARN(WARN_UMASK))
+ || (o->op_type == OP_MKDIR && ckWARN(WARN_MKDIR)))
+ && o->op_flags & OPf_KIDS)
+ {
+ if (o->op_type == OP_MKDIR)
+ p = cLISTOPo->op_last; /* mkdir $foo, 0777 */
+ else if (o->op_type == OP_CHMOD)
+ p = cLISTOPo->op_first->op_sibling; /* chmod 0777, $foo */
+ else
+ p = cUNOPo->op_first; /* umask 0222 */
+
+ if (p->op_type == OP_CONST && !(p->op_private & OPpCONST_OCTAL)) {
+ int mode = SvIV(cSVOPx_sv(p));
+
+ Perl_warner(aTHX_ WARN_OCTMODE,
+ "Non-octal literal mode (%d) specified", mode);
+ Perl_warner(aTHX_ WARN_OCTMODE,
+ "\t(Did you mean 0%d instead?)\n", mode);
+ }
+ }
+ return ck_fun(o);
+}
+
+OP *
Perl_ck_open(pTHX_ OP *o)
{
HV *table = GvHV(PL_hintgv);
#define OPpTARGET_MY 16 /* Target is PADMY. */
/* Private for OP_CONST */
+#define OPpCONST_OCTAL 4 /* Octal constant. */
#define OPpCONST_STRICT 8 /* bearword subject to strict 'subs' */
#define OPpCONST_ENTERED 16 /* Has been entered as symbol. */
#define OPpCONST_ARYBASE 32 /* Was a $[ translated to constant. */
MEMBER_TO_FPTR(Perl_ck_fun), /* close */
MEMBER_TO_FPTR(Perl_ck_fun), /* pipe_op */
MEMBER_TO_FPTR(Perl_ck_fun), /* fileno */
- MEMBER_TO_FPTR(Perl_ck_fun), /* umask */
+ MEMBER_TO_FPTR(Perl_ck_octmode), /* umask */
MEMBER_TO_FPTR(Perl_ck_fun), /* binmode */
MEMBER_TO_FPTR(Perl_ck_fun), /* tie */
MEMBER_TO_FPTR(Perl_ck_fun), /* untie */
MEMBER_TO_FPTR(Perl_ck_fun), /* chown */
MEMBER_TO_FPTR(Perl_ck_fun), /* chroot */
MEMBER_TO_FPTR(Perl_ck_fun), /* unlink */
- MEMBER_TO_FPTR(Perl_ck_fun), /* chmod */
+ MEMBER_TO_FPTR(Perl_ck_octmode), /* chmod */
MEMBER_TO_FPTR(Perl_ck_fun), /* utime */
MEMBER_TO_FPTR(Perl_ck_fun), /* rename */
MEMBER_TO_FPTR(Perl_ck_fun), /* link */
MEMBER_TO_FPTR(Perl_ck_fun), /* symlink */
MEMBER_TO_FPTR(Perl_ck_fun), /* readlink */
- MEMBER_TO_FPTR(Perl_ck_fun), /* mkdir */
+ MEMBER_TO_FPTR(Perl_ck_octmode), /* mkdir */
MEMBER_TO_FPTR(Perl_ck_fun), /* rmdir */
MEMBER_TO_FPTR(Perl_ck_fun), /* open_dir */
MEMBER_TO_FPTR(Perl_ck_fun), /* readdir */
pipe_op pipe ck_fun is@ F F
fileno fileno ck_fun ist% F
-umask umask ck_fun ist% S?
+umask umask ck_octmode ist% S?
binmode binmode ck_fun s@ F S?
tie tie ck_fun idms@ R S L
chown chown ck_fun imsT@ L
chroot chroot ck_fun isTu% S?
unlink unlink ck_fun imsTu@ L
-chmod chmod ck_fun imsT@ L
+chmod chmod ck_octmode imsT@ L
utime utime ck_fun imsT@ L
rename rename ck_fun isT@ S S
link link ck_fun isT@ S S
symlink symlink ck_fun isT@ S S
readlink readlink ck_fun stu% S?
-mkdir mkdir ck_fun isT@ S S?
+mkdir mkdir ck_octmode isT@ S S?
rmdir rmdir ck_fun isTu% S?
# Directory calls.
If you actually want to pack Unicode codepoints, use the C<"U"> format
instead.
-=item chmod() mode argument is missing initial 0
-
-(W chmod) A novice will sometimes say
-
- chmod 777, $filename
-
-not realizing that 777 will be interpreted as a decimal number,
-equivalent to 01411. Octal constants are introduced with a leading 0 in
-Perl, as in C.
-
=item close() on unopened filehandle %s
(W unopened) You tried to close a filehandle that was never opened.
traditional to end such a file with a "1;", though any true value would
do. See L<perlfunc/require>.
+=item (Did you mean 0%d instead?)
+
+(W octmode) The mode argument to chmod, mkdir, and umask is usually
+given in octal (octal constants start with a 0, as in C). Did you really
+mean to use a non-octal number?
+
=item (Did you mean &%s instead?)
(W) You probably referred to an imported subroutine &FOO as $FOO or some
not recognized. Say C<kill -l> in your shell to see the valid signal
names on your system.
+=item Non-octal literal mode (%d) specified
+
+(W octmode) The mode argument to chmod, mkdir, and umask is usually
+given in octal (octal constants start with a 0, as in C). Did you really
+mean to use a non-octal number?
+
=item Not a CODE reference
(F) Perl was trying to evaluate a reference to a code value (that is, a
%NAME or C<%{EXPR}>. No implicit dereferencing is allowed--use the
{EXPR} forms as an explicit dereference. See L<perlref>.
-=item umask: argument is missing initial 0
-
-(W umask) A umask of 222 is incorrect. It should be 0222, because octal
-literals always start with 0 in Perl, as in C.
-
=item umask not implemented
(F) Your machine doesn't implement the umask function and you tried to
Perl_ck_match
Perl_ck_method
Perl_ck_null
+Perl_ck_octmode
Perl_ck_open
Perl_ck_repeat
Perl_ck_require
PERL_CKDEF(Perl_ck_match)
PERL_CKDEF(Perl_ck_method)
PERL_CKDEF(Perl_ck_null)
+PERL_CKDEF(Perl_ck_octmode)
PERL_CKDEF(Perl_ck_open)
PERL_CKDEF(Perl_ck_repeat)
PERL_CKDEF(Perl_ck_require)
%s() called too early to check prototype [Perl_peep]
fred() ; sub fred ($$) {}
+ Non-octal literal mode (%d) specified
+ (Did you mean 0%d instead?)
+ chmod 777, "foo";
+ mkdir "foo", 777;
+ umask 222;
Mandatory Warnings
------------------
EXPECT
Useless use of push with no values at - line 4.
Useless use of unshift with no values at - line 5.
+########
+# op.c
+use warnings 'chmod' ;
+chmod 777;
+no warnings 'chmod' ;
+chmod 777;
+EXPECT
+Non-octal literal mode (777) specified at - line 3.
+ (Did you mean 0777 instead?)
+########
+# op.c
+use warnings 'umask' ;
+umask 222;
+no warnings 'umask' ;
+umask 222;
+EXPECT
+Non-octal literal mode (222) specified at - line 3.
+ (Did you mean 0222 instead?)
+########
+# op.c
+use warnings 'mkdir' ;
+mkdir "", 777;
+no warnings 'mkdir' ;
+mkdir "", 777;
+EXPECT
+Non-octal literal mode (777) specified at - line 3.
+ (Did you mean 0777 instead?)
warn(warn_reserved
$a = abc;
- chmod() mode argument is missing initial 0
- chmod 3;
-
Possible attempt to separate words with commas
@a = qw(a, b, c) ;
Possible attempt to put comments in qw() list
@a = qw(a b # c) ;
- umask: argument is missing initial 0
- umask 3;
-
%s (...) interpreted as function
print ("")
printf ("")
Unquoted string "abc" may clash with future reserved word at - line 3.
########
# toke.c
-use warnings 'chmod' ;
-chmod 3;
-no warnings 'chmod' ;
-chmod 3;
-EXPECT
-chmod() mode argument is missing initial 0 at - line 3.
-########
-# toke.c
use warnings 'qw' ;
@a = qw(a, b, c) ;
no warnings 'qw' ;
Possible attempt to put comments in qw() list at - line 3.
########
# toke.c
-use warnings 'umask' ;
-umask 3;
-no warnings 'umask' ;
-umask 3;
-EXPECT
-umask: argument is missing initial 0 at - line 3.
-########
-# toke.c
use warnings 'syntax' ;
print ("")
EXPECT
LOP(OP_CRYPT,XTERM);
case KEY_chmod:
- if (ckWARN(WARN_CHMOD)) {
- for (d = s; d < PL_bufend && (isSPACE(*d) || *d == '('); d++) ;
- if (*d != '0' && isDIGIT(*d))
- Perl_warner(aTHX_ WARN_CHMOD,
- "chmod() mode argument is missing initial 0");
- }
LOP(OP_CHMOD,XTERM);
case KEY_chown:
LOP(OP_UTIME,XTERM);
case KEY_umask:
- if (ckWARN(WARN_UMASK)) {
- for (d = s; d < PL_bufend && (isSPACE(*d) || *d == '('); d++) ;
- if (*d != '0' && isDIGIT(*d))
- Perl_warner(aTHX_ WARN_UMASK,
- "umask: argument is missing initial 0");
- }
UNI(OP_UMASK);
case KEY_unshift:
register char *e; /* end of temp buffer */
NV nv; /* number read, as a double */
SV *sv = Nullsv; /* place to put the converted number */
- bool floatit; /* boolean: int or float? */
+ bool floatit, /* boolean: int or float? */
+ octal = 0; /* Is this an octal number? */
char *lastub = 0; /* position of last underbar */
static char number_too_long[] = "Number too long";
/* so it must be octal */
else {
shift = 3;
+ octal = 1;
s++;
}
/* make the op for the constant and return */
- if (sv)
+ if (sv) {
lvalp->opval = newSVOP(OP_CONST, 0, sv);
+ if (octal)
+ ((SVOP *)lvalp->opval)->op_private |= OPpCONST_OCTAL;
+ }
else
lvalp->opval = Nullop;
'debugging' => DEFAULT_ON,
'malloc' => DEFAULT_ON,
},
+ 'octmode' => {
+ 'chmod' => DEFAULT_OFF,
+ 'mkdir' => DEFAULT_OFF,
+ 'umask' => DEFAULT_OFF,
+ },
'void' => DEFAULT_OFF,
'recursion' => DEFAULT_OFF,
'redefine' => DEFAULT_OFF,
'regexp' => DEFAULT_OFF,
'glob' => DEFAULT_OFF,
'y2k' => DEFAULT_OFF,
- 'chmod' => DEFAULT_OFF,
- 'umask' => DEFAULT_OFF,
'untie' => DEFAULT_OFF,
'substr' => DEFAULT_OFF,
'taint' => DEFAULT_OFF,