diff options
author | Brian Fraser <fraserbn@gmail.com> | 2013-04-09 04:27:16 -0300 |
---|---|---|
committer | Tony Cook <tony@develop-help.com> | 2013-09-11 10:28:29 +1000 |
commit | 90aeefb47309434774bb94bdb3c7a92dedf59563 (patch) | |
tree | 2ad34ee21ec441502b43472db01c62467abc8d03 /gv.c | |
parent | 30877037d0977c0e3b7a5268b63d626f65d428ab (diff) | |
download | perl-90aeefb47309434774bb94bdb3c7a92dedf59563.tar.gz |
gv.c: Begin splitting gv_fetchpvn_flags into smaller helper functions.
This commit takes a chunk of code out of gv_fetchpvn_flags and
turns it into two fuctions: parse_gv_stash_name and find_default_stash.
Diffstat (limited to 'gv.c')
-rw-r--r-- | gv.c | 441 |
1 files changed, 246 insertions, 195 deletions
@@ -1387,7 +1387,7 @@ Perl_gv_fetchsv(pTHX_ SV *name, I32 flags, const svtype sv_type) { return gv_fetchpvn_flags(nambeg, len, flags | SvUTF8(name), sv_type); } -STATIC void +PERL_STATIC_INLINE void S_gv_magicalize_isa(pTHX_ GV *gv) { AV* av; @@ -1400,6 +1400,237 @@ S_gv_magicalize_isa(pTHX_ GV *gv) NULL, 0); } +/* This function grabs name and tries to split a stash and glob + * from its contents. TODO better description, comments + * + * If the function returns TRUE and 'name == name_end', then + * 'gv' can be directly returned to the caller of gv_fetchpvn_flags + */ +PERL_STATIC_INLINE bool +S_parse_gv_stash_name(pTHX_ HV **stash, GV **gv, const char **name, + STRLEN *len, const char *nambeg, STRLEN full_len, + const U32 is_utf8, const I32 add) +{ + const char *name_cursor; + const char *const name_end = nambeg + full_len; + const char *const name_em1 = name_end - 1; + + PERL_ARGS_ASSERT_PARSE_GV_STASH_NAME; + + if (full_len > 2 && **name == '*' && isIDFIRST_lazy_if(*name + 1, is_utf8)) { + /* accidental stringify on a GV? */ + (*name)++; + } + + for (name_cursor = *name; name_cursor < name_end; name_cursor++) { + if (name_cursor < name_em1 && + ((*name_cursor == ':' && name_cursor[1] == ':') + || *name_cursor == '\'')) + { + if (!*stash) + *stash = PL_defstash; + if (!*stash || !SvREFCNT(*stash)) /* symbol table under destruction */ + return FALSE; + + *len = name_cursor - *name; + if (name_cursor > nambeg) { /* Skip for initial :: or ' */ + const char *key; + GV**gvp; + if (*name_cursor == ':') { + key = *name; + *len += 2; + } + else { + char *tmpbuf; + Newx(tmpbuf, *len+2, char); + Copy(*name, tmpbuf, *len, char); + tmpbuf[(*len)++] = ':'; + tmpbuf[(*len)++] = ':'; + key = tmpbuf; + } + gvp = (GV**)hv_fetch(*stash, key, is_utf8 ? -(*len) : *len, add); + *gv = gvp ? *gvp : NULL; + if (*gv && *gv != (const GV *)&PL_sv_undef) { + if (SvTYPE(*gv) != SVt_PVGV) + gv_init_pvn(*gv, *stash, key, *len, (add & GV_ADDMULTI)|is_utf8); + else + GvMULTI_on(*gv); + } + if (key != *name) + Safefree(key); + if (!*gv || *gv == (const GV *)&PL_sv_undef) + return FALSE; + + if (!(*stash = GvHV(*gv))) { + *stash = GvHV(*gv) = newHV(); + if (!HvNAME_get(*stash)) { + if (GvSTASH(*gv) == PL_defstash && *len == 6 + && strnEQ(*name, "CORE", 4)) + hv_name_set(*stash, "CORE", 4, 0); + else + hv_name_set( + *stash, nambeg, name_cursor-nambeg, is_utf8 + ); + /* If the containing stash has multiple effective + names, see that this one gets them, too. */ + if (HvAUX(GvSTASH(*gv))->xhv_name_count) + mro_package_moved(*stash, NULL, *gv, 1); + } + } + else if (!HvNAME_get(*stash)) + hv_name_set(*stash, nambeg, name_cursor - nambeg, is_utf8); + } + + if (*name_cursor == ':') + name_cursor++; + *name = name_cursor+1; + if (*name == name_end) { + if (!*gv) + *gv = MUTABLE_GV(*hv_fetchs(PL_defstash, "main::", TRUE)); + return TRUE; + } + } + } + *len = name_cursor - *name; + return TRUE; +} + +/* This function is called if parse_gv_stash_name() failed to + * find a stash, or if GV_NOTQUAL or an empty name was passed + * to gv_fetchpvn_flags. + * + * It returns FALSE if the default stash can't be found nor created, + * which might happen during global destruction. + */ +PERL_STATIC_INLINE bool +S_find_default_stash(pTHX_ HV **stash, const char *name, STRLEN len, + const U32 is_utf8, const I32 add, + const svtype sv_type) +{ + PERL_ARGS_ASSERT_FIND_DEFAULT_STASH; + + /* No stash in name, so see how we can default */ + + /* If it's an alphanumeric variable */ + if (len && isIDFIRST_lazy_if(name, is_utf8)) { + bool global = FALSE; + + /* Some "normal" variables are always in main::, + * like INC or STDOUT. + */ + switch (len) { + case 1: + if (*name == '_') + global = TRUE; + break; + case 3: + if ((name[0] == 'I' && name[1] == 'N' && name[2] == 'C') + || (name[0] == 'E' && name[1] == 'N' && name[2] == 'V') + || (name[0] == 'S' && name[1] == 'I' && name[2] == 'G')) + global = TRUE; + break; + case 4: + if (name[0] == 'A' && name[1] == 'R' && name[2] == 'G' + && name[3] == 'V') + global = TRUE; + break; + case 5: + if (name[0] == 'S' && name[1] == 'T' && name[2] == 'D' + && name[3] == 'I' && name[4] == 'N') + global = TRUE; + break; + case 6: + if ((name[0] == 'S' && name[1] == 'T' && name[2] == 'D') + &&((name[3] == 'O' && name[4] == 'U' && name[5] == 'T') + ||(name[3] == 'E' && name[4] == 'R' && name[5] == 'R'))) + global = TRUE; + break; + case 7: + if (name[0] == 'A' && name[1] == 'R' && name[2] == 'G' + && name[3] == 'V' && name[4] == 'O' && name[5] == 'U' + && name[6] == 'T') + global = TRUE; + break; + } + + if (global) + *stash = PL_defstash; + else if (IN_PERL_COMPILETIME) { + *stash = PL_curstash; + if (add && (PL_hints & HINT_STRICT_VARS) && + sv_type != SVt_PVCV && + sv_type != SVt_PVGV && + sv_type != SVt_PVFM && + sv_type != SVt_PVIO && + !(len == 1 && sv_type == SVt_PV && + (*name == 'a' || *name == 'b')) ) + { + GV**gvp = (GV**)hv_fetch(*stash,name,is_utf8 ? -len : len,0); + if (!gvp || *gvp == (const GV *)&PL_sv_undef || + SvTYPE(*gvp) != SVt_PVGV) + { + *stash = NULL; + } + else if ((sv_type == SVt_PV && !GvIMPORTED_SV(*gvp)) || + (sv_type == SVt_PVAV && !GvIMPORTED_AV(*gvp)) || + (sv_type == SVt_PVHV && !GvIMPORTED_HV(*gvp)) ) + { + /* diag_listed_as: Variable "%s" is not imported%s */ + Perl_ck_warner_d( + aTHX_ packWARN(WARN_MISC), + "Variable \"%c%"UTF8f"\" is not imported", + sv_type == SVt_PVAV ? '@' : + sv_type == SVt_PVHV ? '%' : '$', + UTF8fARG(is_utf8, len, name)); + if (GvCVu(*gvp)) + Perl_ck_warner_d( + aTHX_ packWARN(WARN_MISC), + "\t(Did you mean &%"UTF8f" instead?)\n", + UTF8fARG(is_utf8, len, name) + ); + *stash = NULL; + } + } + } + else { + /* Use the current op's stash */ + *stash = CopSTASH(PL_curcop); + } + } + /* *{""}, or a special variable like $@ */ + else + *stash = PL_defstash; + + if (!*stash) { + if (add && !PL_in_clean_all) { + SV * const err = Perl_mess(aTHX_ + "Global symbol \"%s%"UTF8f + "\" requires explicit package name", + (sv_type == SVt_PV ? "$" + : sv_type == SVt_PVAV ? "@" + : sv_type == SVt_PVHV ? "%" + : ""), UTF8fARG(is_utf8, len, name)); + GV *gv; + if (is_utf8) + SvUTF8_on(err); + qerror(err); + gv = gv_fetchpvs("<none>::", GV_ADDMULTI, SVt_PVHV); + if (!gv) { + /* symbol table under destruction */ + return FALSE; + } + *stash = GvHV(gv); + } + else + return FALSE; + } + + if (!SvREFCNT(*stash)) /* symbol table under destruction */ + return FALSE; + + return TRUE; +} + GV * Perl_gv_fetchpvn_flags(pTHX_ const char *nambeg, STRLEN full_len, I32 flags, const svtype sv_type) @@ -1409,7 +1640,6 @@ Perl_gv_fetchpvn_flags(pTHX_ const char *nambeg, STRLEN full_len, I32 flags, GV *gv = NULL; GV**gvp; STRLEN len; - const char *name_cursor; HV *stash = NULL; const I32 no_init = flags & (GV_NOADD_NOINIT | GV_NOINIT); const I32 no_expand = flags & GV_NOEXPAND; @@ -1417,210 +1647,31 @@ Perl_gv_fetchpvn_flags(pTHX_ const char *nambeg, STRLEN full_len, I32 flags, const U32 is_utf8 = flags & SVf_UTF8; bool addmg = !!(flags & GV_ADDMG); const char *const name_end = nambeg + full_len; - const char *const name_em1 = name_end - 1; U32 faking_it; SSize_t paren; PERL_ARGS_ASSERT_GV_FETCHPVN_FLAGS; - if (flags & GV_NOTQUAL) { - /* Caller promised that there is no stash, so we can skip the check. */ - len = full_len; - goto no_stash; + /* If we have GV_NOTQUAL, the caller promised that + * there is no stash, so we can skip the check. + * Similarly if full_len is 0, since then we're + * dealing with something like *{""} or ""->foo() + */ + if ((flags & GV_NOTQUAL) || !full_len) { + len = full_len; } - - if (full_len > 2 && *name == '*' && isIDFIRST_lazy_if(name + 1, is_utf8)) { - /* accidental stringify on a GV? */ - name++; + else if (parse_gv_stash_name(&stash, &gv, &name, &len, nambeg, full_len, is_utf8, add)) { + if (name == name_end) return gv; } - - for (name_cursor = name; name_cursor < name_end; name_cursor++) { - if (name_cursor < name_em1 && - ((*name_cursor == ':' - && name_cursor[1] == ':') - || *name_cursor == '\'')) - { - if (!stash) - stash = PL_defstash; - if (!stash || !SvREFCNT(stash)) /* symbol table under destruction */ - return NULL; - - len = name_cursor - name; - if (name_cursor > nambeg) { /* Skip for initial :: or ' */ - const char *key; - if (*name_cursor == ':') { - key = name; - len += 2; - } else { - char *tmpbuf; - Newx(tmpbuf, len+2, char); - Copy(name, tmpbuf, len, char); - tmpbuf[len++] = ':'; - tmpbuf[len++] = ':'; - key = tmpbuf; - } - gvp = (GV**)hv_fetch(stash, key, is_utf8 ? -len : len, add); - gv = gvp ? *gvp : NULL; - if (gv && gv != (const GV *)&PL_sv_undef) { - if (SvTYPE(gv) != SVt_PVGV) - gv_init_pvn(gv, stash, key, len, (add & GV_ADDMULTI)|is_utf8); - else - GvMULTI_on(gv); - } - if (key != name) - Safefree(key); - if (!gv || gv == (const GV *)&PL_sv_undef) - return NULL; - - if (!(stash = GvHV(gv))) - { - stash = GvHV(gv) = newHV(); - if (!HvNAME_get(stash)) { - if (GvSTASH(gv) == PL_defstash && len == 6 - && strnEQ(name, "CORE", 4)) - hv_name_set(stash, "CORE", 4, 0); - else - hv_name_set( - stash, nambeg, name_cursor-nambeg, is_utf8 - ); - /* If the containing stash has multiple effective - names, see that this one gets them, too. */ - if (HvAUX(GvSTASH(gv))->xhv_name_count) - mro_package_moved(stash, NULL, gv, 1); - } - } - else if (!HvNAME_get(stash)) - hv_name_set(stash, nambeg, name_cursor - nambeg, is_utf8); - } - - if (*name_cursor == ':') - name_cursor++; - name = name_cursor+1; - if (name == name_end) - return gv - ? gv : MUTABLE_GV(*hv_fetchs(PL_defstash, "main::", TRUE)); - } + else { + return NULL; } - len = name_cursor - name; - - /* No stash in name, so see how we can default */ - - if (!stash) { - no_stash: - if (len && isIDFIRST_lazy_if(name, is_utf8)) { - bool global = FALSE; - - switch (len) { - case 1: - if (*name == '_') - global = TRUE; - break; - case 3: - if ((name[0] == 'I' && name[1] == 'N' && name[2] == 'C') - || (name[0] == 'E' && name[1] == 'N' && name[2] == 'V') - || (name[0] == 'S' && name[1] == 'I' && name[2] == 'G')) - global = TRUE; - break; - case 4: - if (name[0] == 'A' && name[1] == 'R' && name[2] == 'G' - && name[3] == 'V') - global = TRUE; - break; - case 5: - if (name[0] == 'S' && name[1] == 'T' && name[2] == 'D' - && name[3] == 'I' && name[4] == 'N') - global = TRUE; - break; - case 6: - if ((name[0] == 'S' && name[1] == 'T' && name[2] == 'D') - &&((name[3] == 'O' && name[4] == 'U' && name[5] == 'T') - ||(name[3] == 'E' && name[4] == 'R' && name[5] == 'R'))) - global = TRUE; - break; - case 7: - if (name[0] == 'A' && name[1] == 'R' && name[2] == 'G' - && name[3] == 'V' && name[4] == 'O' && name[5] == 'U' - && name[6] == 'T') - global = TRUE; - break; - } - if (global) - stash = PL_defstash; - else if (IN_PERL_COMPILETIME) { - stash = PL_curstash; - if (add && (PL_hints & HINT_STRICT_VARS) && - sv_type != SVt_PVCV && - sv_type != SVt_PVGV && - sv_type != SVt_PVFM && - sv_type != SVt_PVIO && - !(len == 1 && sv_type == SVt_PV && - (*name == 'a' || *name == 'b')) ) - { - gvp = (GV**)hv_fetch(stash,name,is_utf8 ? -len : len,0); - if (!gvp || - *gvp == (const GV *)&PL_sv_undef || - SvTYPE(*gvp) != SVt_PVGV) - { - stash = NULL; - } - else if ((sv_type == SVt_PV && !GvIMPORTED_SV(*gvp)) || - (sv_type == SVt_PVAV && !GvIMPORTED_AV(*gvp)) || - (sv_type == SVt_PVHV && !GvIMPORTED_HV(*gvp)) ) - { - /* diag_listed_as: Variable "%s" is not imported%s */ - Perl_ck_warner_d( - aTHX_ packWARN(WARN_MISC), - "Variable \"%c%"UTF8f"\" is not imported", - sv_type == SVt_PVAV ? '@' : - sv_type == SVt_PVHV ? '%' : '$', - UTF8fARG(is_utf8, len, name)); - if (GvCVu(*gvp)) - Perl_ck_warner_d( - aTHX_ packWARN(WARN_MISC), - "\t(Did you mean &%"UTF8f" instead?)\n", - UTF8fARG(is_utf8, len, name) - ); - stash = NULL; - } - } - } - else - stash = CopSTASH(PL_curcop); - } - else - stash = PL_defstash; + if (!stash && !find_default_stash(&stash, name, len, is_utf8, add, sv_type)) { + return NULL; } - + /* By this point we should have a stash and a name */ - - if (!stash) { - if (add && !PL_in_clean_all) { - SV * const err = Perl_mess(aTHX_ - "Global symbol \"%s%"UTF8f - "\" requires explicit package name", - (sv_type == SVt_PV ? "$" - : sv_type == SVt_PVAV ? "@" - : sv_type == SVt_PVHV ? "%" - : ""), UTF8fARG(is_utf8, len, name)); - GV *gv; - if (is_utf8) - SvUTF8_on(err); - qerror(err); - gv = gv_fetchpvs("<none>::", GV_ADDMULTI, SVt_PVHV); - if(!gv) { - /* symbol table under destruction */ - return NULL; - } - stash = GvHV(gv); - } - else - return NULL; - } - - if (!SvREFCNT(stash)) /* symbol table under destruction */ - return NULL; - gvp = (GV**)hv_fetch(stash,name,is_utf8 ? -len : len,add); if (!gvp || *gvp == (const GV *)&PL_sv_undef) { if (addmg) gv = (GV *)newSV(0); |