summaryrefslogtreecommitdiff
path: root/pp_ctl.c
diff options
context:
space:
mode:
authorDavid Mitchell <davem@iabyn.com>2017-04-16 09:50:04 +0100
committerDavid Mitchell <davem@iabyn.com>2017-04-18 12:58:32 +0100
commitd31614f579da61846a22a2eb69b1d0412c86d54f (patch)
tree2ffbe3601110e86146c1eef3c59cbf127767c2a4 /pp_ctl.c
parent4b62894a4418bf61f306acb452472eb9fe79974e (diff)
downloadperl-d31614f579da61846a22a2eb69b1d0412c86d54f.tar.gz
emit require module name err hint only when valid
RT #131098 The helpful "you may need to install" hint which 'require' sometimes includes in its error message these days (split across multiple lines for clarity): $ perl -e'require Foo::Bar' Can't locate Foo/Bar.pm in @INC (you may need to install the Foo::Bar module) (@INC contains: ... ) at ... is a bit over-enthusiastic when the pathname hasn't actually been derived from a module name: $ perl -e'require "Foo.+/%#Bar.pm"' Can't locate Foo.+%#Bar.pm in @INC (you may need to install the Foo.+::%#Bar module) (@INC contains: ... ) at ... This commit changes things so that the hint message is only emitted if the reverse-mapped module name is legal as a bareword: $ perl -e'require "Foo.+/%#Bar.pm"' Can't locate Foo.+%#Bar.pm in @INC (@INC contains: ... ) at ...
Diffstat (limited to 'pp_ctl.c')
-rw-r--r--pp_ctl.c54
1 files changed, 42 insertions, 12 deletions
diff --git a/pp_ctl.c b/pp_ctl.c
index 69280e2942..e75e151f81 100644
--- a/pp_ctl.c
+++ b/pp_ctl.c
@@ -4101,22 +4101,52 @@ S_require_file(pTHX_ SV *sv)
SSize_t i;
SV *const msg = newSVpvs_flags("", SVs_TEMP);
SV *const inc = newSVpvs_flags("", SVs_TEMP);
+ const char *e = name + len - 3; /* possible .pm */
for (i = 0; i <= AvFILL(ar); i++) {
sv_catpvs(inc, " ");
sv_catsv(inc, *av_fetch(ar, i, TRUE));
}
- if (len >= 4 && memEQ(name + len - 3, ".pm", 4)) {
- const char *c, *e = name + len - 3;
- sv_catpv(msg, " (you may need to install the ");
- for (c = name; c < e; c++) {
- if (*c == '/') {
- sv_catpvs(msg, "::");
- }
- else {
- sv_catpvn(msg, c, 1);
- }
- }
- sv_catpv(msg, " module)");
+ if (e > name && _memEQs(e, ".pm")) {
+ const char *c;
+ bool utf8 = cBOOL(SvUTF8(sv));
+
+ /* if the filename, when converted from "Foo/Bar.pm"
+ * form back to Foo::Bar form, makes a valid
+ * package name (i.e. parseable by C<require
+ * Foo::Bar>), then emit a hint.
+ *
+ * this loop is modelled after the one in
+ S_parse_ident */
+ c = name;
+ while (c < e) {
+ if (utf8 && isIDFIRST_utf8_safe(c, e)) {
+ c += UTF8SKIP(c);
+ while (c < e && isIDCONT_utf8_safe(
+ (const U8*) c, (const U8*) e))
+ c += UTF8SKIP(c);
+ }
+ else if (isWORDCHAR_A(*c)) {
+ while (c < e && isWORDCHAR_A(*c))
+ c++;
+ }
+ else if (*c == '/')
+ c++;
+ else
+ break;
+ }
+
+ if (c == e && isIDFIRST_lazy_if_safe(name, e, utf8)) {
+ sv_catpv(msg, " (you may need to install the ");
+ for (c = name; c < e; c++) {
+ if (*c == '/') {
+ sv_catpvs(msg, "::");
+ }
+ else {
+ sv_catpvn(msg, c, 1);
+ }
+ }
+ sv_catpv(msg, " module)");
+ }
}
else if (len >= 2 && memEQ(name + len - 2, ".h", 3)) {
sv_catpv(msg, " (change .h to .ph maybe?) (did you run h2ph?)");