Scalar-List-Utils
view release on metacpan or search on metacpan
ListUtil.xs view on Meta::CPAN
SAVESPTR(GvSV(PL_defgv));
#ifdef dMULTICALL
assert(cv);
if(!CvISXSUB(cv)) {
dMULTICALL;
I32 gimme = G_SCALAR;
UNUSED_VAR_newsp;
PUSH_MULTICALL(cv);
for(index = 1 ; index < items ; index++) {
SV *def_sv = GvSV(PL_defgv) = args[index];
# ifdef SvTEMP_off
SvTEMP_off(def_sv);
# endif
MULTICALL;
if(SvTRUEx(*PL_stack_sp)) {
# ifdef PERL_HAS_BAD_MULTICALL_REFCOUNT
if(CvDEPTH(multicall_cv) > 1)
SvREFCNT_inc_simple_void_NN(multicall_cv);
# endif
POP_MULTICALL;
ST(0) = ST(index);
XSRETURN(1);
}
}
# ifdef PERL_HAS_BAD_MULTICALL_REFCOUNT
if(CvDEPTH(multicall_cv) > 1)
SvREFCNT_inc_simple_void_NN(multicall_cv);
# endif
POP_MULTICALL;
}
else
#endif
{
for(index = 1 ; index < items ; index++) {
dSP;
GvSV(PL_defgv) = args[index];
PUSHMARK(SP);
call_sv((SV*)cv, G_SCALAR);
if(SvTRUEx(*PL_stack_sp)) {
ST(0) = ST(index);
XSRETURN(1);
}
}
}
XSRETURN_UNDEF;
}
void
any(block,...)
SV *block
ALIAS:
none = 0
all = 1
any = 2
notall = 3
PROTOTYPE: &@
PPCODE:
{
int ret_true = !(ix & 2); /* return true at end of loop for none/all; false for any/notall */
int invert = (ix & 1); /* invert block test for all/notall */
SV **args = &PL_stack_base[ax];
CV *cv = sv_to_cv(block,
ix == 0 ? "none" :
ix == 1 ? "all" :
ix == 2 ? "any" :
ix == 3 ? "notall" :
"unknown 'any' alias");
SAVESPTR(GvSV(PL_defgv));
#ifdef dMULTICALL
assert(cv);
if(!CvISXSUB(cv)) {
dMULTICALL;
I32 gimme = G_SCALAR;
int index;
UNUSED_VAR_newsp;
PUSH_MULTICALL(cv);
for(index = 1; index < items; index++) {
SV *def_sv = GvSV(PL_defgv) = args[index];
# ifdef SvTEMP_off
SvTEMP_off(def_sv);
# endif
MULTICALL;
if(SvTRUEx(*PL_stack_sp) ^ invert) {
POP_MULTICALL;
ST(0) = ret_true ? &PL_sv_no : &PL_sv_yes;
XSRETURN(1);
}
}
POP_MULTICALL;
}
else
#endif
{
int index;
for(index = 1; index < items; index++) {
dSP;
GvSV(PL_defgv) = args[index];
PUSHMARK(SP);
call_sv((SV*)cv, G_SCALAR);
if(SvTRUEx(*PL_stack_sp) ^ invert) {
ST(0) = ret_true ? &PL_sv_no : &PL_sv_yes;
XSRETURN(1);
}
}
}
ST(0) = ret_true ? &PL_sv_yes : &PL_sv_no;
XSRETURN(1);
}
void
head(size,...)
PROTOTYPE: $@
ALIAS:
head = 0
tail = 1
PPCODE:
{
int size = 0;
int start = 0;
int end = 0;
int i = 0;
size = SvIV( ST(0) );
if ( ix == 0 ) {
start = 1;
end = start + size;
if ( size < 0 ) {
end += items - 1;
}
if ( end > items ) {
end = items;
}
}
else {
end = items;
if ( size < 0 ) {
start = -size + 1;
}
else {
start = end - size;
}
if ( start < 1 ) {
start = 1;
}
}
if ( end <= start ) {
XSRETURN(0);
}
else {
EXTEND( SP, end - start );
for ( i = start; i < end; i++ ) {
PUSHs( sv_2mortal( newSVsv( ST(i) ) ) );
}
XSRETURN( end - start );
}
}
void
pairs(...)
PROTOTYPE: @
PPCODE:
{
int argi = 0;
int reti = 0;
HV *pairstash = get_hv("List::Util::_Pair::", GV_ADD);
if(items % 2 && ckWARN(WARN_MISC))
warn("Odd number of elements in pairs");
{
for(; argi < items; argi += 2) {
SV *a = ST(argi);
SV *b = argi < items-1 ? ST(argi+1) : &PL_sv_undef;
AV *av = newAV();
av_push(av, newSVsv(a));
av_push(av, newSVsv(b));
ST(reti) = sv_2mortal(newRV_noinc((SV *)av));
sv_bless(ST(reti), pairstash);
reti++;
}
}
XSRETURN(reti);
}
void
unpairs(...)
PROTOTYPE: @
PPCODE:
{
/* Unlike pairs(), we're going to trash the input values on the stack
* almost as soon as we start generating output. So clone them first
*/
int i;
SV **args_copy;
Newx(args_copy, items, SV *);
SAVEFREEPV(args_copy);
Copy(&ST(0), args_copy, items, SV *);
for(i = 0; i < items; i++) {
SV *pair = args_copy[i];
AV *pairav;
SvGETMAGIC(pair);
if(SvTYPE(pair) != SVt_RV)
croak("Not a reference at List::Util::unpairs() argument %d", i);
if(SvTYPE(SvRV(pair)) != SVt_PVAV)
croak("Not an ARRAY reference at List::Util::unpairs() argument %d", i);
/* TODO: assert pair is an ARRAY ref */
pairav = (AV *)SvRV(pair);
EXTEND(SP, 2);
if(AvFILL(pairav) >= 0)
mPUSHs(newSVsv(AvARRAY(pairav)[0]));
else
PUSHs(&PL_sv_undef);
if(AvFILL(pairav) >= 1)
mPUSHs(newSVsv(AvARRAY(pairav)[1]));
else
PUSHs(&PL_sv_undef);
}
XSRETURN(items * 2);
}
void
pairkeys(...)
PROTOTYPE: @
PPCODE:
{
int argi = 0;
int reti = 0;
if(items % 2 && ckWARN(WARN_MISC))
warn("Odd number of elements in pairkeys");
{
for(; argi < items; argi += 2) {
SV *a = ST(argi);
ST(reti++) = sv_2mortal(newSVsv(a));
}
}
XSRETURN(reti);
}
void
pairvalues(...)
PROTOTYPE: @
PPCODE:
{
int argi = 0;
int reti = 0;
if(items % 2 && ckWARN(WARN_MISC))
warn("Odd number of elements in pairvalues");
{
for(; argi < items; argi += 2) {
SV *b = argi < items-1 ? ST(argi+1) : &PL_sv_undef;
ST(reti++) = sv_2mortal(newSVsv(b));
}
}
XSRETURN(reti);
}
void
pairfirst(block,...)
SV *block
PROTOTYPE: &@
PPCODE:
{
GV *agv,*bgv;
CV *cv = sv_to_cv(block, "pairfirst");
I32 ret_gimme = GIMME_V;
int argi = 1; /* "shift" the block */
if(!(items % 2) && ckWARN(WARN_MISC))
warn("Odd number of elements in pairfirst");
agv = gv_fetchpv("a", GV_ADD, SVt_PV);
bgv = gv_fetchpv("b", GV_ADD, SVt_PV);
SAVESPTR(GvSV(agv));
SAVESPTR(GvSV(bgv));
#ifdef dMULTICALL
assert(cv);
if(!CvISXSUB(cv)) {
/* Since MULTICALL is about to move it */
SV **stack = PL_stack_base + ax;
dMULTICALL;
I32 gimme = G_SCALAR;
UNUSED_VAR_newsp;
PUSH_MULTICALL(cv);
for(; argi < items; argi += 2) {
SV *a = GvSV(agv) = stack[argi];
SV *b = GvSV(bgv) = argi < items-1 ? stack[argi+1] : &PL_sv_undef;
MULTICALL;
if(!SvTRUEx(*PL_stack_sp))
continue;
POP_MULTICALL;
if(ret_gimme == G_LIST) {
ST(0) = sv_mortalcopy(a);
ST(1) = sv_mortalcopy(b);
XSRETURN(2);
}
else
XSRETURN_YES;
}
POP_MULTICALL;
XSRETURN(0);
}
else
#endif
{
for(; argi < items; argi += 2) {
dSP;
SV *a = GvSV(agv) = ST(argi);
SV *b = GvSV(bgv) = argi < items-1 ? ST(argi+1) : &PL_sv_undef;
PUSHMARK(SP);
call_sv((SV*)cv, G_SCALAR);
SPAGAIN;
if(!SvTRUEx(*PL_stack_sp))
continue;
if(ret_gimme == G_LIST) {
ST(0) = sv_mortalcopy(a);
ST(1) = sv_mortalcopy(b);
XSRETURN(2);
}
else
XSRETURN_YES;
}
}
XSRETURN(0);
}
void
pairgrep(block,...)
SV *block
PROTOTYPE: &@
PPCODE:
{
GV *agv,*bgv;
CV *cv = sv_to_cv(block, "pairgrep");
I32 ret_gimme = GIMME_V;
/* This function never returns more than it consumed in arguments. So we
* can build the results "live", behind the arguments
*/
int argi = 1; /* "shift" the block */
int reti = 0;
if(!(items % 2) && ckWARN(WARN_MISC))
warn("Odd number of elements in pairgrep");
agv = gv_fetchpv("a", GV_ADD, SVt_PV);
bgv = gv_fetchpv("b", GV_ADD, SVt_PV);
SAVESPTR(GvSV(agv));
SAVESPTR(GvSV(bgv));
#ifdef dMULTICALL
assert(cv);
if(!CvISXSUB(cv)) {
/* Since MULTICALL is about to move it */
SV **stack = PL_stack_base + ax;
int i;
dMULTICALL;
I32 gimme = G_SCALAR;
UNUSED_VAR_newsp;
PUSH_MULTICALL(cv);
for(; argi < items; argi += 2) {
SV *a = GvSV(agv) = stack[argi];
SV *b = GvSV(bgv) = argi < items-1 ? stack[argi+1] : &PL_sv_undef;
MULTICALL;
if(SvTRUEx(*PL_stack_sp)) {
if(ret_gimme == G_LIST) {
/* We can't mortalise yet or they'd be mortal too early */
stack[reti++] = newSVsv(a);
stack[reti++] = newSVsv(b);
}
else if(ret_gimme == G_SCALAR)
reti++;
}
}
POP_MULTICALL;
if(ret_gimme == G_LIST)
for(i = 0; i < reti; i++)
sv_2mortal(stack[i]);
}
else
#endif
{
for(; argi < items; argi += 2) {
dSP;
SV *a = GvSV(agv) = ST(argi);
SV *b = GvSV(bgv) = argi < items-1 ? ST(argi+1) : &PL_sv_undef;
PUSHMARK(SP);
call_sv((SV*)cv, G_SCALAR);
SPAGAIN;
if(SvTRUEx(*PL_stack_sp)) {
if(ret_gimme == G_LIST) {
ST(reti++) = sv_mortalcopy(a);
ST(reti++) = sv_mortalcopy(b);
}
else if(ret_gimme == G_SCALAR)
reti++;
}
}
}
if(ret_gimme == G_LIST)
XSRETURN(reti);
else if(ret_gimme == G_SCALAR) {
ST(0) = newSViv(reti);
XSRETURN(1);
}
}
void
pairmap(block,...)
SV *block
PROTOTYPE: &@
PPCODE:
{
GV *agv,*bgv;
CV *cv = sv_to_cv(block, "pairmap");
SV **args_copy = NULL;
I32 ret_gimme = GIMME_V;
int argi = 1; /* "shift" the block */
int reti = 0;
if(!(items % 2) && ckWARN(WARN_MISC))
warn("Odd number of elements in pairmap");
agv = gv_fetchpv("a", GV_ADD, SVt_PV);
bgv = gv_fetchpv("b", GV_ADD, SVt_PV);
SAVESPTR(GvSV(agv));
SAVESPTR(GvSV(bgv));
/* This MULTICALL-based code appears to fail on perl 5.10.0 and 5.8.9
* Skip it on those versions (RT#87857)
*/
#if defined(dMULTICALL) && (PERL_VERSION_GE(5,10,1) || PERL_VERSION_LE(5,8,8))
assert(cv);
if(!CvISXSUB(cv)) {
/* Since MULTICALL is about to move it */
SV **stack = PL_stack_base + ax;
I32 ret_gimme = GIMME_V;
int i;
AV *spill = NULL; /* accumulates results if too big for stack */
dMULTICALL;
I32 gimme = G_LIST;
UNUSED_VAR_newsp;
PUSH_MULTICALL(cv);
for(; argi < items; argi += 2) {
int count;
GvSV(agv) = stack[argi];
GvSV(bgv) = argi < items-1 ? stack[argi+1]: &PL_sv_undef;
MULTICALL;
count = PL_stack_sp - PL_stack_base;
if (count > 2 || spill) {
/* We can't return more than 2 results for a given input pair
* without trashing the remaining arguments on the stack still
* to be processed, or possibly overrunning the stack end.
* So, we'll accumulate the results in a temporary buffer
* instead.
* We didn't do this initially because in the common case, most
* code blocks will return only 1 or 2 items so it won't be
* necessary
*/
int fill;
if (!spill) {
spill = newAV();
AvREAL_off(spill); /* don't ref count its contents */
/* can't mortalize here as every nextstate in the code
* block frees temps */
SAVEFREESV(spill);
ListUtil.xs view on Meta::CPAN
if( !((iv * sign) & (~valid_bits)) ) {
/* Avoid altering arg's flags */
nv_arg = uok ? (NV)SvUV(arg) : (NV)SvIV(arg);
sv_setpvn(keysv, (char *) &nv_arg, 8);
}
else {
/* Read in the bytes, rather than the numeric value of the IV/UV as *
* this is more efficient, despite having to sv_catpvn an extra byte.*/
sv_setpvn(keysv, (char *) &iv, 8);
/* We add an extra byte to distinguish between an IV/UV and an NV. *
* We also use that byte to distinguish between a -ve IV and a UV. */
if(uok) sv_catpvn(keysv, "U", 1);
else sv_catpvn(keysv, "I", 1);
}
}
}
else {
nv_arg = SvNV(arg);
/* for NaN, use the platform's normal stringification */
if (nv_arg != nv_arg) sv_setpvf(keysv, "%" NVgf, nv_arg);
/* use "0" for all zeros */
else if(nv_arg == 0) sv_setpvs(keysv, "0");
else sv_setpvn(keysv, (char *) &nv_arg, 8);
}
#endif
#ifdef HV_FETCH_EMPTY_HE
he = (HE*) hv_common(seen, NULL, SvPVX(keysv), SvCUR(keysv), 0, HV_FETCH_LVALUE | HV_FETCH_EMPTY_HE, NULL, 0);
if (HeVAL(he))
continue;
HeVAL(he) = &PL_sv_undef;
#else
if(hv_exists(seen, SvPVX(keysv), SvCUR(keysv)))
continue;
hv_store(seen, SvPVX(keysv), SvCUR(keysv), &PL_sv_yes, 0);
#endif
if(GIMME_V == G_LIST)
ST(retcount) = SvOK(arg) ? arg : sv_2mortal(newSViv(0));
retcount++;
}
finish:
if(GIMME_V == G_LIST)
XSRETURN(retcount);
else
ST(0) = sv_2mortal(newSViv(retcount));
}
void
zip(...)
ALIAS:
zip_longest = ZIP_LONGEST
zip_shortest = ZIP_SHORTEST
mesh = ZIP_MESH
mesh_longest = ZIP_MESH_LONGEST
mesh_shortest = ZIP_MESH_SHORTEST
PPCODE:
Size_t nlists = items; /* number of lists */
AV **lists; /* inbound lists */
Size_t len = 0; /* length of longest inbound list = length of result */
Size_t i;
bool is_mesh = (ix & ZIP_MESH);
ix &= ~ZIP_MESH;
if(!nlists)
XSRETURN(0);
Newx(lists, nlists, AV *);
SAVEFREEPV(lists);
/* TODO: This may or maynot work on objects with arrayification overload */
/* Remember to unit test it */
for(i = 0; i < nlists; i++) {
SV *arg = ST(i);
AV *av;
if(!SvROK(arg) || SvTYPE(SvRV(arg)) != SVt_PVAV)
croak("Expected an ARRAY reference to %s",
is_mesh ? "mesh" : "zip");
av = lists[i] = (AV *)SvRV(arg);
if(!i) {
len = av_count(av);
continue;
}
switch(ix) {
case 0: /* zip is alias to zip_longest */
case ZIP_LONGEST:
if(av_count(av) > len)
len = av_count(av);
break;
case ZIP_SHORTEST:
if(av_count(av) < len)
len = av_count(av);
break;
}
}
if(is_mesh) {
SSize_t retcount = (SSize_t)(len * nlists);
EXTEND(SP, retcount);
for(i = 0; i < len; i++) {
Size_t listi;
for(listi = 0; listi < nlists; listi++) {
SV *item = (i < av_count(lists[listi])) ?
AvARRAY(lists[listi])[i] :
&PL_sv_undef;
mPUSHs(newSVsv(item));
}
}
ListUtil.xs view on Meta::CPAN
SV *
looks_like_number(sv)
SV *sv
PROTOTYPE: $
CODE:
SV *tempsv;
SvGETMAGIC(sv);
if(SvAMAGIC(sv) && (tempsv = AMG_CALLun(sv, numer))) {
sv = tempsv;
}
#if !PERL_VERSION_GE(5,8,5)
if(SvPOK(sv) || SvPOKp(sv)) {
RETVAL = looks_like_number(sv) ? &PL_sv_yes : &PL_sv_no;
}
else {
RETVAL = (SvFLAGS(sv) & (SVf_NOK|SVp_NOK|SVf_IOK|SVp_IOK)) ? &PL_sv_yes : &PL_sv_no;
}
#else
RETVAL = looks_like_number(sv) ? &PL_sv_yes : &PL_sv_no;
#endif
OUTPUT:
RETVAL
void
openhandle(SV *sv)
PROTOTYPE: $
CODE:
{
IO *io = NULL;
SvGETMAGIC(sv);
if(SvROK(sv)){
/* deref first */
sv = SvRV(sv);
}
/* must be GLOB or IO */
if(isGV(sv)){
io = GvIO((GV*)sv);
}
else if(SvTYPE(sv) == SVt_PVIO){
io = (IO*)sv;
}
if(io){
/* real or tied filehandle? */
if(IoIFP(io) || SvTIED_mg((SV*)io, PERL_MAGIC_tiedscalar)){
XSRETURN(1);
}
}
XSRETURN_UNDEF;
}
MODULE=List::Util PACKAGE=Sub::Util
void
set_prototype(proto, code)
SV *proto
SV *code
PREINIT:
SV *cv; /* not CV * */
PPCODE:
SvGETMAGIC(code);
if(!SvROK(code))
croak("set_prototype: not a reference");
cv = SvRV(code);
if(SvTYPE(cv) != SVt_PVCV)
croak("set_prototype: not a subroutine reference");
if(SvPOK(proto)) {
/* set the prototype */
sv_copypv(cv, proto);
}
else {
/* delete the prototype */
SvPOK_off(cv);
}
PUSHs(code);
XSRETURN(1);
void
set_subname(name, sub)
SV *name
SV *sub
PREINIT:
CV *cv = NULL;
GV *gv;
HV *stash = CopSTASH(PL_curcop);
const char *s, *end = NULL, *begin = NULL;
MAGIC *mg;
STRLEN namelen;
const char* nameptr = SvPV(name, namelen);
int utf8flag = SvUTF8(name);
#if PERL_VERSION_LT(5, 41, 3) || PERL_VERSION_GT(5, 41, 5)
int quotes_seen = 0;
bool need_subst = FALSE;
#endif
PPCODE:
if (!SvROK(sub) && SvGMAGICAL(sub))
mg_get(sub);
if (SvROK(sub))
cv = (CV *) SvRV(sub);
else if (SvTYPE(sub) == SVt_PVGV)
cv = GvCVu(sub);
else if (!SvOK(sub))
croak(PL_no_usym, "a subroutine");
else if (PL_op->op_private & HINT_STRICT_REFS)
croak("Can't use string (\"%.32s\") as %s ref while \"strict refs\" in use",
SvPV_nolen(sub), "a subroutine");
else if ((gv = gv_fetchsv(sub, FALSE, SVt_PVCV)))
cv = GvCVu(gv);
if (!cv)
croak("Undefined subroutine %s", SvPV_nolen(sub));
if (SvTYPE(cv) != SVt_PVCV && SvTYPE(cv) != SVt_PVFM)
croak("Not a subroutine reference");
for (s = nameptr; s <= nameptr + namelen; s++) {
if (s > nameptr && *s == ':' && s[-1] == ':') {
end = s - 1;
begin = ++s;
#if PERL_VERSION_LT(5, 41, 3) || PERL_VERSION_GT(5, 41, 5)
if (quotes_seen)
need_subst = TRUE;
#endif
}
#if PERL_VERSION_LT(5, 41, 3) || PERL_VERSION_GT(5, 41, 5)
else if (s > nameptr && *s != '\0' && s[-1] == '\'') {
end = s - 1;
begin = s;
if (quotes_seen++)
need_subst = TRUE;
}
#endif
}
s--;
if (end) {
#if PERL_VERSION_LT(5, 41, 3) || PERL_VERSION_GT(5, 41, 5)
SV* tmp;
if (need_subst) {
STRLEN length = end - nameptr + quotes_seen - (*end == '\'' ? 1 : 0);
char* left;
int i, j;
tmp = sv_2mortal(newSV(length));
left = SvPVX(tmp);
for (i = 0, j = 0; j < end - nameptr; ++i, ++j) {
if (nameptr[j] == '\'') {
left[i] = ':';
left[++i] = ':';
}
else {
left[i] = nameptr[j];
}
}
stash = gv_stashpvn(left, length, GV_ADD | utf8flag);
}
else
#endif
stash = gv_stashpvn(nameptr, end - nameptr, GV_ADD | utf8flag);
nameptr = begin;
ListUtil.xs view on Meta::CPAN
if (oldhv) {
SV* old_full_name = sv_2mortal(newSVpvn_flags(HvNAME(oldhv), HvNAMELEN_get(oldhv), HvNAMEUTF8(oldhv) ? SVf_UTF8 : 0));
sv_catpvn(old_full_name, "::", 2);
sv_catpvn_flags(old_full_name, GvNAME(oldgv), GvNAMELEN(oldgv), GvNAMEUTF8(oldgv) ? SV_CATUTF8 : SV_CATBYTES);
old_data = hv_fetch_ent(DBsub, old_full_name, 0, 0);
}
if (old_data && HeVAL(old_data)) {
SV* old_val = HeVAL(old_data);
SV* new_full_name = sv_2mortal(newSVpvn_flags(HvNAME(stash), HvNAMELEN_get(stash), HvNAMEUTF8(stash) ? SVf_UTF8 : 0));
sv_catpvn(new_full_name, "::", 2);
sv_catpvn_flags(new_full_name, nameptr, s - nameptr, utf8flag ? SV_CATUTF8 : SV_CATBYTES);
SvREFCNT_inc(old_val);
if (!hv_store_ent(DBsub, new_full_name, old_val, 0))
SvREFCNT_dec(old_val);
}
}
gv = (GV *) newSV(0);
gv_init_pvn(gv, stash, nameptr, s - nameptr, GV_ADDMULTI | utf8flag);
/*
* set_subname needs to create a GV to store the name. The CvGV field of a
* CV is not refcounted, so perl wouldn't know to SvREFCNT_dec() this GV if
* it destroys the containing CV. We use a MAGIC with an empty vtable
* simply for the side-effect of using MGf_REFCOUNTED to store the
* actually-counted reference to the GV.
*/
mg = SvMAGIC(cv);
while (mg && mg->mg_virtual != &subname_vtbl)
mg = mg->mg_moremagic;
if (!mg) {
Newxz(mg, 1, MAGIC);
mg->mg_moremagic = SvMAGIC(cv);
mg->mg_type = PERL_MAGIC_ext;
mg->mg_virtual = &subname_vtbl;
SvMAGIC_set(cv, mg);
}
if (mg->mg_flags & MGf_REFCOUNTED)
SvREFCNT_dec(mg->mg_obj);
mg->mg_flags |= MGf_REFCOUNTED;
mg->mg_obj = (SV *) gv;
SvRMAGICAL_on(cv);
CvANON_off(cv);
#ifndef CvGV_set
CvGV(cv) = gv;
#else
CvGV_set(cv, gv);
#endif
PUSHs(sub);
void
subname(code)
SV *code
PREINIT:
CV *cv;
GV *gv;
const char *stashname;
PPCODE:
if (!SvROK(code) && SvGMAGICAL(code))
mg_get(code);
if(!SvROK(code) || SvTYPE(cv = (CV *)SvRV(code)) != SVt_PVCV)
croak("Not a subroutine reference");
if(!(gv = CvGV(cv)))
XSRETURN(0);
if(GvSTASH(gv))
stashname = HvNAME(GvSTASH(gv));
else
stashname = "__ANON__";
mPUSHs(newSVpvf("%s::%s", stashname, GvNAME(gv)));
XSRETURN(1);
BOOT:
{
HV *lu_stash = gv_stashpvn("List::Util", 10, TRUE);
GV *rmcgv = *(GV**)hv_fetch(lu_stash, "REAL_MULTICALL", 14, TRUE);
SV *rmcsv;
if(SvTYPE(rmcgv) != SVt_PVGV)
gv_init(rmcgv, lu_stash, "List::Util", 10, TRUE);
rmcsv = GvSVn(rmcgv);
#ifdef REAL_MULTICALL
sv_setsv(rmcsv, &PL_sv_yes);
#else
sv_setsv(rmcsv, &PL_sv_no);
#endif
}
( run in 0.922 second using v1.01-cache-2.11-cpan-5511b514fd6 )