Skip to content

Commit 871e680

Browse files
committed
pp_ctl.c - add support for an INCDIR hook
This hook returns a list of directories for Perl to search. If it returns an empty list it acts like a no-op (except for the error message). The return from INCDIR is always stringified, they are not treated the same as normal @inc entries so no hooks returning hooks.
1 parent eb4b346 commit 871e680

File tree

3 files changed

+76
-8
lines changed

3 files changed

+76
-8
lines changed

pp_ctl.c

Lines changed: 76 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4266,11 +4266,32 @@ S_require_file(pTHX_ SV *sv)
42664266
if (vms_unixname)
42674267
#endif
42684268
{
4269-
SV *nsv = sv;
4269+
AV *incdir_av = (AV*)sv_2mortal((SV*)newAV());
4270+
SV *nsv = sv; /* non const copy we can change if necessary */
42704271
namesv = newSV_type(SVt_PV);
42714272
AV *inc_ar = GvAVn(PL_incgv);
4272-
for (inc_idx = 0; inc_idx <= AvFILL(inc_ar); inc_idx++) {
4273-
SV *dirsv = *av_fetch(inc_ar, inc_idx, TRUE);
4273+
SSize_t incdir_continue_inc_idx = -1;
4274+
4275+
for (
4276+
inc_idx = 0;
4277+
(AvFILL(incdir_av)>=0 /* we have INCDIR items pending */
4278+
|| inc_idx <= AvFILL(inc_ar)); /* @INC entries remain */
4279+
inc_idx++
4280+
) {
4281+
SV *dirsv;
4282+
4283+
/* do we have any pending INCDIR items? */
4284+
if (AvFILL(incdir_av)>=0) {
4285+
/* yep, shift it out */
4286+
dirsv = av_shift(incdir_av);
4287+
if (AvFILL(incdir_av)<0) {
4288+
/* incdir is now empty, continue from where
4289+
* we left off after we process this entry */
4290+
inc_idx = incdir_continue_inc_idx;
4291+
}
4292+
} else {
4293+
dirsv = *av_fetch(inc_ar, inc_idx, TRUE);
4294+
}
42744295

42754296
if (SvGMAGICAL(dirsv)) {
42764297
SvGETMAGIC(dirsv);
@@ -4289,6 +4310,7 @@ S_require_file(pTHX_ SV *sv)
42894310
int count;
42904311
SV **svp;
42914312
SV *loader = dirsv;
4313+
UV diruv = PTR2UV(SvRV(dirsv));
42924314

42934315
if (SvTYPE(SvRV(loader)) == SVt_PVAV
42944316
&& !SvOBJECT(SvRV(loader)))
@@ -4298,7 +4320,7 @@ S_require_file(pTHX_ SV *sv)
42984320
}
42994321

43004322
Perl_sv_setpvf(aTHX_ namesv, "/loader/0x%" UVxf "/%s",
4301-
PTR2UV(SvRV(dirsv)), name);
4323+
diruv, name);
43024324
tryname = SvPVX_const(namesv);
43034325
tryrsfp = NULL;
43044326

@@ -4308,6 +4330,7 @@ S_require_file(pTHX_ SV *sv)
43084330
}
43094331

43104332
const char *method = NULL;
4333+
bool is_incdir = FALSE;
43114334
SV * inc_idx_sv = save_scalar(PL_incgv);
43124335
sv_setiv(inc_idx_sv,inc_idx);
43134336
if (sv_isobject(loader)) {
@@ -4318,6 +4341,12 @@ S_require_file(pTHX_ SV *sv)
43184341
GV * gv = gv_fetchmethod_pvn_flags(pkg, "INC", 3, 0);
43194342
if (gv && isGV(gv)) {
43204343
method = "INC";
4344+
} else {
4345+
gv = gv_fetchmethod_pvn_flags(pkg, "INCDIR", 6, 0);
4346+
if (gv && isGV(gv)) {
4347+
method = "INCDIR";
4348+
is_incdir = TRUE;
4349+
}
43214350
}
43224351
/* But if we have no method, check if this is a
43234352
* coderef, if it is then we treat it as an
@@ -4367,6 +4396,48 @@ S_require_file(pTHX_ SV *sv)
43674396
SV *arg;
43684397

43694398
SP -= count - 1;
4399+
4400+
if (is_incdir) {
4401+
/* push the stringified returned items into the
4402+
* incdir_av array for processing immediately
4403+
* afterwards. we deliberately stringify or copy
4404+
* "special" arguments, so that overload logic for
4405+
* instance applies, but so that the end result is
4406+
* stable. We speficially do *not* support returning
4407+
* coderefs from an INCDIR call. */
4408+
while (count-->0) {
4409+
arg = SP[i++];
4410+
SvGETMAGIC(arg);
4411+
if (!SvOK(arg))
4412+
continue;
4413+
if (SvROK(arg)) {
4414+
STRLEN l;
4415+
char *pv = SvPV(arg,l);
4416+
arg = newSVpvn(pv,l);
4417+
}
4418+
else if (SvGMAGICAL(arg)) {
4419+
arg = newSVsv_nomg(arg);
4420+
}
4421+
else {
4422+
SvREFCNT_inc(arg);
4423+
}
4424+
av_push(incdir_av, arg);
4425+
}
4426+
/* We copy $INC into incdir_continue_inc_idx
4427+
* so that when we finish processing the items
4428+
* we just inserted into incdir_av we can continue
4429+
* as though we had just finished executing the INCDIR
4430+
* hook. We honour $INC here just like we would for
4431+
* an INC hook, the hook might have rewritten @INC
4432+
* at the same time as returning something to us.
4433+
*/
4434+
inc_idx_sv = GvSVn(PL_incgv);
4435+
incdir_continue_inc_idx = SvOK(inc_idx_sv)
4436+
? SvIV(inc_idx_sv) : -1;
4437+
4438+
goto done_hook;
4439+
}
4440+
43704441
arg = SP[i++];
43714442

43724443
if (SvROK(arg) && (SvTYPE(SvRV(arg)) <= SVt_PVLV)
@@ -4415,6 +4486,7 @@ S_require_file(pTHX_ SV *sv)
44154486
tryrsfp = PerlIO_open(BIT_BUCKET,
44164487
PERL_SCRIPT_MODE);
44174488
}
4489+
done_hook:
44184490
SP--;
44194491
} else {
44204492
SV *errsv= ERRSV;

t/op/inccode.t

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -399,7 +399,6 @@ if ($can_fork) {
399399
}
400400
SKIP:{
401401
skip "need fork",1 unless $can_fork;
402-
local $::TODO = "Pending";
403402
fresh_perl_like('@INC=("A",bless({},"Hook"),"D"); '
404403
.'sub Hook::INCDIR { return "B","C"} '
405404
.'eval "require Frobnitz" or print $@;',

t/op/require_errors.t

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -338,7 +338,6 @@ like $@, qr/^Can't locate \Q$nonsearch\E at/,
338338
{ }, 'INC hooks that overwrite @INC and undef $INC continue at start');
339339
}
340340
{
341-
local $::TODO = "Pending new feature: INCDIR";
342341
# as of 5.37.7
343342
fresh_perl_like(
344343
'sub CB::INCDIR { return "b", "c","d" }; '
@@ -398,7 +397,6 @@ like $@, qr/^Can't locate \Q$nonsearch\E at/,
398397
{ }, 'Blessed objects with no hook methods in array form produce expected exception');
399398
}
400399
{
401-
local $::TODO = "Pending new feature: INCDIR";
402400
# as of 5.37.7
403401
fresh_perl_like(
404402
'sub CB::INCDIR { "i" } sub CB2::INCDIR { }'
@@ -408,7 +406,6 @@ like $@, qr/^Can't locate \Q$nonsearch\E at/,
408406
{ }, 'Blessed subs with INCDIR methods call INCDIR');
409407
}
410408
{
411-
local $::TODO = "Pending new feature: INCDIR";
412409
# as of 5.37.7
413410
fresh_perl_like(
414411
'sub CB::INCDIR { return @{$_[2]} }'

0 commit comments

Comments
 (0)