#include "EXTERN.h"
#define PERL_IN_PP_HOT_C
#include "perl.h"
#ifdef USE_5005THREADS
static void unset_cvowner(pTHX_ void *cvarg);
#endif
PP(pp_const)
{
dSP;
XPUSHs(cSVOP_sv);
RETURN;
}
PP(pp_nextstate)
{
PL_curcop = (COP*)PL_op;
TAINT_NOT;
PL_stack_sp = PL_stack_base + cxstack[cxstack_ix].blk_oldsp;
FREETMPS;
return NORMAL;
}
PP(pp_gvsv)
{
dSP;
EXTEND(SP,1);
if (PL_op->op_private & OPpLVAL_INTRO)
PUSHs(save_scalar(cGVOP_gv));
else
PUSHs(GvSV(cGVOP_gv));
RETURN;
}
PP(pp_null)
{
return NORMAL;
}
PP(pp_setstate)
{
PL_curcop = (COP*)PL_op;
return NORMAL;
}
PP(pp_pushmark)
{
PUSHMARK(PL_stack_sp);
return NORMAL;
}
PP(pp_stringify)
{
dSP; dTARGET;
sv_copypv(TARG,TOPs);
SETTARG;
RETURN;
}
PP(pp_gv)
{
dSP;
XPUSHs((SV*)cGVOP_gv);
RETURN;
}
PP(pp_and)
{
dSP;
if (!SvTRUE(TOPs))
RETURN;
else {
--SP;
RETURNOP(cLOGOP->op_other);
}
}
PP(pp_sassign)
{
dSP; dPOPTOPssrl;
if (PL_op->op_private & OPpASSIGN_BACKWARDS) {
SV *temp;
temp = left; left = right; right = temp;
}
if (PL_tainting && PL_tainted && !SvTAINTED(left))
TAINT_NOT;
SvSetMagicSV(right, left);
SETs(right);
RETURN;
}
PP(pp_cond_expr)
{
dSP;
if (SvTRUEx(POPs))
RETURNOP(cLOGOP->op_other);
else
RETURNOP(cLOGOP->op_next);
}
PP(pp_unstack)
{
I32 oldsave;
TAINT_NOT;
PL_stack_sp = PL_stack_base + cxstack[cxstack_ix].blk_oldsp;
FREETMPS;
oldsave = PL_scopestack[PL_scopestack_ix - 1];
LEAVE_SCOPE(oldsave);
return NORMAL;
}
PP(pp_concat)
{
dSP; dATARGET; tryAMAGICbin(concat,opASSIGN);
{
dPOPTOPssrl;
STRLEN llen;
char* lpv;
bool lbyte;
STRLEN rlen;
char* rpv = SvPV(right, rlen);
bool rbyte = !SvUTF8(right), rcopied = FALSE;
if (TARG == right && right != left) {
right = sv_2mortal(newSVpvn(rpv, rlen));
rpv = SvPV(right, rlen);
rcopied = TRUE;
}
if (TARG != left) {
lpv = SvPV(left, llen);
lbyte = !SvUTF8(left);
sv_setpvn(TARG, lpv, llen);
if (!lbyte)
SvUTF8_on(TARG);
else
SvUTF8_off(TARG);
}
else {
if (SvGMAGICAL(left))
mg_get(left);
if (!SvOK(TARG))
sv_setpv(left, "");
lpv = SvPV_nomg(left, llen);
lbyte = !SvUTF8(left);
}
#if defined(PERL_Y2KWARN)
if ((SvIOK(right) || SvNOK(right)) && ckWARN(WARN_Y2K) && SvOK(TARG)) {
if (llen >= 2 && lpv[llen - 2] == '1' && lpv[llen - 1] == '9'
&& (llen == 2 || !isDIGIT(lpv[llen - 3])))
{
Perl_warner(aTHX_ packWARN(WARN_Y2K), "Possible Y2K bug: %s",
"about to append an integer to '19'");
}
}
#endif
if (lbyte != rbyte) {
if (lbyte)
sv_utf8_upgrade_nomg(TARG);
else {
if (!rcopied)
right = sv_2mortal(newSVpvn(rpv, rlen));
sv_utf8_upgrade_nomg(right);
rpv = SvPV(right, rlen);
}
}
sv_catpvn_nomg(TARG, rpv, rlen);
SETTARG;
RETURN;
}
}
PP(pp_padsv)
{
dSP; dTARGET;
XPUSHs(TARG);
if (PL_op->op_flags & OPf_MOD) {
if (PL_op->op_private & OPpLVAL_INTRO)
SAVECLEARSV(PAD_SVl(PL_op->op_targ));
else if (PL_op->op_private & OPpDEREF) {
PUTBACK;
vivify_ref(PAD_SVl(PL_op->op_targ), PL_op->op_private & OPpDEREF);
SPAGAIN;
}
}
RETURN;
}
PP(pp_readline)
{
tryAMAGICunTARGET(iter, 0);
PL_last_in_gv = (GV*)(*PL_stack_sp--);
if (SvTYPE(PL_last_in_gv) != SVt_PVGV) {
if (SvROK(PL_last_in_gv) && SvTYPE(SvRV(PL_last_in_gv)) == SVt_PVGV)
PL_last_in_gv = (GV*)SvRV(PL_last_in_gv);
else {
dSP;
XPUSHs((SV*)PL_last_in_gv);
PUTBACK;
pp_rv2gv();
PL_last_in_gv = (GV*)(*PL_stack_sp--);
}
}
return do_readline();
}
PP(pp_eq)
{
dSP; tryAMAGICbinSET(eq,0);
#ifndef NV_PRESERVES_UV
if (SvROK(TOPs) && SvROK(TOPm1s)) {
SP--;
SETs(boolSV(SvRV(TOPs) == SvRV(TOPp1s)));
RETURN;
}
#endif
#ifdef PERL_PRESERVE_IVUV
SvIV_please(TOPs);
if (SvIOK(TOPs)) {
SvIV_please(TOPm1s);
if (SvIOK(TOPm1s)) {
bool auvok = SvUOK(TOPm1s);
bool buvok = SvUOK(TOPs);
if (auvok == buvok) {
UV buv = SvUVX(POPs);
UV auv = SvUVX(TOPs);
SETs(boolSV(auv == buv));
RETURN;
}
{
SV *ivp, *uvp;
IV iv;
if (auvok) {
ivp = *SP;
uvp = *--SP;
} else {
uvp = *SP;
ivp = *--SP;
}
iv = SvIVX(ivp);
if (iv < 0) {
SETs(&PL_sv_no);
RETURN;
}
SETs(boolSV((UV)iv == SvUVX(uvp)));
RETURN;
}
}
}
#endif
{
dPOPnv;
SETs(boolSV(TOPn == value));
RETURN;
}
}
PP(pp_preinc)
{
dSP;
if (SvTYPE(TOPs) > SVt_PVLV)
DIE(aTHX_ PL_no_modify);
if (!SvREADONLY(TOPs) && SvIOK_notUV(TOPs) && !SvNOK(TOPs) && !SvPOK(TOPs)
&& SvIVX(TOPs) != IV_MAX)
{
++SvIVX(TOPs);
SvFLAGS(TOPs) &= ~(SVp_NOK|SVp_POK);
}
else
sv_inc(TOPs);
SvSETMAGIC(TOPs);
return NORMAL;
}
PP(pp_or)
{
dSP;
if (SvTRUE(TOPs))
RETURN;
else {
--SP;
RETURNOP(cLOGOP->op_other);
}
}
PP(pp_add)
{
dSP; dATARGET; bool useleft; tryAMAGICbin(add,opASSIGN);
useleft = USE_LEFT(TOPm1s);
#ifdef PERL_PRESERVE_IVUV
SvIV_please(TOPs);
if (SvIOK(TOPs)) {
register UV auv = 0;
bool auvok = FALSE;
bool a_valid = 0;
if (!useleft) {
auv = 0;
a_valid = auvok = 1;
} else {
SvIV_please(TOPm1s);
if (SvIOK(TOPm1s)) {
if ((auvok = SvUOK(TOPm1s)))
auv = SvUVX(TOPm1s);
else {
register IV aiv = SvIVX(TOPm1s);
if (aiv >= 0) {
auv = aiv;
auvok = 1;
} else {
auv = (UV)-aiv;
}
}
a_valid = 1;
}
}
if (a_valid) {
bool result_good = 0;
UV result;
register UV buv;
bool buvok = SvUOK(TOPs);
if (buvok)
buv = SvUVX(TOPs);
else {
register IV biv = SvIVX(TOPs);
if (biv >= 0) {
buv = biv;
buvok = 1;
} else
buv = (UV)-biv;
}
if (auvok ^ buvok) {
if (auv >= buv) {
result = auv - buv;
if (result <= auv)
result_good = 1;
} else {
result = buv - auv;
if (result <= buv) {
auvok = !auvok;
result_good = 1;
}
}
} else {
result = auv + buv;
if (result >= auv)
result_good = 1;
}
if (result_good) {
SP--;
if (auvok)
SETu( result );
else {
if (result <= (UV)IV_MIN)
SETi( -(IV)result );
else {
SETn( -(NV)result );
}
}
RETURN;
}
}
}
#endif
{
dPOPnv;
if (!useleft) {
SETn(value);
RETURN;
}
SETn( value + TOPn );
RETURN;
}
}
PP(pp_aelemfast)
{
dSP;
AV *av = GvAV(cGVOP_gv);
U32 lval = PL_op->op_flags & OPf_MOD;
SV** svp = av_fetch(av, PL_op->op_private, lval);
SV *sv = (svp ? *svp : &PL_sv_undef);
EXTEND(SP, 1);
if (!lval && SvGMAGICAL(sv))
sv = sv_mortalcopy(sv);
PUSHs(sv);
RETURN;
}
PP(pp_join)
{
dSP; dMARK; dTARGET;
MARK++;
do_join(TARG, *MARK, MARK, SP);
SP = MARK;
SETs(TARG);
RETURN;
}
PP(pp_pushre)
{
dSP;
#ifdef DEBUGGING
SV* sv = sv_newmortal();
sv_upgrade(sv, SVt_PVLV);
LvTYPE(sv) = '/';
Copy(&PL_op, &LvTARGOFF(sv), 1, OP*);
XPUSHs(sv);
#else
XPUSHs((SV*)PL_op);
#endif
RETURN;
}
PP(pp_print)
{
dSP; dMARK; dORIGMARK;
GV *gv;
IO *io;
register PerlIO *fp;
MAGIC *mg;
if (PL_op->op_flags & OPf_STACKED)
gv = (GV*)*++MARK;
else
gv = PL_defoutgv;
if (gv && (io = GvIO(gv))
&& (mg = SvTIED_mg((SV*)io, PERL_MAGIC_tiedscalar)))
{
had_magic:
if (MARK == ORIGMARK) {
MEXTEND(SP, 1);
++MARK;
Move(MARK, MARK + 1, (SP - MARK) + 1, SV*);
++SP;
}
PUSHMARK(MARK - 1);
*MARK = SvTIED_obj((SV*)io, mg);
PUTBACK;
ENTER;
call_method("PRINT", G_SCALAR);
LEAVE;
SPAGAIN;
MARK = ORIGMARK + 1;
*MARK = *SP;
SP = MARK;
RETURN;
}
if (!(io = GvIO(gv))) {
if ((GvEGV(gv)) && (io = GvIO(GvEGV(gv)))
&& (mg = SvTIED_mg((SV*)io, PERL_MAGIC_tiedscalar)))
goto had_magic;
if (ckWARN2(WARN_UNOPENED,WARN_CLOSED))
report_evil_fh(gv, io, PL_op->op_type);
SETERRNO(EBADF,RMS_IFI);
goto just_say_no;
}
else if (!(fp = IoOFP(io))) {
if (ckWARN2(WARN_CLOSED, WARN_IO)) {
if (IoIFP(io))
report_evil_fh(gv, io, OP_phoney_INPUT_ONLY);
else if (ckWARN2(WARN_UNOPENED,WARN_CLOSED))
report_evil_fh(gv, io, PL_op->op_type);
}
SETERRNO(EBADF,IoIFP(io)?RMS_FAC:RMS_IFI);
goto just_say_no;
}
else {
MARK++;
if (PL_ofs_sv && SvOK(PL_ofs_sv)) {
while (MARK <= SP) {
if (!do_print(*MARK, fp))
break;
MARK++;
if (MARK <= SP) {
if (!do_print(PL_ofs_sv, fp)) {
MARK--;
break;
}
}
}
}
else {
while (MARK <= SP) {
if (!do_print(*MARK, fp))
break;
MARK++;
}
}
if (MARK <= SP)
goto just_say_no;
else {
if (PL_ors_sv && SvOK(PL_ors_sv))
if (!do_print(PL_ors_sv, fp))
goto just_say_no;
if (IoFLAGS(io) & IOf_FLUSH)
if (PerlIO_flush(fp) == EOF)
goto just_say_no;
}
}
SP = ORIGMARK;
PUSHs(&PL_sv_yes);
RETURN;
just_say_no:
SP = ORIGMARK;
PUSHs(&PL_sv_undef);
RETURN;
}
PP(pp_rv2av)
{
dSP; dTOPss;
AV *av;
if (SvROK(sv)) {
wasref:
tryAMAGICunDEREF(to_av);
av = (AV*)SvRV(sv);
if (SvTYPE(av) != SVt_PVAV)
DIE(aTHX_ "Not an ARRAY reference");
if (PL_op->op_flags & OPf_REF) {
SETs((SV*)av);
RETURN;
}
else if (LVRET) {
if (GIMME == G_SCALAR)
Perl_croak(aTHX_ "Can't return array to lvalue scalar context");
SETs((SV*)av);
RETURN;
}
else if (PL_op->op_flags & OPf_MOD
&& PL_op->op_private & OPpLVAL_INTRO)
Perl_croak(aTHX_ PL_no_localize_ref);
}
else {
if (SvTYPE(sv) == SVt_PVAV) {
av = (AV*)sv;
if (PL_op->op_flags & OPf_REF) {
SETs((SV*)av);
RETURN;
}
else if (LVRET) {
if (GIMME == G_SCALAR)
Perl_croak(aTHX_ "Can't return array to lvalue"
" scalar context");
SETs((SV*)av);
RETURN;
}
}
else {
GV *gv;
if (SvTYPE(sv) != SVt_PVGV) {
char *sym;
STRLEN len;
if (SvGMAGICAL(sv)) {
mg_get(sv);
if (SvROK(sv))
goto wasref;
}
if (!SvOK(sv)) {
if (PL_op->op_flags & OPf_REF ||
PL_op->op_private & HINT_STRICT_REFS)
DIE(aTHX_ PL_no_usym, "an ARRAY");
if (ckWARN(WARN_UNINITIALIZED))
report_uninit();
if (GIMME == G_ARRAY) {
(void)POPs;
RETURN;
}
RETSETUNDEF;
}
sym = SvPV(sv,len);
if ((PL_op->op_flags & OPf_SPECIAL) &&
!(PL_op->op_flags & OPf_MOD))
{
gv = (GV*)gv_fetchpv(sym, FALSE, SVt_PVAV);
if (!gv
&& (!is_gv_magical(sym,len,0)
|| !(gv = (GV*)gv_fetchpv(sym, TRUE, SVt_PVAV))))
{
RETSETUNDEF;
}
}
else {
if (PL_op->op_private & HINT_STRICT_REFS)
DIE(aTHX_ PL_no_symref, sym, "an ARRAY");
gv = (GV*)gv_fetchpv(sym, TRUE, SVt_PVAV);
}
}
else {
gv = (GV*)sv;
}
av = GvAVn(gv);
if (PL_op->op_private & OPpLVAL_INTRO)
av = save_ary(gv);
if (PL_op->op_flags & OPf_REF) {
SETs((SV*)av);
RETURN;
}
else if (LVRET) {
if (GIMME == G_SCALAR)
Perl_croak(aTHX_ "Can't return array to lvalue"
" scalar context");
SETs((SV*)av);
RETURN;
}
}
}
if (GIMME == G_ARRAY) {
I32 maxarg = AvFILL(av) + 1;
(void)POPs;
EXTEND(SP, maxarg);
if (SvRMAGICAL(av)) {
U32 i;
for (i=0; i < (U32)maxarg; i++) {
SV **svp = av_fetch(av, i, FALSE);
SP[i+1] = (svp) ? *svp : &PL_sv_undef;
}
}
else {
Copy(AvARRAY(av), SP+1, maxarg, SV*);
}
SP += maxarg;
}
else if (GIMME_V == G_SCALAR) {
dTARGET;
I32 maxarg = AvFILL(av) + 1;
SETi(maxarg);
}
RETURN;
}
PP(pp_rv2hv)
{
dSP; dTOPss;
HV *hv;
I32 gimme = GIMME_V;
if (SvROK(sv)) {
wasref:
tryAMAGICunDEREF(to_hv);
hv = (HV*)SvRV(sv);
if (SvTYPE(hv) != SVt_PVHV && SvTYPE(hv) != SVt_PVAV)
DIE(aTHX_ "Not a HASH reference");
if (PL_op->op_flags & OPf_REF) {
SETs((SV*)hv);
RETURN;
}
else if (LVRET) {
if (GIMME != G_SCALAR)
Perl_croak(aTHX_ "Can't return hash to lvalue scalar context");
SETs((SV*)hv);
RETURN;
}
else if (PL_op->op_flags & OPf_MOD
&& PL_op->op_private & OPpLVAL_INTRO)
Perl_croak(aTHX_ PL_no_localize_ref);
}
else {
if (SvTYPE(sv) == SVt_PVHV || SvTYPE(sv) == SVt_PVAV) {
hv = (HV*)sv;
if (PL_op->op_flags & OPf_REF) {
SETs((SV*)hv);
RETURN;
}
else if (LVRET) {
if (GIMME == G_SCALAR)
Perl_croak(aTHX_ "Can't return hash to lvalue"
" scalar context");
SETs((SV*)hv);
RETURN;
}
}
else {
GV *gv;
if (SvTYPE(sv) != SVt_PVGV) {
char *sym;
STRLEN len;
if (SvGMAGICAL(sv)) {
mg_get(sv);
if (SvROK(sv))
goto wasref;
}
if (!SvOK(sv)) {
if (PL_op->op_flags & OPf_REF ||
PL_op->op_private & HINT_STRICT_REFS)
DIE(aTHX_ PL_no_usym, "a HASH");
if (ckWARN(WARN_UNINITIALIZED))
report_uninit();
if (GIMME == G_ARRAY) {
SP--;
RETURN;
}
RETSETUNDEF;
}
sym = SvPV(sv,len);
if ((PL_op->op_flags & OPf_SPECIAL) &&
!(PL_op->op_flags & OPf_MOD))
{
gv = (GV*)gv_fetchpv(sym, FALSE, SVt_PVHV);
if (!gv
&& (!is_gv_magical(sym,len,0)
|| !(gv = (GV*)gv_fetchpv(sym, TRUE, SVt_PVHV))))
{
RETSETUNDEF;
}
}
else {
if (PL_op->op_private & HINT_STRICT_REFS)
DIE(aTHX_ PL_no_symref, sym, "a HASH");
gv = (GV*)gv_fetchpv(sym, TRUE, SVt_PVHV);
}
}
else {
gv = (GV*)sv;
}
hv = GvHVn(gv);
if (PL_op->op_private & OPpLVAL_INTRO)
hv = save_hash(gv);
if (PL_op->op_flags & OPf_REF) {
SETs((SV*)hv);
RETURN;
}
else if (LVRET) {
if (GIMME == G_SCALAR)
Perl_croak(aTHX_ "Can't return hash to lvalue"
" scalar context");
SETs((SV*)hv);
RETURN;
}
}
}
if (GIMME == G_ARRAY) {
*PL_stack_sp = (SV*)hv;
return do_kv();
}
else {
dTARGET;
if (SvTYPE(hv) == SVt_PVAV)
hv = avhv_keys((AV*)hv);
if (HvFILL(hv))
Perl_sv_setpvf(aTHX_ TARG, "%"IVdf"/%"IVdf,
(IV)HvFILL(hv), (IV)HvMAX(hv) + 1);
else
sv_setiv(TARG, 0);
SETTARG;
RETURN;
}
}
STATIC int
S_do_maybe_phash(pTHX_ AV *ary, SV **lelem, SV **firstlelem, SV **relem,
SV **lastrelem)
{
OP *leftop;
I32 i;
leftop = ((BINOP*)PL_op)->op_last;
assert(leftop);
assert(leftop->op_type == OP_NULL && leftop->op_targ == OP_LIST);
leftop = ((LISTOP*)leftop)->op_first;
assert(leftop);
for (i = lelem - firstlelem; i > 0; i--) {
leftop = leftop->op_sibling;
assert(leftop);
}
if (leftop->op_type != OP_RV2HV)
return 0;
if (av_len(ary) > 0)
av_fill(ary, 0);
if (lastrelem >= relem) {
while (relem < lastrelem) {
SV *tmpstr;
assert(relem[0]);
assert(relem[1]);
tmpstr = sv_newmortal();
sv_setsv(tmpstr,relem[1]);
relem[1] = tmpstr;
if (avhv_store_ent(ary,relem[0],tmpstr,0))
(void)SvREFCNT_inc(tmpstr);
if (SvMAGICAL(ary) != 0 && SvSMAGICAL(tmpstr))
mg_set(tmpstr);
relem += 2;
TAINT_NOT;
}
}
if (relem == lastrelem)
return 1;
return 2;
}
STATIC void
S_do_oddball(pTHX_ HV *hash, SV **relem, SV **firstrelem)
{
if (*relem) {
SV *tmpstr;
if (ckWARN(WARN_MISC)) {
if (relem == firstrelem &&
SvROK(*relem) &&
(SvTYPE(SvRV(*relem)) == SVt_PVAV ||
SvTYPE(SvRV(*relem)) == SVt_PVHV))
{
Perl_warner(aTHX_ packWARN(WARN_MISC),
"Reference found where even-sized list expected");
}
else
Perl_warner(aTHX_ packWARN(WARN_MISC),
"Odd number of elements in hash assignment");
}
if (SvTYPE(hash) == SVt_PVAV) {
tmpstr = sv_newmortal();
if (avhv_store_ent((AV*)hash,*relem,tmpstr,0))
(void)SvREFCNT_inc(tmpstr);
if (SvMAGICAL(hash) && SvSMAGICAL(tmpstr))
mg_set(tmpstr);
}
else {
HE *didstore;
tmpstr = NEWSV(29,0);
didstore = hv_store_ent(hash,*relem,tmpstr,0);
if (SvMAGICAL(hash)) {
if (SvSMAGICAL(tmpstr))
mg_set(tmpstr);
if (!didstore)
sv_2mortal(tmpstr);
}
}
TAINT_NOT;
}
}
PP(pp_aassign)
{
dSP;
SV **lastlelem = PL_stack_sp;
SV **lastrelem = PL_stack_base + POPMARK;
SV **firstrelem = PL_stack_base + POPMARK + 1;
SV **firstlelem = lastrelem + 1;
register SV **relem;
register SV **lelem;
register SV *sv;
register AV *ary;
I32 gimme;
HV *hash;
I32 i;
int magic;
PL_delaymagic = DM_DELAY;
if (PL_op->op_private & (OPpASSIGN_COMMON)) {
EXTEND_MORTAL(lastrelem - firstrelem + 1);
for (relem = firstrelem; relem <= lastrelem; relem++) {
if ((sv = *relem)) {
TAINT_NOT;
*relem = sv_mortalcopy(sv);
}
}
}
relem = firstrelem;
lelem = firstlelem;
ary = Null(AV*);
hash = Null(HV*);
while (lelem <= lastlelem) {
TAINT_NOT;
sv = *lelem++;
switch (SvTYPE(sv)) {
case SVt_PVAV:
ary = (AV*)sv;
magic = SvMAGICAL(ary) != 0;
if (PL_op->op_private & OPpASSIGN_HASH) {
switch (do_maybe_phash(ary, lelem, firstlelem, relem,
lastrelem))
{
case 0:
goto normal_array;
case 1:
do_oddball((HV*)ary, relem, firstrelem);
}
relem = lastrelem + 1;
break;
}
normal_array:
av_clear(ary);
av_extend(ary, lastrelem - relem);
i = 0;
while (relem <= lastrelem) {
SV **didstore;
sv = NEWSV(28,0);
assert(*relem);
sv_setsv(sv,*relem);
*(relem++) = sv;
didstore = av_store(ary,i++,sv);
if (magic) {
if (SvSMAGICAL(sv))
mg_set(sv);
if (!didstore)
sv_2mortal(sv);
}
TAINT_NOT;
}
break;
case SVt_PVHV: {
SV *tmpstr;
hash = (HV*)sv;
magic = SvMAGICAL(hash) != 0;
hv_clear(hash);
while (relem < lastrelem) {
HE *didstore;
if (*relem)
sv = *(relem++);
else
sv = &PL_sv_no, relem++;
tmpstr = NEWSV(29,0);
if (*relem)
sv_setsv(tmpstr,*relem);
*(relem++) = tmpstr;
didstore = hv_store_ent(hash,sv,tmpstr,0);
if (magic) {
if (SvSMAGICAL(tmpstr))
mg_set(tmpstr);
if (!didstore)
sv_2mortal(tmpstr);
}
TAINT_NOT;
}
if (relem == lastrelem) {
do_oddball(hash, relem, firstrelem);
relem++;
}
}
break;
default:
if (SvIMMORTAL(sv)) {
if (relem <= lastrelem)
relem++;
break;
}
if (relem <= lastrelem) {
sv_setsv(sv, *relem);
*(relem++) = sv;
}
else
sv_setsv(sv, &PL_sv_undef);
SvSETMAGIC(sv);
break;
}
}
if (PL_delaymagic & ~DM_DELAY) {
if (PL_delaymagic & DM_UID) {
#ifdef HAS_SETRESUID
(void)setresuid(PL_uid,PL_euid,(Uid_t)-1);
#else
# ifdef HAS_SETREUID
(void)setreuid(PL_uid,PL_euid);
# else
# ifdef HAS_SETRUID
if ((PL_delaymagic & DM_UID) == DM_RUID) {
(void)setruid(PL_uid);
PL_delaymagic &= ~DM_RUID;
}
# endif
# ifdef HAS_SETEUID
if ((PL_delaymagic & DM_UID) == DM_EUID) {
(void)seteuid(PL_uid);
PL_delaymagic &= ~DM_EUID;
}
# endif
if (PL_delaymagic & DM_UID) {
if (PL_uid != PL_euid)
DIE(aTHX_ "No setreuid available");
(void)PerlProc_setuid(PL_uid);
}
# endif
#endif
PL_uid = PerlProc_getuid();
PL_euid = PerlProc_geteuid();
}
if (PL_delaymagic & DM_GID) {
#ifdef HAS_SETRESGID
(void)setresgid(PL_gid,PL_egid,(Gid_t)-1);
#else
# ifdef HAS_SETREGID
(void)setregid(PL_gid,PL_egid);
# else
# ifdef HAS_SETRGID
if ((PL_delaymagic & DM_GID) == DM_RGID) {
(void)setrgid(PL_gid);
PL_delaymagic &= ~DM_RGID;
}
# endif
# ifdef HAS_SETEGID
if ((PL_delaymagic & DM_GID) == DM_EGID) {
(void)setegid(PL_gid);
PL_delaymagic &= ~DM_EGID;
}
# endif
if (PL_delaymagic & DM_GID) {
if (PL_gid != PL_egid)
DIE(aTHX_ "No setregid available");
(void)PerlProc_setgid(PL_gid);
}
# endif
#endif
PL_gid = PerlProc_getgid();
PL_egid = PerlProc_getegid();
}
PL_tainting |= (PL_uid && (PL_euid != PL_uid || PL_egid != PL_gid));
}
PL_delaymagic = 0;
gimme = GIMME_V;
if (gimme == G_VOID)
SP = firstrelem - 1;
else if (gimme == G_SCALAR) {
dTARGET;
SP = firstrelem;
SETi(lastrelem - firstrelem + 1);
}
else {
if (ary || hash)
SP = lastrelem;
else
SP = firstrelem + (lastlelem - firstlelem);
lelem = firstlelem + (relem - firstrelem);
while (relem <= SP)
*relem++ = (lelem <= lastlelem) ? *lelem++ : &PL_sv_undef;
}
RETURN;
}
PP(pp_qr)
{
dSP;
register PMOP *pm = cPMOP;
SV *rv = sv_newmortal();
SV *sv = newSVrv(rv, "Regexp");
if (pm->op_pmdynflags & PMdf_TAINTED)
SvTAINTED_on(rv);
sv_magic(sv,(SV*)ReREFCNT_inc(PM_GETRE(pm)), PERL_MAGIC_qr,0,0);
RETURNX(PUSHs(rv));
}
PP(pp_match)
{
dSP; dTARG;
register PMOP *pm = cPMOP;
PMOP *dynpm = pm;
register char *t;
register char *s;
char *strend;
I32 global;
I32 r_flags = REXEC_CHECKED;
char *truebase;
register REGEXP *rx = PM_GETRE(pm);
bool rxtainted;
I32 gimme = GIMME;
STRLEN len;
I32 minmatch = 0;
I32 oldsave = PL_savestack_ix;
I32 update_minmatch = 1;
I32 had_zerolen = 0;
if (PL_op->op_flags & OPf_STACKED)
TARG = POPs;
else {
TARG = DEFSV;
EXTEND(SP,1);
}
PUTBACK;
s = SvPV(TARG, len);
strend = s + len;
if (!s)
DIE(aTHX_ "panic: pp_match");
rxtainted = ((pm->op_pmdynflags & PMdf_TAINTED) ||
(PL_tainted && (pm->op_pmflags & PMf_RETAINT)));
TAINT_NOT;
RX_MATCH_UTF8_set(rx, DO_UTF8(TARG));
if (pm->op_pmdynflags & PMdf_USED) {
failure:
if (gimme == G_ARRAY)
RETURN;
RETPUSHNO;
}
if (!rx->prelen && PL_curpm) {
pm = PL_curpm;
rx = PM_GETRE(pm);
}
if (rx->minlen > (I32)len)
goto failure;
truebase = t = s;
if ((global = dynpm->op_pmflags & PMf_GLOBAL)) {
rx->startp[0] = -1;
if (SvTYPE(TARG) >= SVt_PVMG && SvMAGIC(TARG)) {
MAGIC* mg = mg_find(TARG, PERL_MAGIC_regex_global);
if (mg && mg->mg_len >= 0) {
if (!(rx->reganch & ROPT_GPOS_SEEN))
rx->endp[0] = rx->startp[0] = mg->mg_len;
else if (rx->reganch & ROPT_ANCH_GPOS) {
r_flags |= REXEC_IGNOREPOS;
rx->endp[0] = rx->startp[0] = mg->mg_len;
}
minmatch = (mg->mg_flags & MGf_MINMATCH);
update_minmatch = 0;
}
}
}
if ((!global && rx->nparens)
|| SvTEMP(TARG) || PL_sawampersand)
r_flags |= REXEC_COPY_STR;
if (SvSCREAM(TARG))
r_flags |= REXEC_SCREAM;
if (pm->op_pmflags & (PMf_MULTILINE|PMf_SINGLELINE)) {
SAVEINT(PL_multiline);
PL_multiline = pm->op_pmflags & PMf_MULTILINE;
}
play_it_again:
if (global && rx->startp[0] != -1) {
t = s = rx->endp[0] + truebase;
if ((s + rx->minlen) > strend)
goto nope;
if (update_minmatch++)
minmatch = had_zerolen;
}
if (rx->reganch & RE_USE_INTUIT &&
DO_UTF8(TARG) == ((rx->reganch & ROPT_UTF8) != 0)) {
PL_bostr = truebase;
s = CALLREG_INTUIT_START(aTHX_ rx, TARG, s, strend, r_flags, NULL);
if (!s)
goto nope;
if ( (rx->reganch & ROPT_CHECK_ALL)
&& !PL_sawampersand
&& ((rx->reganch & ROPT_NOSCAN)
|| !((rx->reganch & RE_INTUIT_TAIL)
&& (r_flags & REXEC_SCREAM)))
&& !SvROK(TARG))
goto yup;
}
if (CALLREGEXEC(aTHX_ rx, s, strend, truebase, minmatch, TARG, NULL, r_flags))
{
PL_curpm = pm;
if (dynpm->op_pmflags & PMf_ONCE)
dynpm->op_pmdynflags |= PMdf_USED;
goto gotcha;
}
else
goto ret_no;
gotcha:
if (rxtainted)
RX_MATCH_TAINTED_on(rx);
TAINT_IF(RX_MATCH_TAINTED(rx));
if (gimme == G_ARRAY) {
I32 nparens, i, len;
nparens = rx->nparens;
if (global && !nparens)
i = 1;
else
i = 0;
SPAGAIN;
EXTEND(SP, nparens + i);
EXTEND_MORTAL(nparens + i);
for (i = !i; i <= nparens; i++) {
PUSHs(sv_newmortal());
if ((rx->startp[i] != -1) && rx->endp[i] != -1 ) {
len = rx->endp[i] - rx->startp[i];
if (rx->endp[i] < 0 || rx->startp[i] < 0 ||
len < 0 || len > strend - s)
DIE(aTHX_ "panic: pp_match start/end pointers");
s = rx->startp[i] + truebase;
sv_setpvn(*SP, s, len);
if (DO_UTF8(TARG) && is_utf8_string((U8*)s, len))
SvUTF8_on(*SP);
}
}
if (global) {
if (dynpm->op_pmflags & PMf_CONTINUE) {
MAGIC* mg = 0;
if (SvTYPE(TARG) >= SVt_PVMG && SvMAGIC(TARG))
mg = mg_find(TARG, PERL_MAGIC_regex_global);
if (!mg) {
sv_magic(TARG, (SV*)0, PERL_MAGIC_regex_global, Nullch, 0);
mg = mg_find(TARG, PERL_MAGIC_regex_global);
}
if (rx->startp[0] != -1) {
mg->mg_len = rx->endp[0];
if (rx->startp[0] == rx->endp[0])
mg->mg_flags |= MGf_MINMATCH;
else
mg->mg_flags &= ~MGf_MINMATCH;
}
}
had_zerolen = (rx->startp[0] != -1
&& rx->startp[0] == rx->endp[0]);
PUTBACK;
r_flags |= REXEC_IGNOREPOS | REXEC_NOT_FIRST;
goto play_it_again;
}
else if (!nparens)
XPUSHs(&PL_sv_yes);
LEAVE_SCOPE(oldsave);
RETURN;
}
else {
if (global) {
MAGIC* mg = 0;
if (SvTYPE(TARG) >= SVt_PVMG && SvMAGIC(TARG))
mg = mg_find(TARG, PERL_MAGIC_regex_global);
if (!mg) {
sv_magic(TARG, (SV*)0, PERL_MAGIC_regex_global, Nullch, 0);
mg = mg_find(TARG, PERL_MAGIC_regex_global);
}
if (rx->startp[0] != -1) {
mg->mg_len = rx->endp[0];
if (rx->startp[0] == rx->endp[0])
mg->mg_flags |= MGf_MINMATCH;
else
mg->mg_flags &= ~MGf_MINMATCH;
}
}
LEAVE_SCOPE(oldsave);
RETPUSHYES;
}
yup:
if (rxtainted)
RX_MATCH_TAINTED_on(rx);
TAINT_IF(RX_MATCH_TAINTED(rx));
PL_curpm = pm;
if (dynpm->op_pmflags & PMf_ONCE)
dynpm->op_pmdynflags |= PMdf_USED;
if (RX_MATCH_COPIED(rx))
Safefree(rx->subbeg);
RX_MATCH_COPIED_off(rx);
rx->subbeg = Nullch;
if (global) {
rx->subbeg = truebase;
rx->startp[0] = s - truebase;
if (RX_MATCH_UTF8(rx)) {
char *t = (char*)utf8_hop((U8*)s, rx->minlen);
rx->endp[0] = t - truebase;
}
else {
rx->endp[0] = s - truebase + rx->minlen;
}
rx->sublen = strend - truebase;
goto gotcha;
}
if (PL_sawampersand) {
I32 off;
rx->subbeg = savepvn(t, strend - t);
rx->sublen = strend - t;
RX_MATCH_COPIED_on(rx);
off = rx->startp[0] = s - t;
rx->endp[0] = off + rx->minlen;
}
else {
rx->startp[0] = s - truebase;
rx->endp[0] = s - truebase + rx->minlen;
}
rx->nparens = rx->lastparen = 0;
LEAVE_SCOPE(oldsave);
RETPUSHYES;
nope:
ret_no:
if (global && !(dynpm->op_pmflags & PMf_CONTINUE)) {
if (SvTYPE(TARG) >= SVt_PVMG && SvMAGIC(TARG)) {
MAGIC* mg = mg_find(TARG, PERL_MAGIC_regex_global);
if (mg)
mg->mg_len = -1;
}
}
LEAVE_SCOPE(oldsave);
if (gimme == G_ARRAY)
RETURN;
RETPUSHNO;
}
OP *
Perl_do_readline(pTHX)
{
dSP; dTARGETSTACKED;
register SV *sv;
STRLEN tmplen = 0;
STRLEN offset;
PerlIO *fp;
register IO *io = GvIO(PL_last_in_gv);
register I32 type = PL_op->op_type;
I32 gimme = GIMME_V;
MAGIC *mg;
if (io && (mg = SvTIED_mg((SV*)io, PERL_MAGIC_tiedscalar))) {
PUSHMARK(SP);
XPUSHs(SvTIED_obj((SV*)io, mg));
PUTBACK;
ENTER;
call_method("READLINE", gimme);
LEAVE;
SPAGAIN;
if (gimme == G_SCALAR) {
SV* result = POPs;
SvSetSV_nosteal(TARG, result);
PUSHTARG;
}
RETURN;
}
fp = Nullfp;
if (io) {
fp = IoIFP(io);
if (!fp) {
if (IoFLAGS(io) & IOf_ARGV) {
if (IoFLAGS(io) & IOf_START) {
IoLINES(io) = 0;
if (av_len(GvAVn(PL_last_in_gv)) < 0) {
IoFLAGS(io) &= ~IOf_START;
do_open(PL_last_in_gv,"-",1,FALSE,O_RDONLY,0,Nullfp);
sv_setpvn(GvSV(PL_last_in_gv), "-", 1);
SvSETMAGIC(GvSV(PL_last_in_gv));
fp = IoIFP(io);
goto have_fp;
}
}
fp = nextargv(PL_last_in_gv);
if (!fp) {
(void)do_close(PL_last_in_gv, FALSE);
}
}
else if (type == OP_GLOB)
fp = Perl_start_glob(aTHX_ POPs, io);
}
else if (type == OP_GLOB)
SP--;
else if (ckWARN(WARN_IO) && IoTYPE(io) == IoTYPE_WRONLY) {
report_evil_fh(PL_last_in_gv, io, OP_phoney_OUTPUT_ONLY);
}
}
if (!fp) {
if (ckWARN2(WARN_GLOB, WARN_CLOSED)
&& (!io || !(IoFLAGS(io) & IOf_START))) {
if (type == OP_GLOB)
Perl_warner(aTHX_ packWARN(WARN_GLOB),
"glob failed (can't start child: %s)",
Strerror(errno));
else
report_evil_fh(PL_last_in_gv, io, PL_op->op_type);
}
if (gimme == G_SCALAR) {
if (type != OP_RCATLINE) {
SV_CHECK_THINKFIRST(TARG);
(void)SvOK_off(TARG);
}
PUSHTARG;
}
RETURN;
}
have_fp:
if (gimme == G_SCALAR) {
sv = TARG;
if (SvROK(sv))
sv_unref(sv);
(void)SvUPGRADE(sv, SVt_PV);
tmplen = SvLEN(sv);
if (!tmplen)
Sv_Grow(sv, 80);
offset = 0;
if (type == OP_RCATLINE && SvOK(sv)) {
if (!SvPOK(sv)) {
STRLEN n_a;
(void)SvPV_force(sv, n_a);
}
offset = SvCUR(sv);
}
}
else {
sv = sv_2mortal(NEWSV(57, 80));
offset = 0;
}
#define MAYBE_TAINT_LINE(io, sv) \
if (!(IoFLAGS(io) & IOf_UNTAINT)) { \
TAINT; \
SvTAINTED_on(sv); \
}
#define SNARF_EOF(gimme,rs,io,sv) \
(gimme != G_SCALAR || SvCUR(sv) \
|| (IoFLAGS(io) & IOf_NOLINE) || !RsSNARF(rs))
for (;;) {
PUTBACK;
if (!sv_gets(sv, fp, offset)
&& (type == OP_GLOB || SNARF_EOF(gimme, PL_rs, io, sv)))
{
PerlIO_clearerr(fp);
if (IoFLAGS(io) & IOf_ARGV) {
fp = nextargv(PL_last_in_gv);
if (fp)
continue;
(void)do_close(PL_last_in_gv, FALSE);
}
else if (type == OP_GLOB) {
if (!do_close(PL_last_in_gv, FALSE) && ckWARN(WARN_GLOB)) {
Perl_warner(aTHX_ packWARN(WARN_GLOB),
"glob failed (child exited with status %d%s)",
(int)(STATUS_CURRENT >> 8),
(STATUS_CURRENT & 0x80) ? ", core dumped" : "");
}
}
if (gimme == G_SCALAR) {
if (type != OP_RCATLINE) {
SV_CHECK_THINKFIRST(TARG);
(void)SvOK_off(TARG);
}
SPAGAIN;
PUSHTARG;
}
MAYBE_TAINT_LINE(io, sv);
RETURN;
}
MAYBE_TAINT_LINE(io, sv);
IoLINES(io)++;
IoFLAGS(io) |= IOf_NOLINE;
SvSETMAGIC(sv);
SPAGAIN;
XPUSHs(sv);
if (type == OP_GLOB) {
char *tmps;
if (SvCUR(sv) > 0 && SvCUR(PL_rs) > 0) {
tmps = SvEND(sv) - 1;
if (*tmps == *SvPVX(PL_rs)) {
*tmps = '\0';
SvCUR(sv)--;
}
}
for (tmps = SvPVX(sv); *tmps; tmps++)
if (!isALPHA(*tmps) && !isDIGIT(*tmps) &&
strchr("$&*(){}[]'\";\\|?<>~`", *tmps))
break;
if (*tmps && PerlLIO_lstat(SvPVX(sv), &PL_statbuf) < 0) {
(void)POPs;
continue;
}
}
if (gimme == G_ARRAY) {
if (SvLEN(sv) - SvCUR(sv) > 20) {
SvLEN_set(sv, SvCUR(sv)+1);
Renew(SvPVX(sv), SvLEN(sv), char);
}
sv = sv_2mortal(NEWSV(58, 80));
continue;
}
else if (gimme == G_SCALAR && !tmplen && SvLEN(sv) - SvCUR(sv) > 80) {
if (SvCUR(sv) < 60)
SvLEN_set(sv, 80);
else
SvLEN_set(sv, SvCUR(sv)+40);
Renew(SvPVX(sv), SvLEN(sv), char);
}
RETURN;
}
}
PP(pp_enter)
{
dSP;
register PERL_CONTEXT *cx;
I32 gimme = OP_GIMME(PL_op, -1);
if (gimme == -1) {
if (cxstack_ix >= 0)
gimme = cxstack[cxstack_ix].blk_gimme;
else
gimme = G_SCALAR;
}
ENTER;
SAVETMPS;
PUSHBLOCK(cx, CXt_BLOCK, SP);
RETURN;
}
PP(pp_helem)
{
dSP;
HE* he;
SV **svp;
SV *keysv = POPs;
HV *hv = (HV*)POPs;
U32 lval = PL_op->op_flags & OPf_MOD || LVRET;
U32 defer = PL_op->op_private & OPpLVAL_DEFER;
SV *sv;
U32 hash = (SvFAKE(keysv) && SvREADONLY(keysv)) ? SvUVX(keysv) : 0;
I32 preeminent = 0;
if (SvTYPE(hv) == SVt_PVHV) {
if (PL_op->op_private & OPpLVAL_INTRO) {
MAGIC *mg;
HV *stash;
preeminent =
( !SvRMAGICAL(hv)
|| mg_find((SV*)hv, PERL_MAGIC_env)
|| ( (mg = mg_find((SV*)hv, PERL_MAGIC_tied))
&& (stash = SvSTASH(SvRV(SvTIED_obj((SV*)hv, mg))))
&& gv_fetchmethod_autoload(stash, "EXISTS", TRUE)
&& gv_fetchmethod_autoload(stash, "DELETE", TRUE)
)
) ? hv_exists_ent(hv, keysv, 0) : 1;
}
he = hv_fetch_ent(hv, keysv, lval && !defer, hash);
svp = he ? &HeVAL(he) : 0;
}
else if (SvTYPE(hv) == SVt_PVAV) {
if (PL_op->op_private & OPpLVAL_INTRO)
DIE(aTHX_ "Can't localize pseudo-hash element");
svp = avhv_fetch_ent((AV*)hv, keysv, lval && !defer, hash);
}
else {
RETPUSHUNDEF;
}
if (lval) {
if (!svp || *svp == &PL_sv_undef) {
SV* lv;
SV* key2;
if (!defer) {
STRLEN n_a;
DIE(aTHX_ PL_no_helem, SvPV(keysv, n_a));
}
lv = sv_newmortal();
sv_upgrade(lv, SVt_PVLV);
LvTYPE(lv) = 'y';
sv_magic(lv, key2 = newSVsv(keysv), PERL_MAGIC_defelem, Nullch, 0);
SvREFCNT_dec(key2);
LvTARG(lv) = SvREFCNT_inc(hv);
LvTARGLEN(lv) = 1;
PUSHs(lv);
RETURN;
}
if (PL_op->op_private & OPpLVAL_INTRO) {
if (HvNAME(hv) && isGV(*svp))
save_gp((GV*)*svp, !(PL_op->op_flags & OPf_SPECIAL));
else {
if (!preeminent) {
STRLEN keylen;
char *key = SvPV(keysv, keylen);
SAVEDELETE(hv, savepvn(key,keylen), keylen);
} else
save_helem(hv, keysv, svp);
}
}
else if (PL_op->op_private & OPpDEREF)
vivify_ref(*svp, PL_op->op_private & OPpDEREF);
}
sv = (svp ? *svp : &PL_sv_undef);
if (!lval && SvGMAGICAL(sv))
sv = sv_mortalcopy(sv);
PUSHs(sv);
RETURN;
}
PP(pp_leave)
{
dSP;
register PERL_CONTEXT *cx;
register SV **mark;
SV **newsp;
PMOP *newpm;
I32 gimme;
if (PL_op->op_flags & OPf_SPECIAL) {
cx = &cxstack[cxstack_ix];
cx->blk_oldpm = PL_curpm;
}
POPBLOCK(cx,newpm);
gimme = OP_GIMME(PL_op, -1);
if (gimme == -1) {
if (cxstack_ix >= 0)
gimme = cxstack[cxstack_ix].blk_gimme;
else
gimme = G_SCALAR;
}
TAINT_NOT;
if (gimme == G_VOID)
SP = newsp;
else if (gimme == G_SCALAR) {
MARK = newsp + 1;
if (MARK <= SP) {
if (SvFLAGS(TOPs) & (SVs_PADTMP|SVs_TEMP))
*MARK = TOPs;
else
*MARK = sv_mortalcopy(TOPs);
} else {
MEXTEND(mark,0);
*MARK = &PL_sv_undef;
}
SP = MARK;
}
else if (gimme == G_ARRAY) {
for (mark = newsp + 1; mark <= SP; mark++) {
if (!(SvFLAGS(*mark) & (SVs_PADTMP|SVs_TEMP))) {
*mark = sv_mortalcopy(*mark);
TAINT_NOT;
}
}
}
PL_curpm = newpm;
LEAVE;
RETURN;
}
PP(pp_iter)
{
dSP;
register PERL_CONTEXT *cx;
SV* sv;
AV* av;
SV **itersvp;
EXTEND(SP, 1);
cx = &cxstack[cxstack_ix];
if (CxTYPE(cx) != CXt_LOOP)
DIE(aTHX_ "panic: pp_iter");
itersvp = CxITERVAR(cx);
av = cx->blk_loop.iterary;
if (SvTYPE(av) != SVt_PVAV) {
if (cx->blk_loop.iterlval) {
register SV* cur = cx->blk_loop.iterlval;
STRLEN maxlen;
char *max = SvPV((SV*)av, maxlen);
if (!SvNIOK(cur) && SvCUR(cur) <= maxlen) {
#ifndef USE_5005THREADS
if (SvREFCNT(*itersvp) == 1 && !SvMAGICAL(*itersvp)) {
sv_setsv(*itersvp, cur);
}
else
#endif
{
SvREFCNT_dec(*itersvp);
*itersvp = newSVsv(cur);
}
if (strEQ(SvPVX(cur), max))
sv_setiv(cur, 0);
else
sv_inc(cur);
RETPUSHYES;
}
RETPUSHNO;
}
if (cx->blk_loop.iterix > cx->blk_loop.itermax)
RETPUSHNO;
#ifndef USE_5005THREADS
if (SvREFCNT(*itersvp) == 1 && !SvMAGICAL(*itersvp)) {
sv_setiv(*itersvp, cx->blk_loop.iterix++);
}
else
#endif
{
SvREFCNT_dec(*itersvp);
*itersvp = newSViv(cx->blk_loop.iterix++);
}
RETPUSHYES;
}
if (cx->blk_loop.iterix >= (av == PL_curstack ? cx->blk_oldsp : AvFILL(av)))
RETPUSHNO;
SvREFCNT_dec(*itersvp);
if (SvMAGICAL(av) || AvREIFY(av)) {
SV **svp = av_fetch(av, ++cx->blk_loop.iterix, FALSE);
if (svp)
sv = *svp;
else
sv = Nullsv;
}
else {
sv = AvARRAY(av)[++cx->blk_loop.iterix];
}
if (sv && SvREFCNT(sv) == 0) {
*itersvp = Nullsv;
Perl_croak(aTHX_
"Use of freed value in iteration (perhaps you modified the iterated array within the loop?)");
}
if (sv)
SvTEMP_off(sv);
else
sv = &PL_sv_undef;
if (av != PL_curstack && sv == &PL_sv_undef) {
SV *lv = cx->blk_loop.iterlval;
if (lv && SvREFCNT(lv) > 1) {
SvREFCNT_dec(lv);
lv = Nullsv;
}
if (lv)
SvREFCNT_dec(LvTARG(lv));
else {
lv = cx->blk_loop.iterlval = NEWSV(26, 0);
sv_upgrade(lv, SVt_PVLV);
LvTYPE(lv) = 'y';
sv_magic(lv, Nullsv, PERL_MAGIC_defelem, Nullch, 0);
}
LvTARG(lv) = SvREFCNT_inc(av);
LvTARGOFF(lv) = cx->blk_loop.iterix;
LvTARGLEN(lv) = (STRLEN)UV_MAX;
sv = (SV*)lv;
}
*itersvp = SvREFCNT_inc(sv);
RETPUSHYES;
}
PP(pp_subst)
{
dSP; dTARG;
register PMOP *pm = cPMOP;
PMOP *rpm = pm;
register SV *dstr;
register char *s;
char *strend;
register char *m;
char *c;
register char *d;
STRLEN clen;
I32 iters = 0;
I32 maxiters;
register I32 i;
bool once;
bool rxtainted;
char *orig;
I32 r_flags;
register REGEXP *rx = PM_GETRE(pm);
STRLEN len;
int force_on_match = 0;
I32 oldsave = PL_savestack_ix;
STRLEN slen;
bool doutf8 = FALSE;
SV *nsv = Nullsv;
dstr = (pm->op_pmflags & PMf_CONST) ? POPs : Nullsv;
if (PL_op->op_flags & OPf_STACKED)
TARG = POPs;
else {
TARG = DEFSV;
EXTEND(SP,1);
}
if (SvFAKE(TARG) && SvREADONLY(TARG))
sv_force_normal(TARG);
if (SvREADONLY(TARG)
|| (SvTYPE(TARG) > SVt_PVLV
&& !(SvTYPE(TARG) == SVt_PVGV && SvFAKE(TARG))))
DIE(aTHX_ PL_no_modify);
PUTBACK;
s = SvPV(TARG, len);
if (!SvPOKp(TARG) || SvTYPE(TARG) == SVt_PVGV)
force_on_match = 1;
rxtainted = ((pm->op_pmdynflags & PMdf_TAINTED) ||
(PL_tainted && (pm->op_pmflags & PMf_RETAINT)));
if (PL_tainted)
rxtainted |= 2;
TAINT_NOT;
RX_MATCH_UTF8_set(rx, DO_UTF8(TARG));
force_it:
if (!pm || !s)
DIE(aTHX_ "panic: pp_subst");
strend = s + len;
slen = RX_MATCH_UTF8(rx) ? utf8_length((U8*)s, (U8*)strend) : len;
maxiters = 2 * slen + 10;
if (!rx->prelen && PL_curpm) {
pm = PL_curpm;
rx = PM_GETRE(pm);
}
r_flags = (rx->nparens || SvTEMP(TARG) || PL_sawampersand)
? REXEC_COPY_STR : 0;
if (SvSCREAM(TARG))
r_flags |= REXEC_SCREAM;
if (pm->op_pmflags & (PMf_MULTILINE|PMf_SINGLELINE)) {
SAVEINT(PL_multiline);
PL_multiline = pm->op_pmflags & PMf_MULTILINE;
}
orig = m = s;
if (rx->reganch & RE_USE_INTUIT) {
PL_bostr = orig;
s = CALLREG_INTUIT_START(aTHX_ rx, TARG, s, strend, r_flags, NULL);
if (!s)
goto nope;
}
once = !(rpm->op_pmflags & PMf_GLOBAL);
if (dstr) {
if (DO_UTF8(TARG) && !doutf8) {
nsv = sv_newmortal();
SvSetSV(nsv, dstr);
if (PL_encoding)
sv_recode_to_utf8(nsv, PL_encoding);
else
sv_utf8_upgrade(nsv);
c = SvPV(nsv, clen);
doutf8 = TRUE;
}
else {
c = SvPV(dstr, clen);
doutf8 = DO_UTF8(dstr);
}
}
else {
c = Nullch;
doutf8 = FALSE;
}
if (c && (I32)clen <= rx->minlen && (once || !(r_flags & REXEC_COPY_STR))
&& !(rx->reganch & ROPT_LOOKBEHIND_SEEN)
&& (!doutf8 || SvUTF8(TARG))) {
if (!CALLREGEXEC(aTHX_ rx, s, strend, orig, 0, TARG, NULL,
r_flags | REXEC_CHECKED))
{
SPAGAIN;
PUSHs(&PL_sv_no);
LEAVE_SCOPE(oldsave);
RETURN;
}
if (force_on_match) {
force_on_match = 0;
s = SvPV_force(TARG, len);
goto force_it;
}
d = s;
PL_curpm = pm;
SvSCREAM_off(TARG);
if (once) {
rxtainted |= RX_MATCH_TAINTED(rx);
m = orig + rx->startp[0];
d = orig + rx->endp[0];
s = orig;
if (m - s > strend - d) {
if (clen) {
Copy(c, m, clen, char);
m += clen;
}
i = strend - d;
if (i > 0) {
Move(d, m, i, char);
m += i;
}
*m = '\0';
SvCUR_set(TARG, m - s);
}
else if ((i = m - s)) {
d -= clen;
m = d;
sv_chop(TARG, d-i);
s += i;
while (i--)
*--d = *--s;
if (clen)
Copy(c, m, clen, char);
}
else if (clen) {
d -= clen;
sv_chop(TARG, d);
Copy(c, d, clen, char);
}
else {
sv_chop(TARG, d);
}
TAINT_IF(rxtainted & 1);
SPAGAIN;
PUSHs(&PL_sv_yes);
}
else {
do {
if (iters++ > maxiters)
DIE(aTHX_ "Substitution loop");
rxtainted |= RX_MATCH_TAINTED(rx);
m = rx->startp[0] + orig;
if ((i = m - s)) {
if (s != d)
Move(s, d, i, char);
d += i;
}
if (clen) {
Copy(c, d, clen, char);
d += clen;
}
s = rx->endp[0] + orig;
} while (CALLREGEXEC(aTHX_ rx, s, strend, orig, s == m,
TARG, NULL,
REXEC_NOT_FIRST|REXEC_IGNOREPOS));
if (s != d) {
i = strend - s;
SvCUR_set(TARG, d - SvPVX(TARG) + i);
Move(s, d, i+1, char);
}
TAINT_IF(rxtainted & 1);
SPAGAIN;
PUSHs(sv_2mortal(newSViv((I32)iters)));
}
(void)SvPOK_only_UTF8(TARG);
TAINT_IF(rxtainted);
if (SvSMAGICAL(TARG)) {
PUTBACK;
mg_set(TARG);
SPAGAIN;
}
SvTAINT(TARG);
if (doutf8)
SvUTF8_on(TARG);
LEAVE_SCOPE(oldsave);
RETURN;
}
if (CALLREGEXEC(aTHX_ rx, s, strend, orig, 0, TARG, NULL,
r_flags | REXEC_CHECKED))
{
if (force_on_match) {
force_on_match = 0;
s = SvPV_force(TARG, len);
goto force_it;
}
rxtainted |= RX_MATCH_TAINTED(rx);
dstr = NEWSV(25, len);
sv_setpvn(dstr, m, s-m);
if (DO_UTF8(TARG))
SvUTF8_on(dstr);
PL_curpm = pm;
if (!c) {
register PERL_CONTEXT *cx;
SPAGAIN;
ReREFCNT_inc(rx);
PUSHSUBST(cx);
RETURNOP(cPMOP->op_pmreplroot);
}
r_flags |= REXEC_IGNOREPOS | REXEC_NOT_FIRST;
do {
if (iters++ > maxiters)
DIE(aTHX_ "Substitution loop");
rxtainted |= RX_MATCH_TAINTED(rx);
if (RX_MATCH_COPIED(rx) && rx->subbeg != orig) {
m = s;
s = orig;
orig = rx->subbeg;
s = orig + (m - s);
strend = s + (strend - m);
}
m = rx->startp[0] + orig;
if (doutf8 && !SvUTF8(dstr))
sv_catpvn_utf8_upgrade(dstr, s, m - s, nsv);
else
sv_catpvn(dstr, s, m-s);
s = rx->endp[0] + orig;
if (clen)
sv_catpvn(dstr, c, clen);
if (once)
break;
} while (CALLREGEXEC(aTHX_ rx, s, strend, orig, s == m,
TARG, NULL, r_flags));
if (doutf8 && !DO_UTF8(TARG))
sv_catpvn_utf8_upgrade(dstr, s, strend - s, nsv);
else
sv_catpvn(dstr, s, strend - s);
(void)SvOOK_off(TARG);
if (SvLEN(TARG))
Safefree(SvPVX(TARG));
SvPVX(TARG) = SvPVX(dstr);
SvCUR_set(TARG, SvCUR(dstr));
SvLEN_set(TARG, SvLEN(dstr));
doutf8 |= DO_UTF8(dstr);
SvPVX(dstr) = 0;
sv_free(dstr);
TAINT_IF(rxtainted & 1);
SPAGAIN;
PUSHs(sv_2mortal(newSViv((I32)iters)));
(void)SvPOK_only(TARG);
if (doutf8)
SvUTF8_on(TARG);
TAINT_IF(rxtainted);
SvSETMAGIC(TARG);
SvTAINT(TARG);
LEAVE_SCOPE(oldsave);
RETURN;
}
goto ret_no;
nope:
ret_no:
SPAGAIN;
PUSHs(&PL_sv_no);
LEAVE_SCOPE(oldsave);
RETURN;
}
PP(pp_grepwhile)
{
dSP;
if (SvTRUEx(POPs))
PL_stack_base[PL_markstack_ptr[-1]++] = PL_stack_base[*PL_markstack_ptr];
++*PL_markstack_ptr;
LEAVE;
if (PL_stack_base + *PL_markstack_ptr > SP) {
I32 items;
I32 gimme = GIMME_V;
LEAVE;
(void)POPMARK;
items = --*PL_markstack_ptr - PL_markstack_ptr[-1];
(void)POPMARK;
SP = PL_stack_base + POPMARK;
if (gimme == G_SCALAR) {
dTARGET;
XPUSHi(items);
}
else if (gimme == G_ARRAY)
SP += items;
RETURN;
}
else {
SV *src;
ENTER;
SAVEVPTR(PL_curpm);
src = PL_stack_base[*PL_markstack_ptr];
SvTEMP_off(src);
DEFSV = src;
RETURNOP(cLOGOP->op_other);
}
}
PP(pp_leavesub)
{
dSP;
SV **mark;
SV **newsp;
PMOP *newpm;
I32 gimme;
register PERL_CONTEXT *cx;
SV *sv;
POPBLOCK(cx,newpm);
TAINT_NOT;
if (gimme == G_SCALAR) {
MARK = newsp + 1;
if (MARK <= SP) {
if (cx->blk_sub.cv && CvDEPTH(cx->blk_sub.cv) > 1) {
if (SvTEMP(TOPs)) {
*MARK = SvREFCNT_inc(TOPs);
FREETMPS;
sv_2mortal(*MARK);
}
else {
sv = SvREFCNT_inc(TOPs);
FREETMPS;
*MARK = sv_mortalcopy(sv);
SvREFCNT_dec(sv);
}
}
else
*MARK = SvTEMP(TOPs) ? TOPs : sv_mortalcopy(TOPs);
}
else {
MEXTEND(MARK, 0);
*MARK = &PL_sv_undef;
}
SP = MARK;
}
else if (gimme == G_ARRAY) {
for (MARK = newsp + 1; MARK <= SP; MARK++) {
if (!SvTEMP(*MARK)) {
*MARK = sv_mortalcopy(*MARK);
TAINT_NOT;
}
}
}
PUTBACK;
LEAVE;
POPSUB(cx,sv);
PL_curpm = newpm;
LEAVESUB(sv);
return pop_return();
}
PP(pp_leavesublv)
{
dSP;
SV **mark;
SV **newsp;
PMOP *newpm;
I32 gimme;
register PERL_CONTEXT *cx;
SV *sv;
POPBLOCK(cx,newpm);
TAINT_NOT;
if (cx->blk_sub.lval & OPpENTERSUB_INARGS) {
if (gimme == G_SCALAR)
goto temporise;
if (gimme == G_ARRAY) {
if (!CvLVALUE(cx->blk_sub.cv))
goto temporise_array;
EXTEND_MORTAL(SP - newsp);
for (mark = newsp + 1; mark <= SP; mark++) {
if (SvTEMP(*mark))
;
else if (SvFLAGS(*mark) & (SVs_PADTMP | SVf_READONLY))
*mark = sv_mortalcopy(*mark);
else {
PL_tmps_stack[++PL_tmps_ix] = *mark;
(void)SvREFCNT_inc(*mark);
}
}
}
}
else if (cx->blk_sub.lval) {
if (!CvLVALUE(cx->blk_sub.cv)) {
LEAVE;
POPSUB(cx,sv);
PL_curpm = newpm;
LEAVESUB(sv);
DIE(aTHX_ "Can't modify non-lvalue subroutine call");
}
if (gimme == G_SCALAR) {
MARK = newsp + 1;
EXTEND_MORTAL(1);
if (MARK == SP) {
if (SvFLAGS(TOPs) & (SVs_TEMP | SVs_PADTMP | SVf_READONLY)) {
LEAVE;
POPSUB(cx,sv);
PL_curpm = newpm;
LEAVESUB(sv);
DIE(aTHX_ "Can't return %s from lvalue subroutine",
SvREADONLY(TOPs) ? (TOPs == &PL_sv_undef) ? "undef"
: "a readonly value" : "a temporary");
}
else {
PL_tmps_stack[++PL_tmps_ix] = *mark;
(void)SvREFCNT_inc(*mark);
}
}
else {
LEAVE;
POPSUB(cx,sv);
PL_curpm = newpm;
LEAVESUB(sv);
DIE(aTHX_ "%s returned from lvalue subroutine in scalar context",
(MARK > SP ? "Empty array" : "Array"));
}
SP = MARK;
}
else if (gimme == G_ARRAY) {
EXTEND_MORTAL(SP - newsp);
for (mark = newsp + 1; mark <= SP; mark++) {
if (*mark != &PL_sv_undef
&& SvFLAGS(*mark) & (SVs_TEMP | SVs_PADTMP | SVf_READONLY)) {
PUTBACK;
LEAVE;
POPSUB(cx,sv);
PL_curpm = newpm;
LEAVESUB(sv);
DIE(aTHX_ "Can't return a %s from lvalue subroutine",
SvREADONLY(TOPs) ? "readonly value" : "temporary");
}
else {
PL_tmps_stack[++PL_tmps_ix] = *mark;
(void)SvREFCNT_inc(*mark);
}
}
}
}
else {
if (gimme == G_SCALAR) {
temporise:
MARK = newsp + 1;
if (MARK <= SP) {
if (cx->blk_sub.cv && CvDEPTH(cx->blk_sub.cv) > 1) {
if (SvTEMP(TOPs)) {
*MARK = SvREFCNT_inc(TOPs);
FREETMPS;
sv_2mortal(*MARK);
}
else {
sv = SvREFCNT_inc(TOPs);
FREETMPS;
*MARK = sv_mortalcopy(sv);
SvREFCNT_dec(sv);
}
}
else
*MARK = SvTEMP(TOPs) ? TOPs : sv_mortalcopy(TOPs);
}
else {
MEXTEND(MARK, 0);
*MARK = &PL_sv_undef;
}
SP = MARK;
}
else if (gimme == G_ARRAY) {
temporise_array:
for (MARK = newsp + 1; MARK <= SP; MARK++) {
if (!SvTEMP(*MARK)) {
*MARK = sv_mortalcopy(*MARK);
TAINT_NOT;
}
}
}
}
PUTBACK;
LEAVE;
POPSUB(cx,sv);
PL_curpm = newpm;
LEAVESUB(sv);
return pop_return();
}
STATIC CV *
S_get_db_sub(pTHX_ SV **svp, CV *cv)
{
SV *dbsv = GvSV(PL_DBsub);
if (!PERLDB_SUB_NN) {
GV *gv = CvGV(cv);
save_item(dbsv);
if ( (CvFLAGS(cv) & (CVf_ANON | CVf_CLONED))
|| strEQ(GvNAME(gv), "END")
|| ((GvCV(gv) != cv) &&
!( (SvTYPE(*svp) == SVt_PVGV) && (GvCV((GV*)*svp) == cv)
&& (gv = (GV*)*svp) ))) {
SV *tmp = newRV((SV*)cv);
sv_setsv(dbsv, tmp);
SvREFCNT_dec(tmp);
}
else {
gv_efullname3(dbsv, gv, Nullch);
}
}
else {
(void)SvUPGRADE(dbsv, SVt_PVIV);
(void)SvIOK_on(dbsv);
SAVEIV(SvIVX(dbsv));
SvIVX(dbsv) = PTR2IV(cv);
}
if (CvXSUB(cv))
PL_curcopdb = PL_curcop;
cv = GvCV(PL_DBsub);
return cv;
}
PP(pp_entersub)
{
dSP; dPOPss;
GV *gv;
HV *stash;
register CV *cv;
register PERL_CONTEXT *cx;
I32 gimme;
bool hasargs = (PL_op->op_flags & OPf_STACKED) != 0;
if (!sv)
DIE(aTHX_ "Not a CODE reference");
switch (SvTYPE(sv)) {
default:
if (!SvROK(sv)) {
char *sym;
STRLEN n_a;
if (sv == &PL_sv_yes) {
if (hasargs)
SP = PL_stack_base + POPMARK;
RETURN;
}
if (SvGMAGICAL(sv)) {
mg_get(sv);
if (SvROK(sv))
goto got_rv;
sym = SvPOKp(sv) ? SvPVX(sv) : Nullch;
}
else
sym = SvPV(sv, n_a);
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);
break;
}
got_rv:
{
SV **sp = &sv;
tryAMAGICunDEREF(to_cv);
}
cv = (CV*)SvRV(sv);
if (SvTYPE(cv) == SVt_PVCV)
break;
case SVt_PVHV:
case SVt_PVAV:
DIE(aTHX_ "Not a CODE reference");
case SVt_PVCV:
cv = (CV*)sv;
break;
case SVt_PVGV:
if (!(cv = GvCVu((GV*)sv)))
cv = sv_2cv(sv, &stash, &gv, FALSE);
if (!cv) {
ENTER;
SAVETMPS;
goto try_autoload;
}
break;
}
ENTER;
SAVETMPS;
retry:
if (!CvROOT(cv) && !CvXSUB(cv)) {
GV* autogv;
SV* sub_name;
if (CvANON(cv) || !(gv = CvGV(cv)))
DIE(aTHX_ "Undefined subroutine called");
if (cv != GvCV(gv)) {
cv = GvCV(gv);
}
else {
try_autoload:
if ((autogv = gv_autoload4(GvSTASH(gv), GvNAME(gv), GvNAMELEN(gv),
FALSE)))
{
cv = GvCV(autogv);
}
else {
sub_name = sv_newmortal();
gv_efullname3(sub_name, gv, Nullch);
DIE(aTHX_ "Undefined subroutine &%"SVf" called", sub_name);
}
}
if (!cv)
DIE(aTHX_ "Not a CODE reference");
goto retry;
}
gimme = GIMME_V;
if ((PL_op->op_private & OPpENTERSUB_DB) && GvCV(PL_DBsub) && !CvNODEBUG(cv)) {
cv = get_db_sub(&sv, cv);
if (!cv)
DIE(aTHX_ "No DBsub routine");
}
#ifdef USE_5005THREADS
MUTEX_LOCK(CvMUTEXP(cv));
if (CvFLAGS(cv) & CVf_LOCKED) {
MAGIC *mg;
if (CvFLAGS(cv) & CVf_METHOD) {
if (SP > PL_stack_base + TOPMARK)
sv = *(PL_stack_base + TOPMARK + 1);
else {
AV *av = (AV*)PAD_SVl(0);
if (hasargs || !av || AvFILLp(av) < 0
|| !(sv = AvARRAY(av)[0]))
{
MUTEX_UNLOCK(CvMUTEXP(cv));
DIE(aTHX_ "no argument for locked method call");
}
}
if (SvROK(sv))
sv = SvRV(sv);
else {
STRLEN len;
char *stashname = SvPV(sv, len);
sv = (SV*)gv_stashpvn(stashname, len, TRUE);
}
}
else {
sv = (SV*)cv;
}
MUTEX_UNLOCK(CvMUTEXP(cv));
mg = condpair_magic(sv);
MUTEX_LOCK(MgMUTEXP(mg));
if (MgOWNER(mg) == thr)
MUTEX_UNLOCK(MgMUTEXP(mg));
else {
while (MgOWNER(mg))
COND_WAIT(MgOWNERCONDP(mg), MgMUTEXP(mg));
MgOWNER(mg) = thr;
DEBUG_S(PerlIO_printf(Perl_debug_log, "%p: pp_entersub lock %p\n",
thr, sv));
MUTEX_UNLOCK(MgMUTEXP(mg));
SAVEDESTRUCTOR_X(Perl_unlock_condpair, sv);
}
MUTEX_LOCK(CvMUTEXP(cv));
}
if (CvOWNER(cv) == thr || CvXSUB(cv))
MUTEX_UNLOCK(CvMUTEXP(cv));
else {
SV **svp;
if ((svp = hv_fetch(thr->cvcache, (char *)cv, sizeof(cv), FALSE)))
{
MUTEX_UNLOCK(CvMUTEXP(cv));
cv = *(CV**)svp;
DEBUG_S(PerlIO_printf(Perl_debug_log,
"entersub: %p already has clone %p:%s\n",
thr, cv, SvPEEK((SV*)cv)));
CvOWNER(cv) = thr;
SvREFCNT_inc(cv);
if (CvDEPTH(cv) == 0)
SAVEDESTRUCTOR_X(unset_cvowner, (void*) cv);
}
else {
if (!CvOWNER(cv)) {
CvOWNER(cv) = thr;
SvREFCNT_inc(cv);
MUTEX_UNLOCK(CvMUTEXP(cv));
DEBUG_S(PerlIO_printf(Perl_debug_log,
"entersub: %p grabbing %p:%s in stash %s\n",
thr, cv, SvPEEK((SV*)cv), CvSTASH(cv) ?
HvNAME(CvSTASH(cv)) : "(none)"));
}
else {
CV *clonecv;
SvREFCNT_inc(cv);
MUTEX_UNLOCK(CvMUTEXP(cv));
DEBUG_S((PerlIO_printf(Perl_debug_log,
"entersub: %p cloning %p:%s\n",
thr, cv, SvPEEK((SV*)cv))));
clonecv = cv_clone(cv);
SvREFCNT_dec(cv);
hv_store(thr->cvcache, (char*)cv, sizeof(cv), (SV*)clonecv,0);
CvOWNER(clonecv) = thr;
cv = clonecv;
SvREFCNT_inc(cv);
}
DEBUG_S(if (CvDEPTH(cv) != 0)
PerlIO_printf(Perl_debug_log, "depth %ld != 0\n",
CvDEPTH(cv)));
SAVEDESTRUCTOR_X(unset_cvowner, (void*) cv);
}
}
#endif
if (CvXSUB(cv)) {
#ifdef PERL_XSUB_OLDSTYLE
if (CvOLDSTYLE(cv)) {
I32 (*fp3)(int,int,int);
dMARK;
register I32 items = SP - MARK;
while (SP > mark) {
SP[1] = SP[0];
SP--;
}
PL_stack_sp = mark + 1;
fp3 = (I32(*)(int,int,int))CvXSUB(cv);
items = (*fp3)(CvXSUBANY(cv).any_i32,
MARK - PL_stack_base + 1,
items);
PL_stack_sp = PL_stack_base + items;
}
else
#endif
{
I32 markix = TOPMARK;
PUTBACK;
if (!hasargs) {
AV* av;
I32 items;
#ifdef USE_5005THREADS
av = (AV*)PAD_SVl(0);
#else
av = GvAV(PL_defgv);
#endif
items = AvFILLp(av) + 1;
if (items) {
EXTEND(SP, items);
Copy(AvARRAY(av), SP + 1, items, SV*);
SP += items;
PUTBACK ;
}
}
if (PL_curcopdb) {
SAVEVPTR(PL_curcop);
PL_curcop = PL_curcopdb;
PL_curcopdb = NULL;
}
(void)(*CvXSUB(cv))(aTHX_ cv);
if (gimme == G_SCALAR && ++markix != PL_stack_sp - PL_stack_base ) {
if (markix > PL_stack_sp - PL_stack_base)
*(PL_stack_base + markix) = &PL_sv_undef;
else
*(PL_stack_base + markix) = *PL_stack_sp;
PL_stack_sp = PL_stack_base + markix;
}
}
LEAVE;
return NORMAL;
}
else {
dMARK;
register I32 items = SP - MARK;
AV* padlist = CvPADLIST(cv);
push_return(PL_op->op_next);
PUSHBLOCK(cx, CXt_SUB, MARK);
PUSHSUB(cx);
CvDEPTH(cv)++;
if (CvDEPTH(cv) < 2)
(void)SvREFCNT_inc(cv);
else {
PERL_STACK_OVERFLOW_CHECK();
pad_push(padlist, CvDEPTH(cv), 1);
}
#ifdef USE_5005THREADS
if (!hasargs) {
AV* av = (AV*)PAD_SVl(0);
items = AvFILLp(av) + 1;
if (items) {
EXTEND(SP, items);
Copy(AvARRAY(av), SP + 1, items, SV*);
SP += items;
PUTBACK ;
}
}
#endif
PAD_SET_CUR(padlist, CvDEPTH(cv));
#ifndef USE_5005THREADS
if (hasargs)
#endif
{
AV* av;
SV** ary;
#if 0
DEBUG_S(PerlIO_printf(Perl_debug_log,
"%p entersub preparing @_\n", thr));
#endif
av = (AV*)PAD_SVl(0);
if (AvREAL(av)) {
av_clear(av);
AvREAL_off(av);
AvREIFY_on(av);
}
#ifndef USE_5005THREADS
cx->blk_sub.savearray = GvAV(PL_defgv);
GvAV(PL_defgv) = (AV*)SvREFCNT_inc(av);
#endif
CX_CURPAD_SAVE(cx->blk_sub);
cx->blk_sub.argarray = av;
++MARK;
if (items > AvMAX(av) + 1) {
ary = AvALLOC(av);
if (AvARRAY(av) != ary) {
AvMAX(av) += AvARRAY(av) - AvALLOC(av);
SvPVX(av) = (char*)ary;
}
if (items > AvMAX(av) + 1) {
AvMAX(av) = items - 1;
Renew(ary,items,SV*);
AvALLOC(av) = ary;
SvPVX(av) = (char*)ary;
}
}
Copy(MARK,AvARRAY(av),items,SV*);
AvFILLp(av) = items - 1;
while (items--) {
if (*MARK)
SvTEMP_off(*MARK);
MARK++;
}
}
if (CvDEPTH(cv) == 100 && ckWARN(WARN_RECURSION)
&& !(PERLDB_SUB && cv == GvCV(PL_DBsub)))
sub_crush_depth(cv);
#if 0
DEBUG_S(PerlIO_printf(Perl_debug_log,
"%p entersub returning %p\n", thr, CvSTART(cv)));
#endif
RETURNOP(CvSTART(cv));
}
}
void
Perl_sub_crush_depth(pTHX_ CV *cv)
{
if (CvANON(cv))
Perl_warner(aTHX_ packWARN(WARN_RECURSION), "Deep recursion on anonymous subroutine");
else {
SV* tmpstr = sv_newmortal();
gv_efullname3(tmpstr, CvGV(cv), Nullch);
Perl_warner(aTHX_ packWARN(WARN_RECURSION), "Deep recursion on subroutine \"%"SVf"\"",
tmpstr);
}
}
PP(pp_aelem)
{
dSP;
SV** svp;
SV* elemsv = POPs;
IV elem = SvIV(elemsv);
AV* av = (AV*)POPs;
U32 lval = PL_op->op_flags & OPf_MOD || LVRET;
U32 defer = (PL_op->op_private & OPpLVAL_DEFER) && (elem > AvFILL(av));
SV *sv;
if (SvROK(elemsv) && !SvGAMAGIC(elemsv) && ckWARN(WARN_MISC))
Perl_warner(aTHX_ packWARN(WARN_MISC), "Use of reference \"%"SVf"\" as array index", elemsv);
if (elem > 0)
elem -= PL_curcop->cop_arybase;
if (SvTYPE(av) != SVt_PVAV)
RETPUSHUNDEF;
svp = av_fetch(av, elem, lval && !defer);
if (lval) {
if (!svp || *svp == &PL_sv_undef) {
SV* lv;
if (!defer)
DIE(aTHX_ PL_no_aelem, elem);
lv = sv_newmortal();
sv_upgrade(lv, SVt_PVLV);
LvTYPE(lv) = 'y';
sv_magic(lv, Nullsv, PERL_MAGIC_defelem, Nullch, 0);
LvTARG(lv) = SvREFCNT_inc(av);
LvTARGOFF(lv) = elem;
LvTARGLEN(lv) = 1;
PUSHs(lv);
RETURN;
}
if (PL_op->op_private & OPpLVAL_INTRO)
save_aelem(av, elem, svp);
else if (PL_op->op_private & OPpDEREF)
vivify_ref(*svp, PL_op->op_private & OPpDEREF);
}
sv = (svp ? *svp : &PL_sv_undef);
if (!lval && SvGMAGICAL(sv))
sv = sv_mortalcopy(sv);
PUSHs(sv);
RETURN;
}
void
Perl_vivify_ref(pTHX_ SV *sv, U32 to_what)
{
if (SvGMAGICAL(sv))
mg_get(sv);
if (!SvOK(sv)) {
if (SvREADONLY(sv))
Perl_croak(aTHX_ PL_no_modify);
if (SvTYPE(sv) < SVt_RV)
sv_upgrade(sv, SVt_RV);
else if (SvTYPE(sv) >= SVt_PV) {
(void)SvOOK_off(sv);
Safefree(SvPVX(sv));
SvLEN(sv) = SvCUR(sv) = 0;
}
switch (to_what) {
case OPpDEREF_SV:
SvRV(sv) = NEWSV(355,0);
break;
case OPpDEREF_AV:
SvRV(sv) = (SV*)newAV();
break;
case OPpDEREF_HV:
SvRV(sv) = (SV*)newHV();
break;
}
SvROK_on(sv);
SvSETMAGIC(sv);
}
}
PP(pp_method)
{
dSP;
SV* sv = TOPs;
if (SvROK(sv)) {
SV* rsv = SvRV(sv);
if (SvTYPE(rsv) == SVt_PVCV) {
SETs(rsv);
RETURN;
}
}
SETs(method_common(sv, Null(U32*)));
RETURN;
}
PP(pp_method_named)
{
dSP;
SV* sv = cSVOP_sv;
U32 hash = SvUVX(sv);
XPUSHs(method_common(sv, &hash));
RETURN;
}
STATIC SV *
S_method_common(pTHX_ SV* meth, U32* hashp)
{
SV* sv;
SV* ob;
GV* gv;
HV* stash;
char* name;
STRLEN namelen;
char* packname = 0;
SV *packsv = Nullsv;
STRLEN packlen;
name = SvPV(meth, namelen);
sv = *(PL_stack_base + TOPMARK + 1);
if (!sv)
Perl_croak(aTHX_ "Can't call method \"%s\" on an undefined value", name);
if (SvGMAGICAL(sv))
mg_get(sv);
if (SvROK(sv))
ob = (SV*)SvRV(sv);
else {
GV* iogv;
packname = Nullch;
if(SvOK(sv) && (packname = SvPV(sv, packlen))) {
HE* he;
he = hv_fetch_ent(PL_stashcache, sv, 0, 0);
if (he) {
stash = INT2PTR(HV*,SvIV(HeVAL(he)));
goto fetch;
}
}
if (!SvOK(sv) ||
!(packname) ||
!(iogv = gv_fetchpv(packname, FALSE, SVt_PVIO)) ||
!(ob=(SV*)GvIO(iogv)))
{
if (!packname ||
((UTF8_IS_START(*packname) && DO_UTF8(sv))
? !isIDFIRST_utf8((U8*)packname)
: !isIDFIRST(*packname)
))
{
Perl_croak(aTHX_ "Can't call method \"%s\" %s", name,
SvOK(sv) ? "without a package or object reference"
: "on an undefined value");
}
stash = gv_stashpvn(packname, packlen, FALSE);
if (!stash)
packsv = sv;
else {
SV* ref = newSViv(PTR2IV(stash));
hv_store(PL_stashcache, packname, packlen, ref, 0);
}
goto fetch;
}
*(PL_stack_base + TOPMARK + 1) = sv_2mortal(newRV((SV*)iogv));
}
if (!ob || !(SvOBJECT(ob)
|| (SvTYPE(ob) == SVt_PVGV && (ob = (SV*)GvIO((GV*)ob))
&& SvOBJECT(ob))))
{
Perl_croak(aTHX_ "Can't call method \"%s\" on unblessed reference",
name);
}
stash = SvSTASH(ob);
fetch:
if (hashp) {
HE* he = hv_fetch_ent(stash, meth, 0, *hashp);
if (he) {
gv = (GV*)HeVAL(he);
if (isGV(gv) && GvCV(gv) &&
(!GvCVGEN(gv) || GvCVGEN(gv) == PL_sub_generation))
return (SV*)GvCV(gv);
}
}
gv = gv_fetchmethod(stash ? stash : (HV*)packsv, name);
if (!gv) {
char* leaf = name;
char* sep = Nullch;
char* p;
for (p = name; *p; p++) {
if (*p == '\'')
sep = p, leaf = p + 1;
else if (*p == ':' && *(p + 1) == ':')
sep = p, leaf = p + 2;
}
if (!sep || ((sep - name) == 5 && strnEQ(name, "SUPER", 5))) {
packname = sep ? CopSTASHPV(PL_curcop) :
stash ? HvNAME(stash) : packname;
packlen = strlen(packname);
}
else {
packname = name;
packlen = sep - name;
}
if (gv_stashpvn(packname, packlen, FALSE)) {
Perl_croak(aTHX_
"Can't locate object method \"%s\" via package \"%.*s\"",
leaf, (int)packlen, packname);
}
else {
Perl_croak(aTHX_
"Can't locate object method \"%s\" via package \"%.*s\""
" (perhaps you forgot to load \"%.*s\"?)",
leaf, (int)packlen, packname, (int)packlen, packname);
}
}
return isGV(gv) ? (SV*)GvCV(gv) : (SV*)gv;
}
#ifdef USE_5005THREADS
static void
unset_cvowner(pTHX_ void *cvarg)
{
register CV* cv = (CV *) cvarg;
DEBUG_S((PerlIO_printf(Perl_debug_log, "%p unsetting CvOWNER of %p:%s\n",
thr, cv, SvPEEK((SV*)cv))));
MUTEX_LOCK(CvMUTEXP(cv));
DEBUG_S(if (CvDEPTH(cv) != 0)
PerlIO_printf(Perl_debug_log, "depth %ld != 0\n",
CvDEPTH(cv)));
assert(thr == CvOWNER(cv));
CvOWNER(cv) = 0;
MUTEX_UNLOCK(CvMUTEXP(cv));
SvREFCNT_dec(cv);
}
#endif