From: Nicholas Clark Date: Mon, 15 Jan 2007 14:38:58 +0000 (+0000) Subject: Add get_cvn_flags(), which is like get_cv() but takes a length. This X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=780a5241a93925d81e932db73df46ee749b203b9;p=p5sagit%2Fp5-mst-13.2.git Add get_cvn_flags(), which is like get_cv() but takes a length. This allows symbolic code references with embeded NULs to work. p4raw-id: //depot/perl@29830 --- diff --git a/embed.fnc b/embed.fnc index 2801844..0847142 100644 --- a/embed.fnc +++ b/embed.fnc @@ -639,7 +639,8 @@ Apd |I32 |eval_sv |NN SV* sv|I32 flags Apd |SV* |get_sv |NN const char* name|I32 create Apd |AV* |get_av |NN const char* name|I32 create Apd |HV* |get_hv |NN const char* name|I32 create -Apd |CV* |get_cv |NN const char* name|I32 create +Apd |CV* |get_cv |NN const char* name|I32 flags +Apd |CV* |get_cvn_flags |NN const char* name|STRLEN len|I32 flags Ap |int |init_i18nl10n |int printwarn Ap |int |init_i18nl14n |int printwarn Ap |void |new_collate |NULLOK const char* newcoll diff --git a/embed.h b/embed.h index bf4f169..eae6f3d 100644 --- a/embed.h +++ b/embed.h @@ -647,6 +647,7 @@ #define get_av Perl_get_av #define get_hv Perl_get_hv #define get_cv Perl_get_cv +#define get_cvn_flags Perl_get_cvn_flags #define init_i18nl10n Perl_init_i18nl10n #define init_i18nl14n Perl_init_i18nl14n #define new_collate Perl_new_collate @@ -2858,6 +2859,7 @@ #define get_av(a,b) Perl_get_av(aTHX_ a,b) #define get_hv(a,b) Perl_get_hv(aTHX_ a,b) #define get_cv(a,b) Perl_get_cv(aTHX_ a,b) +#define get_cvn_flags(a,b,c) Perl_get_cvn_flags(aTHX_ a,b,c) #define init_i18nl10n(a) Perl_init_i18nl10n(aTHX_ a) #define init_i18nl14n(a) Perl_init_i18nl14n(aTHX_ a) #define new_collate(a) Perl_new_collate(aTHX_ a) diff --git a/global.sym b/global.sym index d59dd24..21d7532 100644 --- a/global.sym +++ b/global.sym @@ -368,6 +368,7 @@ Perl_get_sv Perl_get_av Perl_get_hv Perl_get_cv +Perl_get_cvn_flags Perl_init_i18nl10n Perl_init_i18nl14n Perl_new_collate diff --git a/gv.c b/gv.c index e4c59b5..8630c1b 100644 --- a/gv.c +++ b/gv.c @@ -806,8 +806,7 @@ Perl_gv_fetchpvn_flags(pTHX_ const char *nambeg, STRLEN full_len, I32 flags, HV *stash = NULL; const I32 no_init = flags & (GV_NOADD_NOINIT | GV_NOINIT); const I32 no_expand = flags & GV_NOEXPAND; - const I32 add = - flags & ~SVf_UTF8 & ~GV_NOADD_NOINIT & ~GV_NOEXPAND & ~GV_NOTQUAL; + const I32 add = flags & ~GV_NOADD_MASK; const char *const name_end = nambeg + full_len; const char *const name_em1 = name_end - 1; diff --git a/gv.h b/gv.h index 2463335..cbc6840 100644 --- a/gv.h +++ b/gv.h @@ -207,6 +207,10 @@ Return the SV from the GV. /* SVf_UTF8 (more accurately the return value from SvUTF8) is also valid as a flag to gv_fetch_pvn_flags, so ensure it lies outside this range. */ + +#define GV_NOADD_MASK (SVf_UTF8|GV_NOADD_NOINIT|GV_NOEXPAND|GV_NOTQUAL) +/* The bit flags that don't cause gv_fetchpv() to add a symbol if not found */ + #define gv_fullname3(sv,gv,prefix) gv_fullname4(sv,gv,prefix,TRUE) #define gv_efullname3(sv,gv,prefix) gv_efullname4(sv,gv,prefix,TRUE) #define gv_fetchmethod(stash, name) gv_fetchmethod_autoload(stash, name, TRUE) diff --git a/op.c b/op.c index 40275ab..9e565fe 100644 --- a/op.c +++ b/op.c @@ -2063,7 +2063,8 @@ Perl_newPROG(pTHX_ OP *o) /* Register with debugger */ if (PERLDB_INTER) { - CV * const cv = get_cv("DB::postponed", FALSE); + CV * const cv + = Perl_get_cvn_flags(aTHX_ STR_WITH_LEN("DB::postponed"), 0); if (cv) { dSP; PUSHMARK(SP); diff --git a/perl.c b/perl.c index fdcbcbd..88bbcbb 100644 --- a/perl.c +++ b/perl.c @@ -2476,33 +2476,47 @@ Perl_get_hv(pTHX_ const char *name, I32 create) /* =head1 CV Manipulation Functions +=for apidoc p||get_cvn_flags + +Returns the CV of the specified Perl subroutine. C are passed to +C. If C is set and the Perl subroutine does not +exist then it will be declared (which has the same effect as saying +C). If C is not set and the subroutine does not exist +then NULL is returned. + =for apidoc p||get_cv -Returns the CV of the specified Perl subroutine. If C is set and -the Perl subroutine does not exist then it will be declared (which has the -same effect as saying C). If C is not set and the -subroutine does not exist then NULL is returned. +Uses C to get the length of C, then calls C. =cut */ CV* -Perl_get_cv(pTHX_ const char *name, I32 create) +Perl_get_cvn_flags(pTHX_ const char *name, STRLEN len, I32 flags) { - GV* const gv = gv_fetchpv(name, create, SVt_PVCV); + GV* const gv = gv_fetchpvn_flags(name, len, flags, SVt_PVCV); /* XXX unsafe for threads if eval_owner isn't held */ /* XXX this is probably not what they think they're getting. * It has the same effect as "sub name;", i.e. just a forward * declaration! */ - if (create && !GvCVu(gv)) + if ((flags & ~GV_NOADD_MASK) && !GvCVu(gv)) { + SV *const sv = newSVpvn(name,len); + SvFLAGS(sv) |= flags & SVf_UTF8; return newSUB(start_subparse(FALSE, 0), - newSVOP(OP_CONST, 0, newSVpv(name,0)), + newSVOP(OP_CONST, 0, sv), NULL, NULL); + } if (gv) return GvCVu(gv); return NULL; } +CV* +Perl_get_cv(pTHX_ const char *name, I32 flags) +{ + return get_cvn_flags(name, strlen(name), flags); +} + /* Be sure to refetch the stack pointer after calling these routines. */ /* diff --git a/perlio.c b/perlio.c index 54aab1b..6e2d9e1 100644 --- a/perlio.c +++ b/perlio.c @@ -796,7 +796,7 @@ PerlIO_find_layer(pTHX_ const char *name, STRLEN len, int load) } else { SV * const pkgsv = newSVpvs("PerlIO"); SV * const layer = newSVpvn(name, len); - CV * const cv = get_cv("PerlIO::Layer::NoWarnings", FALSE); + CV * const cv = Perl_get_cvn_flags(aTHX_ STR_WITH_LEN("PerlIO::Layer::NoWarnings"), 0); ENTER; SAVEINT(PL_in_load_module); if (cv) { diff --git a/pp_hot.c b/pp_hot.c index 476fd80..f1ad3ed 100644 --- a/pp_hot.c +++ b/pp_hot.c @@ -2710,6 +2710,7 @@ PP(pp_entersub) default: if (!SvROK(sv)) { const char *sym; + STRLEN len; if (sv == &PL_sv_yes) { /* unfound import, ignore */ if (hasargs) SP = PL_stack_base + POPMARK; @@ -2719,16 +2720,22 @@ PP(pp_entersub) mg_get(sv); if (SvROK(sv)) goto got_rv; - sym = SvPOKp(sv) ? SvPVX_const(sv) : NULL; + if (SvPOKp(sv)) { + sym = SvPVX_const(sv); + len = SvCUR(sv); + } else { + sym = NULL; + len = 0; + } } else { - sym = SvPV_nolen_const(sv); + sym = SvPV_const(sv, len); } if (!sym) DIE(aTHX_ PL_no_usym, "a subroutine"); if (PL_op->op_private & HINT_STRICT_REFS) DIE(aTHX_ PL_no_symref, sym, "a subroutine"); - cv = get_cv(sym, TRUE); + cv = get_cvn_flags(sym, len, GV_ADD|SvUTF8(sv)); break; } got_rv: diff --git a/proto.h b/proto.h index 5d0f551..662f09c 100644 --- a/proto.h +++ b/proto.h @@ -1769,7 +1769,10 @@ PERL_CALLCONV AV* Perl_get_av(pTHX_ const char* name, I32 create) PERL_CALLCONV HV* Perl_get_hv(pTHX_ const char* name, I32 create) __attribute__nonnull__(pTHX_1); -PERL_CALLCONV CV* Perl_get_cv(pTHX_ const char* name, I32 create) +PERL_CALLCONV CV* Perl_get_cv(pTHX_ const char* name, I32 flags) + __attribute__nonnull__(pTHX_1); + +PERL_CALLCONV CV* Perl_get_cvn_flags(pTHX_ const char* name, STRLEN len, I32 flags) __attribute__nonnull__(pTHX_1); PERL_CALLCONV int Perl_init_i18nl10n(pTHX_ int printwarn); @@ -2603,10 +2606,6 @@ PERL_CALLCONV int Perl_yyparse(pTHX); PERL_CALLCONV void Perl_parser_free(pTHX_ const yy_parser *) __attribute__nonnull__(pTHX_1); -PERL_CALLCONV yy_parser* Perl_parser_dup(pTHX_ const yy_parser *proto, CLONE_PARAMS* param) - __attribute__nonnull__(pTHX_1) - __attribute__nonnull__(pTHX_2); - PERL_CALLCONV int Perl_yywarn(pTHX_ const char* s) __attribute__nonnull__(pTHX_1); @@ -2864,6 +2863,10 @@ PERL_CALLCONV void Perl_rvpv_dup(pTHX_ SV* dstr, const SV *sstr, CLONE_PARAMS* p __attribute__nonnull__(pTHX_2) __attribute__nonnull__(pTHX_3); +PERL_CALLCONV yy_parser* Perl_parser_dup(pTHX_ const yy_parser *proto, CLONE_PARAMS* param) + __attribute__nonnull__(pTHX_1) + __attribute__nonnull__(pTHX_2); + #endif PERL_CALLCONV PTR_TBL_t* Perl_ptr_table_new(pTHX) __attribute__malloc__ diff --git a/t/op/ref.t b/t/op/ref.t index 1c713a9..9d88182 100755 --- a/t/op/ref.t +++ b/t/op/ref.t @@ -8,7 +8,7 @@ BEGIN { require 'test.pl'; use strict qw(refs subs); -plan(119); +plan(121); # Test glob operations. @@ -468,6 +468,12 @@ TODO: { my $glob2 = *{$name2}; isnt ($glob1, $glob2, "We get different typeglobs"); + + *{$name1} = sub {"One"}; + *{$name2} = sub {"Two"}; + + is (&{$name1}, "One"); + is (&{$name2}, "Two"); } # test derefs after list slice diff --git a/toke.c b/toke.c index 755f22c..f9f0627 100644 --- a/toke.c +++ b/toke.c @@ -4795,12 +4795,12 @@ Perl_yylex(pTHX) t++; } while (isSPACE(*t)); if (isIDFIRST_lazy_if(t,UTF)) { - STRLEN dummylen; + STRLEN len; t = scan_word(t, tmpbuf, sizeof tmpbuf, TRUE, - &dummylen); + &len); while (isSPACE(*t)) t++; - if (*t == ';' && get_cv(tmpbuf, FALSE)) + if (*t == ';' && get_cvn_flags(tmpbuf, len, 0)) Perl_warner(aTHX_ packWARN(WARN_SYNTAX), "You need to quote \"%s\"", tmpbuf); @@ -10738,7 +10738,8 @@ S_scan_ident(pTHX_ register char *s, register const char *send, char *dest, STRL } if (PL_lex_state == LEX_NORMAL) { if (ckWARN(WARN_AMBIGUOUS) && - (keyword(dest, d - dest, 0) || get_cv(dest, FALSE))) + (keyword(dest, d - dest, 0) + || get_cvn_flags(dest, d - dest, 0))) { if (funny == '#') funny = '@';