#include "EXTERN.h"
#define PERL_IN_PP_CTL_C
#include "perl.h"
#include "feature.h"
#define dopopto_cursub() \
(PL_curstackinfo->si_cxsubix >= 0 \
? PL_curstackinfo->si_cxsubix \
: dopoptosub_at(cxstack, cxstack_ix))
#define dopoptosub(plop) dopoptosub_at(cxstack, (plop))
PP(pp_wantarray)
{
I32 cxix;
const
PERL_CONTEXT *cx;
SV *sv;
if
(PL_op->op_private & OPpOFFBYONE) {
if
(!(cx = caller_cx(1,NULL))) {
sv = &PL_sv_undef;
goto
ret;
}
}
else
{
cxix = dopopto_cursub();
if
(cxix < 0) {
sv = &PL_sv_undef;
goto
ret;
}
cx = &cxstack[cxix];
}
switch
(cx->blk_gimme) {
case
G_LIST:
sv = &PL_sv_yes;
break
;
case
G_SCALAR:
sv = &PL_sv_no;
break
;
default
:
sv = &PL_sv_undef;
break
;
}
ret:
rpp_xpush_IMM(sv);
return
NORMAL;
}
PP(pp_regcreset)
{
TAINT_NOT;
return
NORMAL;
}
PP(pp_regcomp)
{
PMOP *pm = cPMOPx(cLOGOP->op_other);
SV **args;
int
nargs;
REGEXP *re = NULL;
REGEXP *new_re;
const
regexp_engine *eng;
bool
is_bare_re= FALSE;
if
(PL_op->op_flags & OPf_STACKED) {
dMARK;
nargs = PL_stack_sp - MARK;
args = ++MARK;
}
else
{
nargs = 1;
args = PL_stack_sp;
}
#if defined(USE_ITHREADS)
if
(pm->op_pmflags & PMf_KEEP && PM_GETRE(pm))
goto
finish;
#endif
re = PM_GETRE(pm);
assert
(re != (REGEXP*) &PL_sv_undef);
eng = re ? RX_ENGINE(re) : current_re_engine();
new_re = (eng->op_comp
? eng->op_comp
: &Perl_re_op_compile
)(aTHX_ args, nargs, pm->op_code_list, eng, re,
&is_bare_re,
(pm->op_pmflags & RXf_PMf_FLAGCOPYMASK),
pm->op_pmflags |
(PL_op->op_flags & OPf_SPECIAL ? PMf_USE_RE_EVAL : 0));
if
(pm->op_pmflags & PMf_HAS_CV)
ReANY(new_re)->qr_anoncv
= (CV*) SvREFCNT_inc(PAD_SV(PL_op->op_targ));
if
(is_bare_re) {
REGEXP *tmp;
if
(pm->op_type == OP_MATCH) {
SV *lhs;
const
bool
was_tainted = TAINT_get;
if
(pm->op_flags & OPf_STACKED)
lhs = args[-1];
else
if
(pm->op_targ)
lhs = PAD_SV(pm->op_targ);
else
lhs = DEFSV;
SvGETMAGIC(lhs);
TAINT_set(was_tainted);
#ifdef NO_TAINT_SUPPORT
PERL_UNUSED_VAR(was_tainted);
#endif
}
tmp = reg_temp_copy(NULL, new_re);
ReREFCNT_dec(new_re);
new_re = tmp;
}
if
(re != new_re) {
ReREFCNT_dec(re);
PM_SETRE(pm, new_re);
}
assert
(TAINTING_get || !TAINT_get);
if
(TAINT_get) {
SvTAINTED_on((SV*)new_re);
RX_TAINT_on(new_re);
}
if
(!RX_PRELEN(PM_GETRE(pm)) && PL_curpm) {
if
(PL_curpm == PL_reg_curpm) {
if
(PL_curpm_under && PL_curpm_under == PL_reg_curpm) {
Perl_croak(aTHX_
"Infinite recursion via empty pattern"
);
}
}
}
#if !defined(USE_ITHREADS)
if
(pm->op_pmflags & PMf_KEEP) {
cLOGOP->op_first->op_next = PL_op->op_next;
}
#endif
#if defined(USE_ITHREADS)
finish:
#endif
rpp_popfree_to_NN(args - 1);
return
NORMAL;
}
PP(pp_substcont)
{
PERL_CONTEXT *cx = CX_CUR();
PMOP *
const
pm = cPMOPx(cLOGOP->op_other);
SV *
const
dstr = cx->sb_dstr;
char
*s = cx->sb_s;
char
*m = cx->sb_m;
char
*orig = cx->sb_orig;
REGEXP *
const
rx = cx->sb_rx;
SV *nsv = NULL;
REGEXP *old = PM_GETRE(pm);
PERL_ASYNC_CHECK();
if
(old != rx) {
if
(old)
ReREFCNT_dec(old);
PM_SETRE(pm,ReREFCNT_inc(rx));
}
rxres_restore(&cx->sb_rxres, rx);
if
(cx->sb_iters++) {
const
SSize_t saviters = cx->sb_iters;
if
(cx->sb_iters > cx->sb_maxiters)
DIE(aTHX_
"Substitution loop"
);
SvGETMAGIC(*PL_stack_sp);
sv_catsv_nomg(dstr, *PL_stack_sp);
rpp_popfree_1_NN();
if
(UNLIKELY(TAINT_get))
cx->sb_rxtainted |= SUBST_TAINT_REPL;
if
(CxONCE(cx) || s < orig ||
!CALLREGEXEC(rx, s, cx->sb_strend, orig,
(s == m), cx->sb_targ, NULL,
(REXEC_IGNOREPOS|REXEC_NOT_FIRST|REXEC_FAIL_ON_UNDERFLOW)))
{
SV *targ = cx->sb_targ;
SV *retval;
assert
(cx->sb_strend >= s);
if
(cx->sb_strend > s) {
if
(DO_UTF8(dstr) && !SvUTF8(targ))
sv_catpvn_nomg_utf8_upgrade(dstr, s, cx->sb_strend - s, nsv);
else
sv_catpvn_nomg(dstr, s, cx->sb_strend - s);
}
if
(RX_MATCH_TAINTED(rx))
cx->sb_rxtainted |= SUBST_TAINT_PAT;
if
(pm->op_pmflags & PMf_NONDESTRUCT) {
retval = dstr;
targ = dstr;
}
else
{
SV_CHECK_THINKFIRST_COW_DROP(targ);
if
(isGV(targ)) Perl_croak_no_modify();
SvPV_free(targ);
SvPV_set(targ, SvPVX(dstr));
SvCUR_set(targ, SvCUR(dstr));
SvLEN_set(targ, SvLEN(dstr));
if
(DO_UTF8(dstr))
SvUTF8_on(targ);
SvPV_set(dstr, NULL);
PL_tainted = 0;
retval = sv_newmortal();
sv_setiv(retval, saviters - 1);
(
void
)SvPOK_only_UTF8(targ);
}
if
(pm->op_pmflags & PMf_CONST)
rpp_popfree_1_NN();
if
(pm->op_flags & OPf_STACKED)
rpp_replace_1_1_NN(retval);
else
rpp_push_1(retval);
if
(TAINTING_get) {
if
((cx->sb_rxtainted & SUBST_TAINT_PAT) ||
((cx->sb_rxtainted & (SUBST_TAINT_STR|SUBST_TAINT_RETAINT))
== (SUBST_TAINT_STR|SUBST_TAINT_RETAINT))
)
(RX_MATCH_TAINTED_on(rx));
if
(!(cx->sb_rxtainted & SUBST_TAINT_BOOLRET)
&& (cx->sb_rxtainted & (SUBST_TAINT_STR|SUBST_TAINT_PAT))
)
SvTAINTED_on(retval);
TAINT_set(
cBOOL(cx->sb_rxtainted &
(SUBST_TAINT_STR|SUBST_TAINT_PAT|SUBST_TAINT_REPL))
);
{
MAGIC *mg;
mg = mg_find_mglob(targ);
if
(mg) {
MgBYTEPOS_set(mg, targ, SvPVX(targ), -1);
}
}
SvTAINT(TARG);
}
SvSETMAGIC(TARG);
TAINT_NOT;
CX_LEAVE_SCOPE(cx);
CX_POPSUBST(cx);
CX_POP(cx);
PERL_ASYNC_CHECK();
return
pm->op_next;
NOT_REACHED;
}
cx->sb_iters = saviters;
}
if
(RX_MATCH_COPIED(rx) && RX_SUBBEG(rx) != orig) {
m = s;
s = orig;
assert
(!RX_SUBOFFSET(rx));
cx->sb_orig = orig = RX_SUBBEG(rx);
s = orig + (m - s);
cx->sb_strend = s + (cx->sb_strend - m);
}
cx->sb_m = m = RX_OFFS_START(rx,0) + orig;
if
(m > s) {
if
(DO_UTF8(dstr) && !SvUTF8(cx->sb_targ))
sv_catpvn_nomg_utf8_upgrade(dstr, s, m - s, nsv);
else
sv_catpvn_nomg(dstr, s, m-s);
}
cx->sb_s = RX_OFFS_END(rx,0) + orig;
{
SV *
const
sv
= (pm->op_pmflags & PMf_NONDESTRUCT) ? cx->sb_dstr : cx->sb_targ;
MAGIC *mg;
if
(!SvPOK(sv))
SvPV_force_nomg_nolen(sv);
if
(!(mg = mg_find_mglob(sv))) {
mg = sv_magicext_mglob(sv);
}
MgBYTEPOS_set(mg, sv, SvPVX(sv), m - orig);
}
if
(old != rx)
(
void
)ReREFCNT_inc(rx);
if
(TAINTING_get) {
if
(RX_MATCH_TAINTED(rx))
cx->sb_rxtainted |= SUBST_TAINT_PAT;
if
((cx->sb_rxtainted & SUBST_TAINT_PAT) ||
((cx->sb_rxtainted & (SUBST_TAINT_STR|SUBST_TAINT_RETAINT))
== (SUBST_TAINT_STR|SUBST_TAINT_RETAINT))
)
(RX_MATCH_TAINTED_on(rx));
if
(cx->sb_iters > 1 && (cx->sb_rxtainted &
(SUBST_TAINT_STR|SUBST_TAINT_PAT|SUBST_TAINT_REPL)))
SvTAINTED_on((pm->op_pmflags & PMf_NONDESTRUCT)
? cx->sb_dstr : cx->sb_targ);
TAINT_NOT;
}
rxres_save(&cx->sb_rxres, rx);
PL_curpm = pm;
return
pm->op_pmstashstartu.op_pmreplstart;
}
void
Perl_rxres_save(pTHX_
void
**rsp, REGEXP *rx)
{
UV *p = (UV*)*rsp;
U32 i;
PERL_ARGS_ASSERT_RXRES_SAVE;
PERL_UNUSED_CONTEXT;
if
(!p || p[1] < RX_NPARENS(rx)) {
#ifdef PERL_ANY_COW
i = 7 + (RX_NPARENS(rx)+1) * 2;
#else
i = 6 + (RX_NPARENS(rx)+1) * 2;
#endif
if
(!p)
Newx(p, i, UV);
else
Renew(p, i, UV);
*rsp = (
void
*)p;
}
*p++ = PTR2UV(RX_MATCH_COPIED(rx) ? RX_SUBBEG(rx) : NULL);
RX_MATCH_COPIED_off(rx);
*p++ = RX_NPARENS(rx);
#ifdef PERL_ANY_COW
*p++ = PTR2UV(RX_SAVED_COPY(rx));
RX_SAVED_COPY(rx) = NULL;
#endif
*p++ = PTR2UV(RX_SUBBEG(rx));
*p++ = (UV)RX_SUBLEN(rx);
*p++ = (UV)RX_SUBOFFSET(rx);
*p++ = (UV)RX_SUBCOFFSET(rx);
for
(i = 0; i <= RX_NPARENS(rx); ++i) {
*p++ = (UV)RX_OFFSp(rx)[i].start;
*p++ = (UV)RX_OFFSp(rx)[i].end;
}
}
static
void
S_rxres_restore(pTHX_
void
**rsp, REGEXP *rx)
{
UV *p = (UV*)*rsp;
U32 i;
PERL_ARGS_ASSERT_RXRES_RESTORE;
PERL_UNUSED_CONTEXT;
RX_MATCH_COPY_FREE(rx);
RX_MATCH_COPIED_set(rx, *p);
*p++ = 0;
RX_NPARENS(rx) = *p++;
#ifdef PERL_ANY_COW
if
(RX_SAVED_COPY(rx))
SvREFCNT_dec (RX_SAVED_COPY(rx));
RX_SAVED_COPY(rx) = INT2PTR(SV*,*p);
*p++ = 0;
#endif
RX_SUBBEG(rx) = INT2PTR(
char
*,*p++);
RX_SUBLEN(rx) = (SSize_t)(*p++);
RX_SUBOFFSET(rx) = (Size_t)*p++;
RX_SUBCOFFSET(rx) = (SSize_t)*p++;
for
(i = 0; i <= RX_NPARENS(rx); ++i) {
RX_OFFSp(rx)[i].start = (SSize_t)(*p++);
RX_OFFSp(rx)[i].end = (SSize_t)(*p++);
}
}
static
void
S_rxres_free(pTHX_
void
**rsp)
{
UV *
const
p = (UV*)*rsp;
PERL_ARGS_ASSERT_RXRES_FREE;
PERL_UNUSED_CONTEXT;
if
(p) {
void
*tmp = INT2PTR(
char
*,*p);
#ifdef PERL_POISON
#ifdef PERL_ANY_COW
U32 i = 9 + p[1] * 2;
#else
U32 i = 8 + p[1] * 2;
#endif
#endif
#ifdef PERL_ANY_COW
SvREFCNT_dec (INT2PTR(SV*,p[2]));
#endif
#ifdef PERL_POISON
PoisonFree(p, i,
sizeof
(UV));
#endif
Safefree(tmp);
Safefree(p);
*rsp = NULL;
}
}
#define FORM_NUM_BLANK (1<<30)
#define FORM_NUM_POINT (1<<29)
PP_wrapped(pp_formline, 0, 1)
{
dSP; dMARK; dORIGMARK;
SV *
const
tmpForm = *++MARK;
SV *formsv;
U32 *fpc;
char
*t;
const
char
*f;
I32 arg;
SV *sv = NULL;
const
char
*item = NULL;
I32 itemsize = 0;
I32 itembytes = 0;
I32 fieldsize = 0;
I32 lines = 0;
bool
chopspace = (
strchr
(PL_chopset,
' '
) != NULL);
const
char
*chophere = NULL;
STRLEN linemark = 0;
NV value;
bool
gotsome = FALSE;
STRLEN len;
STRLEN linemax;
bool
item_is_utf8 = FALSE;
bool
targ_is_utf8 = FALSE;
const
char
*fmt;
MAGIC *mg = NULL;
U8 *source;
STRLEN to_copy;
char
trans;
bool
copied_form = FALSE;
mg = doparseform(tmpForm);
fpc = (U32*)mg->mg_ptr;
formsv = mg->mg_obj;
SvPV_force(PL_formtarget, len);
if
(SvTAINTED(tmpForm) || SvTAINTED(formsv))
SvTAINTED_on(PL_formtarget);
if
(DO_UTF8(PL_formtarget))
targ_is_utf8 = TRUE;
linemax = (SvCUR(formsv) * (IN_BYTES ? 1 : 3) + 1);
t = SvGROW(PL_formtarget, len + linemax + 1);
t += len;
f = SvPV_const(formsv, len);
for
(;;) {
DEBUG_f( {
const
char
*name =
"???"
;
arg = -1;
switch
(*fpc) {
case
FF_LITERAL: arg = fpc[1]; name =
"LITERAL"
;
break
;
case
FF_BLANK: arg = fpc[1]; name =
"BLANK"
;
break
;
case
FF_SKIP: arg = fpc[1]; name =
"SKIP"
;
break
;
case
FF_FETCH: arg = fpc[1]; name =
"FETCH"
;
break
;
case
FF_DECIMAL: arg = fpc[1]; name =
"DECIMAL"
;
break
;
case
FF_CHECKNL: name =
"CHECKNL"
;
break
;
case
FF_CHECKCHOP: name =
"CHECKCHOP"
;
break
;
case
FF_SPACE: name =
"SPACE"
;
break
;
case
FF_HALFSPACE: name =
"HALFSPACE"
;
break
;
case
FF_ITEM: name =
"ITEM"
;
break
;
case
FF_CHOP: name =
"CHOP"
;
break
;
case
FF_LINEGLOB: name =
"LINEGLOB"
;
break
;
case
FF_NEWLINE: name =
"NEWLINE"
;
break
;
case
FF_MORE: name =
"MORE"
;
break
;
case
FF_LINEMARK: name =
"LINEMARK"
;
break
;
case
FF_END: name =
"END"
;
break
;
case
FF_0DECIMAL: name =
"0DECIMAL"
;
break
;
case
FF_LINESNGL: name =
"LINESNGL"
;
break
;
}
if
(arg >= 0)
PerlIO_printf(Perl_debug_log,
"%-16s%ld\n"
, name, (
long
) arg);
else
PerlIO_printf(Perl_debug_log,
"%-16s\n"
, name);
} );
switch
(*fpc++) {
case
FF_LINEMARK:
linemark = t - SvPVX(PL_formtarget);
lines++;
gotsome = FALSE;
break
;
case
FF_LITERAL:
to_copy = *fpc++;
source = (U8 *)f;
f += to_copy;
trans =
'~'
;
item_is_utf8 = (targ_is_utf8)
? cBOOL(DO_UTF8(formsv))
: cBOOL(SvUTF8(formsv));
goto
append;
case
FF_SKIP:
f += *fpc++;
break
;
case
FF_FETCH:
arg = *fpc++;
f += arg;
fieldsize = arg;
if
(MARK < SP)
sv = *++MARK;
else
{
sv = &PL_sv_no;
Perl_ck_warner(aTHX_ packWARN(WARN_SYNTAX),
"Not enough format arguments"
);
}
if
(SvTAINTED(sv))
SvTAINTED_on(PL_formtarget);
break
;
case
FF_CHECKNL:
{
const
char
*s = item = SvPV_const(sv, len);
const
char
*send = s + len;
itemsize = 0;
item_is_utf8 = DO_UTF8(sv);
while
(s < send) {
if
(!isCNTRL(*s))
gotsome = TRUE;
else
if
(*s ==
'\n'
)
break
;
if
(item_is_utf8)
s += UTF8SKIP(s);
else
s++;
itemsize++;
if
(itemsize == fieldsize)
break
;
}
itembytes = s - item;
chophere = s;
break
;
}
case
FF_CHECKCHOP:
{
const
char
*s = item = SvPV_const(sv, len);
const
char
*send = s + len;
I32 size = 0;
chophere = NULL;
item_is_utf8 = DO_UTF8(sv);
while
(s < send) {
if
(isSPACE(*s)) {
if
(*s ==
'\r'
) {
chophere = s;
itemsize = size;
break
;
}
if
(chopspace) {
chophere = s;
itemsize = size;
}
if
(size == fieldsize)
break
;
}
else
{
if
(size == fieldsize)
break
;
if
(
strchr
(PL_chopset, *s)) {
chophere = s + 1;
itemsize = size + 1;
}
if
(!isCNTRL(*s))
gotsome = TRUE;
}
if
(item_is_utf8)
s += UTF8SKIP(s);
else
s++;
size++;
}
if
(!chophere || s == send) {
chophere = s;
itemsize = size;
}
itembytes = chophere - item;
break
;
}
case
FF_SPACE:
arg = fieldsize - itemsize;
if
(arg) {
fieldsize -= arg;
while
(arg-- > 0)
*t++ =
' '
;
}
break
;
case
FF_HALFSPACE:
arg = fieldsize - itemsize;
if
(arg) {
arg /= 2;
fieldsize -= arg;
while
(arg-- > 0)
*t++ =
' '
;
}
break
;
case
FF_ITEM:
to_copy = itembytes;
source = (U8 *)item;
trans = 1;
goto
append;
case
FF_CHOP:
if
(sv != &PL_sv_no) {
const
char
*s = chophere;
if
(!copied_form &&
((sv == tmpForm || SvSMAGICAL(sv))
|| (SvGMAGICAL(tmpForm) && !sv_only_taint_gmagic(tmpForm))) ) {
SV *newformsv = sv_mortalcopy(formsv);
U32 *new_compiled;
f = SvPV_nolen(newformsv) + (f - SvPV_nolen(formsv));
Newx(new_compiled, mg->mg_len /
sizeof
(U32), U32);
memcpy
(new_compiled, mg->mg_ptr, mg->mg_len);
SAVEFREEPV(new_compiled);
fpc = new_compiled + (fpc - (U32*)mg->mg_ptr);
formsv = newformsv;
copied_form = TRUE;
}
if
(chopspace) {
while
(isSPACE(*s))
s++;
}
if
(SvPOKp(sv))
sv_chop(sv,s);
else
sv_setpvn(sv, s, len - (s-item));
SvSETMAGIC(sv);
break
;
}
case
FF_LINESNGL:
chopspace = 0;
case
FF_LINEGLOB:
{
const
bool
oneline = fpc[-1] == FF_LINESNGL;
const
char
*s = item = SvPV_const(sv, len);
const
char
*
const
send = s + len;
item_is_utf8 = DO_UTF8(sv);
chophere = s + len;
if
(!len)
break
;
trans = 0;
gotsome = TRUE;
source = (U8 *) s;
to_copy = len;
while
(s < send) {
if
(*s++ ==
'\n'
) {
if
(oneline) {
to_copy = s - item - 1;
chophere = s;
break
;
}
else
{
if
(s == send) {
to_copy--;
}
else
lines++;
}
}
}
}
append:
{
U8 *tmp = NULL;
STRLEN grow = 0;
SvCUR_set(PL_formtarget,
t - SvPVX_const(PL_formtarget));
if
(targ_is_utf8 && !item_is_utf8) {
source = tmp = bytes_to_utf8(source, &to_copy);
grow = to_copy;
}
else
{
if
(item_is_utf8 && !targ_is_utf8) {
U8 *s;
sv_utf8_upgrade_nomg(PL_formtarget);
targ_is_utf8 = TRUE;
s = (U8*)SvPVX(PL_formtarget);
grow = linemax;
while
(linemark--)
s += UTF8_SAFE_SKIP(s,
(U8 *) SvEND(PL_formtarget));
linemark = s - (U8*)SvPVX(PL_formtarget);
}
assert
(item_is_utf8 == targ_is_utf8);
}
if
(!trans)
grow = linemax + to_copy;
if
(grow)
SvGROW(PL_formtarget, SvCUR(PL_formtarget) + grow + 1);
t = SvPVX(PL_formtarget) + SvCUR(PL_formtarget);
Copy(source, t, to_copy,
char
);
if
(trans) {
U8 *s = (U8*)t;
U8 *send = s + to_copy;
while
(s < send) {
const
int
ch = *s;
if
(trans ==
'~'
? (ch ==
'~'
) : isCNTRL(ch))
*s =
' '
;
s++;
}
}
t += to_copy;
SvCUR_set(PL_formtarget, SvCUR(PL_formtarget) + to_copy);
if
(tmp)
Safefree(tmp);
break
;
}
case
FF_0DECIMAL:
arg = *fpc++;
fmt = (
const
char
*)
((arg & FORM_NUM_POINT) ?
"%#0*.*"
NVff :
"%0*.*"
NVff);
goto
ff_dec;
case
FF_DECIMAL:
arg = *fpc++;
fmt = (
const
char
*)
((arg & FORM_NUM_POINT) ?
"%#*.*"
NVff :
"%*.*"
NVff);
ff_dec:
if
((arg & FORM_NUM_BLANK) && !SvOK(sv)) {
arg = fieldsize;
while
(arg--)
*t++ =
' '
;
break
;
}
gotsome = TRUE;
value = SvNV(sv);
if
(num_overflow(value, fieldsize, arg)) {
arg = fieldsize;
while
(arg--)
*t++ =
'#'
;
break
;
}
{
Size_t max = SvLEN(PL_formtarget) - (t - SvPVX(PL_formtarget));
int
len;
arg &= ~(FORM_NUM_POINT|FORM_NUM_BLANK);
#ifdef USE_QUADMATH
{
int
len;
if
(!quadmath_format_valid(fmt))
Perl_croak_nocontext(
"panic: quadmath invalid format \"%s\""
, fmt);
WITH_LC_NUMERIC_SET_TO_NEEDED(
len = quadmath_snprintf(t, max, fmt, (
int
) fieldsize,
(
int
) arg, value);
);
if
(len == -1)
Perl_croak_nocontext(
"panic: quadmath_snprintf failed, format \"%s\""
, fmt);
}
#else
GCC_DIAG_IGNORE_STMT(-Wformat-nonliteral);
len = my_snprintf(t, max, fmt, (
int
) fieldsize, (
int
) arg, value);
GCC_DIAG_RESTORE_STMT;
#endif
PERL_MY_SNPRINTF_POST_GUARD(len, max);
}
t += fieldsize;
break
;
case
FF_NEWLINE:
f++;
while
(t-- > (SvPVX(PL_formtarget) + linemark) && *t ==
' '
) ;
t++;
*t++ =
'\n'
;
break
;
case
FF_BLANK:
arg = *fpc++;
if
(gotsome) {
if
(arg) {
fpc--;
goto
end;
}
}
else
{
t = SvPVX(PL_formtarget) + linemark;
lines--;
}
break
;
case
FF_MORE:
{
const
char
*s = chophere;
const
char
*send = item + len;
if
(chopspace) {
while
(isSPACE(*s) && (s < send))
s++;
}
if
(s < send) {
char
*s1;
arg = fieldsize - itemsize;
if
(arg) {
fieldsize -= arg;
while
(arg-- > 0)
*t++ =
' '
;
}
s1 = t - 3;
if
(strBEGINs(s1,
" "
)) {
while
(s1 > SvPVX_const(PL_formtarget) && isSPACE(s1[-1]))
s1--;
}
*s1++ =
'.'
;
*s1++ =
'.'
;
*s1++ =
'.'
;
}
break
;
}
case
FF_END:
end:
assert
(t < SvPVX_const(PL_formtarget) + SvLEN(PL_formtarget));
*t =
'\0'
;
SvCUR_set(PL_formtarget, t - SvPVX_const(PL_formtarget));
if
(targ_is_utf8)
SvUTF8_on(PL_formtarget);
FmLINES(PL_formtarget) += lines;
SP = ORIGMARK;
if
(fpc[-1] == FF_BLANK)
RETURNOP(cLISTOP->op_first);
else
RETPUSHYES;
}
}
}
PP(pp_grepstart)
{
SV *src;
SV **svp;
if
(PL_stack_base + TOPMARK == PL_stack_sp) {
(
void
)POPMARK;
if
(GIMME_V == G_SCALAR) {
rpp_extend(1);
*++PL_stack_sp = &PL_sv_zero;
}
return
PL_op->op_next->op_next;
}
svp = PL_stack_base + TOPMARK + 1;
PUSHMARK(svp);
PUSHMARK(svp);
ENTER_with_name(
"grep"
);
SAVETMPS;
SAVE_DEFSV;
ENTER_with_name(
"grep_item"
);
SAVEVPTR(PL_curpm);
src = PL_stack_base[TOPMARK];
if
(SvPADTMP(src)) {
SV *newsrc = sv_mortalcopy(src);
PL_tmps_floor++;
PL_stack_base[TOPMARK] = newsrc;
#ifdef PERL_RC_STACK
SvREFCNT_inc_simple_void_NN(newsrc);
SvREFCNT_dec(src);
#endif
src = newsrc;
}
SvTEMP_off(src);
DEFSV_set(src);
if
(PL_op->op_type == OP_MAPSTART)
PUSHMARK(PL_stack_sp);
return
cLOGOPx(PL_op->op_next)->op_other;
}
PP(pp_mapwhile)
{
const
U8 gimme = GIMME_V;
SSize_t items = (PL_stack_sp - PL_stack_base) - TOPMARK;
SSize_t count;
SSize_t shift;
SV** src;
SV** dst;
#ifdef PERL_RC_STACK
dst = PL_stack_base + PL_markstack_ptr[-1];
SvREFCNT_dec_NN(*dst);
*dst = NULL;
#endif
++PL_markstack_ptr[-1];
if
(items && gimme != G_VOID) {
if
(items > PL_markstack_ptr[-1] - PL_markstack_ptr[-2]) {
shift = items - (PL_markstack_ptr[-1] - PL_markstack_ptr[-2]);
count = (PL_stack_sp - PL_stack_base) - (PL_markstack_ptr[-1] - 1);
if
(shift < count)
shift = count;
rpp_extend(shift);
src = PL_stack_sp;
PL_stack_sp += shift;
dst = PL_stack_sp;
PL_markstack_ptr[-1] += shift;
*PL_markstack_ptr += shift;
while
(count--)
*dst-- = *src--;
#ifdef PERL_RC_STACK
Zero(src+1, (dst-src), SV*);
#endif
}
PL_markstack_ptr[-2] += items;
dst = PL_stack_base + PL_markstack_ptr[-2] - 1;
if
(gimme == G_LIST) {
SSize_t tmpsbase;
SSize_t i = items;
EXTEND_MORTAL(items);
tmpsbase = PL_tmps_floor + 1;
Move(PL_tmps_stack + tmpsbase,
PL_tmps_stack + tmpsbase + items,
PL_tmps_ix - PL_tmps_floor,
SV*);
PL_tmps_ix += items;
while
(i-- > 0) {
#ifdef PERL_RC_STACK
SV *sv = *PL_stack_sp;
assert
(!*dst);
if
(!SvTEMP(sv)) {
sv = sv_mortalcopy(sv);
*dst-- = sv;
SvREFCNT_inc_simple_void_NN(sv);
rpp_popfree_1_NN();
}
else
{
*dst-- = sv;
PL_stack_sp--;
}
#else
SV *sv = *PL_stack_sp--;
if
(!SvTEMP(sv))
sv = sv_mortalcopy(sv);
*dst-- = sv;
#endif
PL_tmps_stack[tmpsbase++] = SvREFCNT_inc_simple(sv);
}
PL_tmps_floor += items;
FREETMPS;
i = items;
while
(i-- > 0)
SvTEMP_on(PL_tmps_stack[--tmpsbase]);
}
else
{
*(dst - items + 1) = &PL_sv_undef;
rpp_popfree_to(PL_stack_sp - items);
FREETMPS;
}
}
else
{
if
(items) {
assert
(gimme == G_VOID);
rpp_popfree_to(PL_stack_sp - items);
}
FREETMPS;
}
LEAVE_with_name(
"grep_item"
);
if
(PL_markstack_ptr[-1] > TOPMARK) {
(
void
)POPMARK;
LEAVE_with_name(
"grep"
);
(
void
)POPMARK;
items = --*PL_markstack_ptr - PL_markstack_ptr[-1];
(
void
)POPMARK;
SV **svp = PL_stack_base + POPMARK;
if
(gimme == G_LIST)
svp += items;
rpp_popfree_to(svp);
if
(gimme == G_SCALAR) {
dTARGET;
TARGi(items, 1);
rpp_xpush_1(targ);
}
return
NORMAL;
}
else
{
SV *src;
ENTER_with_name(
"grep_item"
);
SAVEVPTR(PL_curpm);
src = PL_stack_base[PL_markstack_ptr[-1]];
if
(SvPADTMP(src)) {
SV *newsrc = sv_mortalcopy(src);
PL_stack_base[PL_markstack_ptr[-1]] = newsrc;
#ifdef PERL_RC_STACK
SvREFCNT_inc_simple_void_NN(newsrc);
SvREFCNT_dec(src);
#endif
src = newsrc;
}
if
(SvPADTMP(src)) {
src = sv_mortalcopy(src);
}
SvTEMP_off(src);
DEFSV_set(src);
return
cLOGOP->op_other;
}
}
PP(pp_range)
{
dTARG;
if
(GIMME_V == G_LIST)
return
NORMAL;
GETTARGET;
if
(SvTRUE_NN(targ))
return
cLOGOP->op_other;
else
return
NORMAL;
}
PP_wrapped(pp_flip,((GIMME_V == G_LIST) ? 0 : 1), 0)
{
dSP;
if
(GIMME_V == G_LIST) {
RETURNOP(cLOGOPx(cUNOP->op_first)->op_other);
}
else
{
dTOPss;
SV *
const
targ = PAD_SV(PL_op->op_targ);
int
flip = 0;
if
(PL_op->op_private & OPpFLIP_LINENUM) {
if
(GvIO(PL_last_in_gv)) {
flip = SvIV(sv) == (IV)IoLINES(GvIOp(PL_last_in_gv));
}
else
{
GV *
const
gv = gv_fetchpvs(
"."
, GV_ADD|GV_NOTQUAL, SVt_PV);
if
(gv && GvSV(gv))
flip = SvIV(sv) == SvIV(GvSV(gv));
}
}
else
{
flip = SvTRUE_NN(sv);
}
if
(flip) {
sv_setiv(PAD_SV(cUNOP->op_first->op_targ), 1);
if
(PL_op->op_flags & OPf_SPECIAL) {
sv_setiv(targ, 1);
SETs(targ);
RETURN;
}
else
{
sv_setiv(targ, 0);
SP--;
RETURNOP(cLOGOPx(cUNOP->op_first)->op_other);
}
}
SvPVCLEAR(TARG);
SETs(targ);
RETURN;
}
}
#define RANGE_IS_NUMERIC(left,right) ( \
SvNIOKp(left) || (SvOK(left) && !SvPOKp(left)) || \
SvNIOKp(right) || (SvOK(right) && !SvPOKp(right)) || \
(((!SvOK(left) && SvOK(right)) || ((!SvOK(left) || \
looks_like_number(left)) && SvPOKp(left) \
&& !(*SvPVX_const(left) ==
'0'
&& SvCUR(left)>1 ) )) \
&& (!SvOK(right) || looks_like_number(right))))
PP_wrapped(pp_flop, (GIMME_V == G_LIST) ? 2 : 1, 0)
{
dSP;
if
(GIMME_V == G_LIST) {
dPOPPOPssrl;
SvGETMAGIC(left);
SvGETMAGIC(right);
if
(RANGE_IS_NUMERIC(left,right)) {
IV i, j, n;
if
((SvOK(left) && !SvIOK(left) && SvNV_nomg(left) < IV_MIN) ||
(SvOK(right) && (SvIOK(right)
? SvIsUV(right) && SvUV(right) > IV_MAX
: SvNV_nomg(right) > (NV) IV_MAX)))
DIE(aTHX_
"Range iterator outside integer range"
);
i = SvIV_nomg(left);
j = SvIV_nomg(right);
if
(j >= i) {
bool
overflow = (i <= 0 && j > SSize_t_MAX + i - 1);
if
(!overflow) {
n = j - i + 1;
if
(n < 1
#if IVSIZE > Size_t_size
|| n > SSize_t_MAX
#endif
)
overflow = TRUE;
}
if
(overflow)
Perl_croak(aTHX_
"Out of memory during list extend"
);
EXTEND_MORTAL(n);
EXTEND(SP, n);
}
else
n = 0;
while
(n--) {
SV *
const
sv = sv_2mortal(newSViv(i));
PUSHs(sv);
if
(n)
i++;
}
}
else
{
STRLEN len, llen;
const
char
*
const
lpv = SvPV_nomg_const(left, llen);
const
char
*
const
tmps = SvPV_nomg_const(right, len);
SV *sv = newSVpvn_flags(lpv, llen, SvUTF8(left)|SVs_TEMP);
if
(DO_UTF8(right) && IN_UNI_8_BIT)
len = sv_len_utf8_nomg(right);
while
(!SvNIOKp(sv) && SvCUR(sv) <= len) {
XPUSHs(sv);
if
(strEQ(SvPVX_const(sv),tmps))
break
;
sv = sv_2mortal(newSVsv(sv));
sv_inc(sv);
}
}
}
else
{
dTOPss;
SV *
const
targ = PAD_SV(cUNOP->op_first->op_targ);
int
flop = 0;
sv_inc(targ);
if
(PL_op->op_private & OPpFLIP_LINENUM) {
if
(GvIO(PL_last_in_gv)) {
flop = SvIV(sv) == (IV)IoLINES(GvIOp(PL_last_in_gv));
}
else
{
GV *
const
gv = gv_fetchpvs(
"."
, GV_ADD|GV_NOTQUAL, SVt_PV);
if
(gv && GvSV(gv)) flop = SvIV(sv) == SvIV(GvSV(gv));
}
}
else
{
flop = SvTRUE_NN(sv);
}
if
(flop) {
sv_setiv(PAD_SV(cUNOPx(cUNOP->op_first)->op_first->op_targ), 0);
sv_catpvs(targ,
"E0"
);
}
SETs(targ);
}
RETURN;
}
static
const
char
*
const
context_name[] = {
"pseudo-block"
,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
"subroutine"
,
"format"
,
"eval"
,
"substitution"
,
"defer block"
,
};
STATIC I32
S_dopoptolabel(pTHX_
const
char
*label, STRLEN len, U32 flags)
{
I32 i;
PERL_ARGS_ASSERT_DOPOPTOLABEL;
for
(i = cxstack_ix; i >= 0; i--) {
const
PERL_CONTEXT *
const
cx = &cxstack[i];
switch
(CxTYPE(cx)) {
case
CXt_EVAL:
if
(CxTRY(cx))
continue
;
case
CXt_SUBST:
case
CXt_SUB:
case
CXt_FORMAT:
case
CXt_NULL:
Perl_ck_warner(aTHX_ packWARN(WARN_EXITING),
"Exiting %s via %s"
,
context_name[CxTYPE(cx)], OP_NAME(PL_op));
if
(CxTYPE(cx) == CXt_NULL)
return
-1;
break
;
case
CXt_LOOP_PLAIN:
case
CXt_LOOP_LAZYIV:
case
CXt_LOOP_LAZYSV:
case
CXt_LOOP_LIST:
case
CXt_LOOP_ARY:
{
STRLEN cx_label_len = 0;
U32 cx_label_flags = 0;
const
char
*cx_label = CxLABEL_len_flags(cx, &cx_label_len, &cx_label_flags);
if
(!cx_label || !(
( (cx_label_flags & SVf_UTF8) != (flags & SVf_UTF8) ) ?
(flags & SVf_UTF8)
? (bytes_cmp_utf8(
(
const
U8*)cx_label, cx_label_len,
(
const
U8*)label, len) == 0)
: (bytes_cmp_utf8(
(
const
U8*)label, len,
(
const
U8*)cx_label, cx_label_len) == 0)
: (len == cx_label_len && ((cx_label == label)
|| memEQ(cx_label, label, len))) )) {
DEBUG_l(Perl_deb(aTHX_
"(poptolabel(): skipping label at cx=%ld %s)\n"
,
(
long
)i, cx_label));
continue
;
}
DEBUG_l( Perl_deb(aTHX_
"(poptolabel(): found label at cx=%ld %s)\n"
, (
long
)i, label));
return
i;
}
}
}
return
i;
}
U8
Perl_dowantarray(pTHX)
{
const
U8 gimme = block_gimme();
return
(gimme == G_VOID) ? G_SCALAR : gimme;
}
U8
Perl_block_gimme(pTHX)
{
const
I32 cxix = dopopto_cursub();
U8 gimme;
if
(cxix < 0)
return
G_VOID;
gimme = (cxstack[cxix].blk_gimme & G_WANT);
if
(!gimme)
Perl_croak(aTHX_
"panic: bad gimme: %d\n"
, gimme);
return
gimme;
}
I32
Perl_is_lvalue_sub(pTHX)
{
const
I32 cxix = dopopto_cursub();
assert
(cxix >= 0);
if
(CxLVAL(cxstack + cxix) && CvLVALUE(cxstack[cxix].blk_sub.cv))
return
CxLVAL(cxstack + cxix);
else
return
0;
}
I32
Perl_was_lvalue_sub(pTHX)
{
const
I32 cxix = dopoptosub(cxstack_ix-1);
assert
(cxix >= 0);
if
(CxLVAL(cxstack + cxix) && CvLVALUE(cxstack[cxix].blk_sub.cv))
return
CxLVAL(cxstack + cxix);
else
return
0;
}
STATIC I32
S_dopoptosub_at(pTHX_
const
PERL_CONTEXT *cxstk, I32 startingblock)
{
I32 i;
PERL_ARGS_ASSERT_DOPOPTOSUB_AT;
#ifndef DEBUGGING
PERL_UNUSED_CONTEXT;
#endif
for
(i = startingblock; i >= 0; i--) {
const
PERL_CONTEXT *
const
cx = &cxstk[i];
switch
(CxTYPE(cx)) {
default
:
continue
;
case
CXt_SUB:
if
(cx->cx_type & CXp_SUB_RE_FAKE)
continue
;
DEBUG_l( Perl_deb(aTHX_
"(dopoptosub_at(): found sub at cx=%ld)\n"
, (
long
)i));
return
i;
case
CXt_EVAL:
if
(CxTRY(cx))
continue
;
DEBUG_l( Perl_deb(aTHX_
"(dopoptosub_at(): found sub at cx=%ld)\n"
, (
long
)i));
return
i;
case
CXt_FORMAT:
DEBUG_l( Perl_deb(aTHX_
"(dopoptosub_at(): found sub at cx=%ld)\n"
, (
long
)i));
return
i;
}
}
return
i;
}
STATIC I32
S_dopoptoeval(pTHX_ I32 startingblock)
{
I32 i;
for
(i = startingblock; i >= 0; i--) {
const
PERL_CONTEXT *cx = &cxstack[i];
switch
(CxTYPE(cx)) {
default
:
continue
;
case
CXt_EVAL:
DEBUG_l( Perl_deb(aTHX_
"(dopoptoeval(): found eval at cx=%ld)\n"
, (
long
)i));
return
i;
}
}
return
i;
}
STATIC I32
S_dopoptoloop(pTHX_ I32 startingblock)
{
I32 i;
for
(i = startingblock; i >= 0; i--) {
const
PERL_CONTEXT *
const
cx = &cxstack[i];
switch
(CxTYPE(cx)) {
case
CXt_EVAL:
if
(CxTRY(cx))
continue
;
case
CXt_SUBST:
case
CXt_SUB:
case
CXt_FORMAT:
case
CXt_NULL:
Perl_ck_warner(aTHX_ packWARN(WARN_EXITING),
"Exiting %s via %s"
,
context_name[CxTYPE(cx)], OP_NAME(PL_op));
if
((CxTYPE(cx)) == CXt_NULL)
return
-1;
break
;
case
CXt_LOOP_PLAIN:
case
CXt_LOOP_LAZYIV:
case
CXt_LOOP_LAZYSV:
case
CXt_LOOP_LIST:
case
CXt_LOOP_ARY:
DEBUG_l( Perl_deb(aTHX_
"(dopoptoloop(): found loop at cx=%ld)\n"
, (
long
)i));
return
i;
}
}
return
i;
}
STATIC I32
S_dopoptogivenfor(pTHX_ I32 startingblock)
{
I32 i;
for
(i = startingblock; i >= 0; i--) {
const
PERL_CONTEXT *cx = &cxstack[i];
switch
(CxTYPE(cx)) {
default
:
continue
;
case
CXt_GIVEN:
DEBUG_l( Perl_deb(aTHX_
"(dopoptogivenfor(): found given at cx=%ld)\n"
, (
long
)i));
return
i;
case
CXt_LOOP_PLAIN:
assert
(!(cx->cx_type & CXp_FOR_DEF));
break
;
case
CXt_LOOP_LAZYIV:
case
CXt_LOOP_LAZYSV:
case
CXt_LOOP_LIST:
case
CXt_LOOP_ARY:
if
(cx->cx_type & CXp_FOR_DEF) {
DEBUG_l( Perl_deb(aTHX_
"(dopoptogivenfor(): found foreach at cx=%ld)\n"
, (
long
)i));
return
i;
}
}
}
return
i;
}
STATIC I32
S_dopoptowhen(pTHX_ I32 startingblock)
{
I32 i;
for
(i = startingblock; i >= 0; i--) {
const
PERL_CONTEXT *cx = &cxstack[i];
switch
(CxTYPE(cx)) {
default
:
continue
;
case
CXt_WHEN:
DEBUG_l( Perl_deb(aTHX_
"(dopoptowhen(): found when at cx=%ld)\n"
, (
long
)i));
return
i;
}
}
return
i;
}
void
Perl_dounwind(pTHX_ I32 cxix)
{
if
(!PL_curstackinfo)
return
;
while
(cxstack_ix > cxix) {
PERL_CONTEXT *cx = CX_CUR();
CX_DEBUG(cx,
"UNWIND"
);
CX_LEAVE_SCOPE(cx);
switch
(CxTYPE(cx)) {
case
CXt_SUBST:
CX_POPSUBST(cx);
if
(cxstack_ix == cxix + 1) {
cxstack_ix--;
return
;
}
break
;
case
CXt_SUB:
cx_popsub(cx);
break
;
case
CXt_EVAL:
cx_popeval(cx);
break
;
case
CXt_LOOP_PLAIN:
case
CXt_LOOP_LAZYIV:
case
CXt_LOOP_LAZYSV:
case
CXt_LOOP_LIST:
case
CXt_LOOP_ARY:
cx_poploop(cx);
break
;
case
CXt_WHEN:
cx_popwhen(cx);
break
;
case
CXt_GIVEN:
cx_popgiven(cx);
break
;
case
CXt_BLOCK:
case
CXt_NULL:
case
CXt_DEFER:
break
;
case
CXt_FORMAT:
cx_popformat(cx);
break
;
}
if
(cxstack_ix == cxix + 1) {
cx_popblock(cx);
}
cxstack_ix--;
}
}
void
Perl_rpp_obliterate_stack_to(pTHX_ I32 ix)
{
#ifdef PERL_RC_STACK
I32 nonrc_base = PL_curstackinfo->si_stack_nonrc_base;
assert
(ix >= 0);
assert
(ix <= PL_stack_sp - PL_stack_base);
assert
(nonrc_base <= PL_stack_sp - PL_stack_base + 1);
if
(nonrc_base && nonrc_base > ix) {
PL_stack_sp = PL_stack_base + nonrc_base - 1;
PL_curstackinfo->si_stack_nonrc_base = 0;
}
if
(rpp_stack_is_rc())
rpp_popfree_to(PL_stack_base + ix);
else
PL_stack_sp = PL_stack_base + ix;
#else
PL_stack_sp = PL_stack_base + ix;
#endif
}
void
Perl_qerror(pTHX_ SV *err)
{
PERL_ARGS_ASSERT_QERROR;
if
(err!=NULL) {
if
(PL_in_eval) {
if
(PL_in_eval & EVAL_KEEPERR) {
Perl_ck_warner(aTHX_ packWARN(WARN_MISC),
"\t(in cleanup) %"
SVf,
SVfARG(err));
}
else
{
sv_catsv(ERRSV, err);
}
}
else
if
(PL_errors)
sv_catsv(PL_errors, err);
else
Perl_warn(aTHX_
"%"
SVf, SVfARG(err));
if
(PL_parser) {
++PL_parser->error_count;
}
}
if
( PL_parser && (err == NULL ||
PL_parser->error_count >= PERL_STOP_PARSING_AFTER_N_ERRORS)
) {
const
char
*
const
name = OutCopFILE(PL_curcop);
SV * errsv = NULL;
U8 raw_error_count = PERL_PARSE_ERROR_COUNT(PL_parser->error_count);
if
(PL_in_eval) {
errsv = ERRSV;
}
if
(err == NULL) {
abort_execution(errsv, name);
}
else
if
(raw_error_count >= PERL_STOP_PARSING_AFTER_N_ERRORS) {
if
(errsv) {
Perl_croak(aTHX_
"%"
SVf
"%s has too many errors.\n"
,
SVfARG(errsv), name);
}
else
{
Perl_croak(aTHX_
"%s has too many errors.\n"
, name);
}
}
}
}
static
void
S_pop_eval_context_maybe_croak(pTHX_ PERL_CONTEXT *cx, SV *errsv,
int
action)
{
SV *namesv = NULL;
bool
do_croak;
CX_LEAVE_SCOPE(cx);
do_croak = action && (CxOLD_OP_TYPE(cx) == OP_REQUIRE);
if
(do_croak) {
namesv = cx->blk_eval.old_namesv;
cx->blk_eval.old_namesv = NULL;
sv_2mortal(namesv);
}
cx_popeval(cx);
cx_popblock(cx);
CX_POP(cx);
if
(do_croak) {
const
char
*fmt;
HV *inc_hv = GvHVn(PL_incgv);
if
(action == 1) {
(
void
)hv_delete_ent(inc_hv, namesv, G_DISCARD, 0);
fmt =
"%"
SVf
" did not return a true value"
;
errsv = namesv;
}
else
{
(
void
)hv_store_ent(inc_hv, namesv, &PL_sv_undef, 0);
fmt =
"%"
SVf
"Compilation failed in require"
;
if
(!errsv)
errsv = newSVpvs_flags(
"Unknown error\n"
, SVs_TEMP);
}
Perl_croak(aTHX_ fmt, SVfARG(errsv));
}
}
void
Perl_die_unwind(pTHX_ SV *msv)
{
SV *exceptsv = msv;
U8 in_eval = PL_in_eval;
PERL_ARGS_ASSERT_DIE_UNWIND;
if
(in_eval) {
I32 cxix;
if
(PL_phase == PERL_PHASE_DESTRUCT) {
exceptsv = sv_mortalcopy(exceptsv);
}
else
{
exceptsv = sv_2mortal(SvREFCNT_inc_simple_NN(exceptsv));
}
if
(!(in_eval & EVAL_KEEPERR)) {
SANE_ERRSV();
sv_setsv_flags(ERRSV, exceptsv,
(SV_GMAGIC|SV_DO_COW_SVSETSV|SV_NOSTEAL));
}
if
(in_eval & EVAL_KEEPERR) {
Perl_ck_warner(aTHX_ packWARN(WARN_MISC),
"\t(in cleanup) %"
SVf,
SVfARG(exceptsv));
}
while
((cxix = dopoptoeval(cxstack_ix)) < 0
&& PL_curstackinfo->si_prev)
{
dounwind(-1);
rpp_obliterate_stack_to(0);
POPSTACK;
}
if
(cxix >= 0) {
PERL_CONTEXT *cx;
U8 gimme;
JMPENV *restartjmpenv;
OP *restartop;
if
(cxix < cxstack_ix)
dounwind(cxix);
cx = CX_CUR();
assert
(CxTYPE(cx) == CXt_EVAL);
rpp_obliterate_stack_to(cx->blk_oldsp);
gimme = cx->blk_gimme;
if
(gimme == G_SCALAR)
rpp_xpush_IMM(&PL_sv_undef);
restartjmpenv = cx->blk_eval.cur_top_env;
restartop = cx->blk_eval.retop;
SAVEFREESV(SvREFCNT_inc_simple_NN(exceptsv));
FREETMPS;
sv_2mortal(SvREFCNT_inc_simple_NN(exceptsv));
S_pop_eval_context_maybe_croak(aTHX_ cx, exceptsv, 2);
if
(!(in_eval & EVAL_KEEPERR)) {
SANE_ERRSV();
sv_setsv(ERRSV, exceptsv);
}
PL_restartjmpenv = restartjmpenv;
PL_restartop = restartop;
JMPENV_JUMP(3);
NOT_REACHED;
}
}
write_to_stderr(exceptsv);
my_failure_exit();
NOT_REACHED;
}
PP(pp_xor)
{
SV *left = PL_stack_sp[0];
SV *right = PL_stack_sp[-1];
rpp_replace_2_IMM_NN(SvTRUE_NN(left) != SvTRUE_NN(right)
? &PL_sv_yes
: &PL_sv_no);
return
NORMAL;
}
const
PERL_CONTEXT *
Perl_caller_cx(pTHX_ I32 count,
const
PERL_CONTEXT **dbcxp)
{
I32 cxix = dopopto_cursub();
const
PERL_CONTEXT *cx;
const
PERL_CONTEXT *ccstack = cxstack;
const
PERL_SI *top_si = PL_curstackinfo;
for
(;;) {
while
(cxix < 0 && top_si->si_type != PERLSI_MAIN) {
top_si = top_si->si_prev;
ccstack = top_si->si_cxstack;
cxix = dopoptosub_at(ccstack, top_si->si_cxix);
}
if
(cxix < 0)
return
NULL;
if
(PL_DBsub && GvCV(PL_DBsub) && cxix >= 0 &&
ccstack[cxix].blk_sub.cv == GvCV(PL_DBsub))
count++;
if
(!count--)
break
;
cxix = dopoptosub_at(ccstack, cxix - 1);
}
cx = &ccstack[cxix];
if
(dbcxp) *dbcxp = cx;
if
(CxTYPE(cx) == CXt_SUB || CxTYPE(cx) == CXt_FORMAT) {
const
I32 dbcxix = dopoptosub_at(ccstack, cxix - 1);
if
(PL_DBsub && GvCV(PL_DBsub) && dbcxix >= 0 && ccstack[dbcxix].blk_sub.cv == GvCV(PL_DBsub))
cx = &ccstack[dbcxix];
}
return
cx;
}
PP_wrapped(pp_caller, MAXARG, 0)
{
dSP;
const
PERL_CONTEXT *cx;
const
PERL_CONTEXT *dbcx;
U8 gimme = GIMME_V;
const
HEK *stash_hek;
I32 count = 0;
bool
has_arg = MAXARG && TOPs;
const
COP *lcop;
if
(MAXARG) {
if
(has_arg)
count = POPi;
else
(
void
)POPs;
}
cx = caller_cx(count + cBOOL(PL_op->op_private & OPpOFFBYONE), &dbcx);
if
(!cx) {
if
(gimme != G_LIST) {
EXTEND(SP, 1);
RETPUSHUNDEF;
}
RETURN;
}
if
(CxTYPE(cx) == CXt_SUB && CxHASARGS(cx)
&& CopSTASH_eq(PL_curcop, PL_debstash))
{
AV *
const
ary = MUTABLE_AV(AvARRAY(MUTABLE_AV(
PadlistARRAY(CvPADLIST(cx->blk_sub.cv))[
cx->blk_sub.olddepth+1]))[0]);
const
SSize_t off = AvARRAY(ary) - AvALLOC(ary);
Perl_init_dbargs(aTHX);
if
(AvMAX(PL_dbargs) < AvFILLp(ary) + off)
av_extend(PL_dbargs, AvFILLp(ary) + off);
for
(SSize_t i = AvFILLp(ary) + off; i >= 0; i--) {
SV* sv = AvALLOC(ary)[i];
if
(sv && (SvREFCNT(sv) == 0 || SvIS_FREED(sv)))
sv = NULL;
AvARRAY(PL_dbargs)[i] = sv;
}
AvFILLp(PL_dbargs) = AvFILLp(ary) + off;
}
CX_DEBUG(cx,
"CALLER"
);
assert
(CopSTASH(cx->blk_oldcop));
stash_hek = SvTYPE(CopSTASH(cx->blk_oldcop)) == SVt_PVHV
? HvNAME_HEK((HV*)CopSTASH(cx->blk_oldcop))
: NULL;
if
(gimme != G_LIST) {
EXTEND(SP, 1);
if
(!stash_hek)
PUSHs(&PL_sv_undef);
else
{
dTARGET;
sv_sethek(TARG, stash_hek);
PUSHs(TARG);
}
RETURN;
}
EXTEND(SP, 11);
if
(!stash_hek)
PUSHs(&PL_sv_undef);
else
{
dTARGET;
sv_sethek(TARG, stash_hek);
PUSHTARG;
}
mPUSHs(newSVpv(OutCopFILE(cx->blk_oldcop), 0));
lcop = closest_cop(cx->blk_oldcop, OpSIBLING(cx->blk_oldcop),
cx->blk_sub.retop, TRUE);
if
(!lcop)
lcop = cx->blk_oldcop;
mPUSHu(CopLINE(lcop));
if
(!has_arg)
RETURN;
if
(CxTYPE(cx) == CXt_SUB || CxTYPE(cx) == CXt_FORMAT) {
if
(CvHASGV(dbcx->blk_sub.cv)) {
PUSHs(cv_name(dbcx->blk_sub.cv, 0, 0));
PUSHs(boolSV(CxHASARGS(cx)));
}
else
{
PUSHs(newSVpvs_flags(
"(unknown)"
, SVs_TEMP));
PUSHs(boolSV(CxHASARGS(cx)));
}
}
else
{
PUSHs(newSVpvs_flags(
"(eval)"
, SVs_TEMP));
PUSHs(&PL_sv_zero);
}
gimme = cx->blk_gimme;
if
(gimme == G_VOID)
PUSHs(&PL_sv_undef);
else
PUSHs(boolSV((gimme & G_WANT) == G_LIST));
if
(CxTYPE(cx) == CXt_EVAL) {
if
(CxOLD_OP_TYPE(cx) == OP_ENTEREVAL) {
SV *cur_text = cx->blk_eval.cur_text;
if
(SvCUR(cur_text) >= 2) {
PUSHs(newSVpvn_flags(SvPVX(cur_text), SvCUR(cur_text)-2,
SvUTF8(cur_text)|SVs_TEMP));
}
else
{
PUSHs(sv_2mortal(newSVsv(cur_text)));
}
PUSHs(&PL_sv_no);
}
else
if
(cx->blk_eval.old_namesv) {
mPUSHs(newSVsv(cx->blk_eval.old_namesv));
PUSHs(&PL_sv_yes);
}
else
{
PUSHs(&PL_sv_undef);
PUSHs(&PL_sv_undef);
}
}
else
{
PUSHs(&PL_sv_undef);
PUSHs(&PL_sv_undef);
}
mPUSHi(CopHINTS_get(cx->blk_oldcop));
{
SV * mask ;
char
*old_warnings = cx->blk_oldcop->cop_warnings;
if
(old_warnings == pWARN_NONE)
mask = newSVpvn(WARN_NONEstring, WARNsize) ;
else
if
(old_warnings == pWARN_STD && (PL_dowarn & G_WARN_ON) == 0)
mask = &PL_sv_undef ;
else
if
(old_warnings == pWARN_ALL ||
(old_warnings == pWARN_STD && PL_dowarn & G_WARN_ON)) {
mask = newSVpvn(WARN_ALLstring, WARNsize) ;
}
else
mask = newSVpvn(old_warnings, RCPV_LEN(old_warnings));
mPUSHs(mask);
}
PUSHs(cx->blk_oldcop->cop_hints_hash ?
sv_2mortal(newRV_noinc(MUTABLE_SV(cop_hints_2hv(cx->blk_oldcop, 0))))
: &PL_sv_undef);
RETURN;
}
PP_wrapped(pp_reset, MAXARG, 0)
{
dSP;
const
char
* tmps;
STRLEN len = 0;
if
(MAXARG < 1 || (!TOPs && !POPs)) {
EXTEND(SP, 1);
tmps = NULL, len = 0;
}
else
tmps = SvPVx_const(POPs, len);
sv_resetpvn(tmps, len, CopSTASH(PL_curcop));
PUSHs(&PL_sv_yes);
RETURN;
}
PP(pp_dbstate)
{
PL_curcop = (COP*)PL_op;
TAINT_NOT;
rpp_popfree_to_NN(PL_stack_base + CX_CUR()->blk_oldsp);
FREETMPS;
PERL_ASYNC_CHECK();
if
(PL_op->op_flags & OPf_SPECIAL
|| PL_DBsingle_iv || PL_DBsignal_iv || PL_DBtrace_iv)
{
PERL_CONTEXT *cx;
const
U8 gimme = G_LIST;
GV *
const
gv = PL_DBgv;
CV * cv = NULL;
if
(gv && isGV_with_GP(gv))
cv = GvCV(gv);
if
(!cv || (!CvROOT(cv) && !CvXSUB(cv)))
DIE(aTHX_
"No DB::DB routine defined"
);
if
(CvDEPTH(cv) >= 1 && !(PL_debug & DEBUG_DB_RECURSE_FLAG))
return
NORMAL;
if
(CvISXSUB(cv)) {
ENTER;
SAVEI32(PL_debug);
PL_debug = 0;
#ifndef PERL_RC_STACK
SAVESTACK_POS();
#endif
SAVETMPS;
PUSHMARK(PL_stack_sp);
rpp_invoke_xs(cv);
FREETMPS;
LEAVE;
return
NORMAL;
}
else
{
#ifdef PERL_RC_STACK
assert
(!PL_curstackinfo->si_stack_nonrc_base);
#endif
cx = cx_pushblock(CXt_SUB, gimme, PL_stack_sp, PL_savestack_ix);
cx_pushsub(cx, cv, PL_op->op_next, 0);
cx->blk_u16 = 0;
SAVEI32(PL_debug);
PL_debug = 0;
#ifndef PERL_RC_STACK
SAVESTACK_POS();
#endif
CvDEPTH(cv)++;
if
(CvDEPTH(cv) >= 2)
pad_push(CvPADLIST(cv), CvDEPTH(cv));
PAD_SET_CUR_NOSAVE(CvPADLIST(cv), CvDEPTH(cv));
return
CvSTART(cv);
}
}
else
return
NORMAL;
}
PP(pp_enter)
{
U8 gimme = GIMME_V;
(
void
)cx_pushblock(CXt_BLOCK, gimme, PL_stack_sp, PL_savestack_ix);
return
NORMAL;
}
PP(pp_leave)
{
PERL_CONTEXT *cx;
SV **oldsp;
U8 gimme;
cx = CX_CUR();
assert
(CxTYPE(cx) == CXt_BLOCK);
if
(PL_op->op_flags & OPf_SPECIAL)
cx->blk_oldpm = PL_curpm;
oldsp = PL_stack_base + cx->blk_oldsp;
gimme = cx->blk_gimme;
if
(gimme == G_VOID)
rpp_popfree_to_NN(oldsp);
else
leave_adjust_stacks(oldsp, oldsp, gimme,
PL_op->op_private & OPpLVALUE ? 3 : 1);
CX_LEAVE_SCOPE(cx);
cx_popblock(cx);
CX_POP(cx);
return
NORMAL;
}
static
bool
S_outside_integer(pTHX_ SV *sv)
{
if
(SvOK(sv)) {
const
NV nv = SvNV_nomg(sv);
if
(Perl_isinfnan(nv))
return
TRUE;
#ifdef NV_PRESERVES_UV
if
(nv < (NV)IV_MIN || nv > (NV)IV_MAX)
return
TRUE;
#else
if
(nv <= (NV)IV_MIN)
return
TRUE;
if
((nv > 0) &&
((nv > (NV)UV_MAX ||
SvUV_nomg(sv) > (UV)IV_MAX)))
return
TRUE;
#endif
}
return
FALSE;
}
PP(pp_enteriter)
{
dMARK;
PERL_CONTEXT *cx;
const
U8 gimme = GIMME_V;
void
*itervarp;
SV *itersave;
U8 cxflags = 0;
if
(PL_op->op_targ) {
itervarp = &PAD_SVl(PL_op->op_targ);
itersave = *(SV**)itervarp;
assert
(itersave);
if
(PL_op->op_private & OPpLVAL_INTRO) {
SvPADSTALE_on(itersave);
}
SvREFCNT_inc_simple_void_NN(itersave);
cxflags = CXp_FOR_PAD;
}
else
{
SV *
const
sv = *PL_stack_sp;
itervarp = (
void
*)sv;
if
(LIKELY(isGV(sv))) {
itersave = GvSV(sv);
SvREFCNT_inc_simple_void(itersave);
cxflags = CXp_FOR_GV;
if
(PL_op->op_private & OPpITER_DEF)
cxflags |= CXp_FOR_DEF;
}
else
{
assert
(SvTYPE(sv) == SVt_PVMG);
assert
(SvMAGIC(sv));
assert
(SvMAGIC(sv)->mg_type == PERL_MAGIC_lvref);
itersave = NULL;
cxflags = CXp_FOR_LVREF;
}
(
void
)rpp_pop_1_norc();
}
assert
((cxflags & CXp_FOR_GV) || !(PL_op->op_private & OPpITER_DEF));
cx = cx_pushblock(cxflags, gimme, MARK, PL_savestack_ix);
cx_pushloop_for(cx, itervarp, itersave);
if
(PL_op->op_flags & OPf_STACKED) {
SV *maybe_ary = *PL_stack_sp;
if
(SvTYPE(maybe_ary) != SVt_PVAV) {
SV* sv = PL_stack_sp[-1];
SV *
const
right = maybe_ary;
if
(UNLIKELY(cxflags & CXp_FOR_LVREF))
DIE(aTHX_
"Assigned value is not a reference"
);
SvGETMAGIC(sv);
SvGETMAGIC(right);
if
(RANGE_IS_NUMERIC(sv,right)) {
cx->cx_type |= CXt_LOOP_LAZYIV;
if
(S_outside_integer(aTHX_ sv) ||
S_outside_integer(aTHX_ right))
DIE(aTHX_
"Range iterator outside integer range"
);
cx->blk_loop.state_u.lazyiv.cur = SvIV_nomg(sv);
cx->blk_loop.state_u.lazyiv.end = SvIV_nomg(right);
rpp_popfree_2_NN();
}
else
{
cx->cx_type |= CXt_LOOP_LAZYSV;
cx->blk_loop.state_u.lazysv.cur = newSVsv(sv);
cx->blk_loop.state_u.lazysv.end = right;
(
void
)rpp_pop_1_norc();
rpp_popfree_1_NN();
(
void
) SvPV_force_nolen(cx->blk_loop.state_u.lazysv.cur);
(
void
) SvPV_nolen_const(right);
if
(!SvOK(right)) {
SvREFCNT_dec(right);
cx->blk_loop.state_u.lazysv.end = &PL_sv_no;
}
}
}
else
{
cx->cx_type |= CXt_LOOP_ARY;
cx->blk_loop.state_u.ary.ary = MUTABLE_AV(maybe_ary);
(
void
)rpp_pop_1_norc();
cx->blk_loop.state_u.ary.ix =
(PL_op->op_private & OPpITER_REVERSED) ?
AvFILL(cx->blk_loop.state_u.ary.ary) + 1 :
-1;
}
}
else
{
cx->cx_type |= CXt_LOOP_LIST;
cx->blk_oldsp = PL_stack_sp - PL_stack_base;
cx->blk_loop.state_u.stack.basesp = MARK - PL_stack_base;
cx->blk_loop.state_u.stack.ix =
(PL_op->op_private & OPpITER_REVERSED)
? cx->blk_oldsp + 1
: cx->blk_loop.state_u.stack.basesp;
rpp_extend(1);
}
return
NORMAL;
}
PP(pp_enterloop)
{
PERL_CONTEXT *cx;
const
U8 gimme = GIMME_V;
cx = cx_pushblock(CXt_LOOP_PLAIN, gimme, PL_stack_sp, PL_savestack_ix);
cx_pushloop_plain(cx);
return
NORMAL;
}
PP(pp_leaveloop)
{
PERL_CONTEXT *cx;
U8 gimme;
SV **base;
SV **oldsp;
cx = CX_CUR();
assert
(CxTYPE_is_LOOP(cx));
oldsp = PL_stack_base + cx->blk_oldsp;
base = CxTYPE(cx) == CXt_LOOP_LIST
? PL_stack_base + cx->blk_loop.state_u.stack.basesp
: oldsp;
gimme = cx->blk_gimme;
if
(gimme == G_VOID)
rpp_popfree_to_NN(base);
else
leave_adjust_stacks(oldsp, base, gimme,
PL_op->op_private & OPpLVALUE ? 3 : 1);
CX_LEAVE_SCOPE(cx);
cx_poploop(cx);
cx_popblock(cx);
CX_POP(cx);
return
NORMAL;
}
PP(pp_leavesublv)
{
U8 gimme;
PERL_CONTEXT *cx;
SV **oldsp;
OP *retop;
cx = CX_CUR();
assert
(CxTYPE(cx) == CXt_SUB);
if
(CxMULTICALL(cx)) {
assert
(PL_stack_sp > PL_stack_base || *PL_stack_base == &PL_sv_undef);
return
0;
}
gimme = cx->blk_gimme;
oldsp = PL_stack_base + cx->blk_oldsp;
if
(gimme == G_VOID)
rpp_popfree_to_NN(oldsp);
else
{
U8 lval = CxLVAL(cx);
bool
is_lval = (lval && !(lval & OPpENTERSUB_INARGS));
const
char
*what = NULL;
if
(gimme == G_SCALAR) {
if
(is_lval) {
if
(oldsp < PL_stack_sp) {
SV *sv = *PL_stack_sp;
if
((SvPADTMP(sv) || SvREADONLY(sv))) {
what =
SvREADONLY(sv) ? (sv == &PL_sv_undef) ?
"undef"
:
"a readonly value"
:
"a temporary"
;
}
else
goto
ok;
}
else
{
what =
"undef"
;
}
croak:
Perl_croak(aTHX_
"Can't return %s from lvalue subroutine"
, what);
}
ok:
leave_adjust_stacks(oldsp, oldsp, gimme, is_lval ? 3 : 2);
if
(lval & OPpDEREF) {
SvGETMAGIC(*PL_stack_sp);
if
(!SvOK(*PL_stack_sp)) {
SV *sv = vivify_ref(*PL_stack_sp, CxLVAL(cx) & OPpDEREF);
rpp_replace_1_1_NN(sv);
}
}
}
else
{
assert
(gimme == G_LIST);
assert
(!(lval & OPpDEREF));
if
(is_lval) {
SV **p;
for
(p = PL_stack_sp; p > oldsp; p--) {
SV *sv = *p;
if
(sv != &PL_sv_undef && (SvPADTMP(sv) || SvREADONLY(sv)))
{
what = SvREADONLY(sv)
?
"a readonly value"
:
"a temporary"
;
goto
croak;
}
}
}
leave_adjust_stacks(oldsp, oldsp, gimme, is_lval ? 3 : 2);
}
}
CX_LEAVE_SCOPE(cx);
cx_popsub(cx);
cx_popblock(cx);
retop = cx->blk_sub.retop;
CX_POP(cx);
return
retop;
}
static
const
char
*S_defer_blockname(PERL_CONTEXT *cx)
{
return
(cx->cx_type & CXp_FINALLY) ?
"finally"
:
"defer"
;
}
PP(pp_return)
{
dMARK;
PERL_CONTEXT *cx;
I32 cxix = dopopto_cursub();
assert
(cxstack_ix >= 0);
if
(cxix < cxstack_ix) {
I32 i;
for
(i = cxstack_ix; i > cxix; i--) {
if
(CxTYPE(&cxstack[i]) == CXt_DEFER)
Perl_croak(aTHX_
"Can't \"%s\" out of a \"%s\" block"
,
"return"
, S_defer_blockname(&cxstack[i]));
}
if
(cxix < 0) {
if
(!( PL_curstackinfo->si_type == PERLSI_SORT
|| ( PL_curstackinfo->si_type == PERLSI_MULTICALL
&& (cxstack[0].cx_type & CXp_SUB_RE_FAKE))
)
)
DIE(aTHX_
"Can't return outside a subroutine"
);
assert
(CxTYPE(&cxstack[0]) == CXt_NULL
|| ( CxTYPE(&cxstack[0]) == CXt_SUB
&& (cxstack[0].cx_type & CXp_SUB_RE_FAKE)));
if
(cxstack_ix > 0) {
SV *sv = *PL_stack_sp;
assert
(cxstack[0].blk_gimme == G_SCALAR);
if
( (PL_stack_sp != PL_stack_base)
&& !(SvFLAGS(sv) & (SVs_TEMP|SVs_PADTMP))
)
#ifdef PERL_RC_STACK
rpp_replace_at_norc(PL_stack_sp, newSVsv(sv));
#else
*PL_stack_sp = sv_mortalcopy(sv);
#endif
dounwind(0);
}
return
0;
}
cx = &cxstack[cxix];
if
(cx->blk_gimme != G_VOID)
leave_adjust_stacks(MARK, PL_stack_base + cx->blk_oldsp,
cx->blk_gimme,
CxTYPE(cx) == CXt_SUB && CvLVALUE(cx->blk_sub.cv)
? 3 : 0);
dounwind(cxix);
cx = &cxstack[cxix];
}
else
{
SV **oldsp;
cx = &cxstack[cxix];
oldsp = PL_stack_base + cx->blk_oldsp;
if
(oldsp != MARK) {
SSize_t nargs = PL_stack_sp - MARK;
if
(nargs) {
if
(cx->blk_gimme == G_LIST) {
#ifdef PERL_RC_STACK
SV **p;
for
(p = MARK; p > oldsp; p--) {
SV *sv = *p;
*p = NULL;
SvREFCNT_dec(sv);
}
#endif
Move(MARK + 1, oldsp + 1, nargs, SV*);
PL_stack_sp = oldsp + nargs;
}
}
else
rpp_popfree_to_NN(oldsp);
}
}
switch
(CxTYPE(cx)) {
case
CXt_EVAL:
return
CxEVALBLOCK(cx)
? Perl_pp_leavetry(aTHX)
: Perl_pp_leaveeval(aTHX);
case
CXt_SUB:
return
CvLVALUE(cx->blk_sub.cv)
? Perl_pp_leavesublv(aTHX)
: Perl_pp_leavesub(aTHX);
case
CXt_FORMAT:
return
Perl_pp_leavewrite(aTHX);
default
:
DIE(aTHX_
"panic: return, type=%u"
, (unsigned) CxTYPE(cx));
}
}
static
PERL_CONTEXT *
S_unwind_loop(pTHX)
{
I32 cxix;
if
(PL_op->op_flags & OPf_SPECIAL) {
cxix = dopoptoloop(cxstack_ix);
if
(cxix < 0)
Perl_croak(aTHX_
"Can't \"%s\" outside a loop block"
,
OP_NAME(PL_op));
}
else
{
STRLEN label_len;
const
char
* label;
U32 label_flags;
SV *sv;
if
(PL_op->op_flags & OPf_STACKED) {
sv = *PL_stack_sp;
label = SvPV(sv, label_len);
label_flags = SvUTF8(sv);
}
else
{
sv = NULL;
label = cPVOP->op_pv;
label_len =
strlen
(label);
label_flags = (cPVOP->op_private & OPpPV_IS_UTF8) ? SVf_UTF8 : 0;
}
cxix = dopoptolabel(label, label_len, label_flags);
if
(cxix < 0)
Perl_croak(aTHX_
"Label not found for \"%s %"
SVf
"\""
,
OP_NAME(PL_op),
SVfARG(PL_op->op_flags & OPf_STACKED
&& !SvGMAGICAL(sv)
? sv
: newSVpvn_flags(label,
label_len,
label_flags | SVs_TEMP)));
if
(PL_op->op_flags & OPf_STACKED)
rpp_popfree_1_NN();
}
if
(cxix < cxstack_ix) {
I32 i;
for
(i = cxstack_ix; i > cxix; i--) {
if
(CxTYPE(&cxstack[i]) == CXt_DEFER)
Perl_croak(aTHX_
"Can't \"%s\" out of a \"%s\" block"
,
OP_NAME(PL_op), S_defer_blockname(&cxstack[i]));
}
dounwind(cxix);
}
return
&cxstack[cxix];
}
PP(pp_last)
{
PERL_CONTEXT *cx;
OP* nextop;
cx = S_unwind_loop(aTHX);
assert
(CxTYPE_is_LOOP(cx));
rpp_popfree_to_NN(PL_stack_base
+ (CxTYPE(cx) == CXt_LOOP_LIST
? cx->blk_loop.state_u.stack.basesp
: cx->blk_oldsp
));
TAINT_NOT;
CX_LEAVE_SCOPE(cx);
cx_poploop(cx);
cx_popblock(cx);
nextop = cx->blk_loop.my_op->op_lastop->op_next;
CX_POP(cx);
return
nextop;
}
PP(pp_next)
{
PERL_CONTEXT *cx;
cx = CX_CUR();
if
(!((PL_op->op_flags & OPf_SPECIAL) && CxTYPE_is_LOOP(cx)))
cx = S_unwind_loop(aTHX);
cx_topblock(cx);
PL_curcop = cx->blk_oldcop;
PERL_ASYNC_CHECK();
return
(cx)->blk_loop.my_op->op_nextop;
}
PP(pp_redo)
{
PERL_CONTEXT *cx = S_unwind_loop(aTHX);
OP* redo_op = cx->blk_loop.my_op->op_redoop;
if
(redo_op->op_type == OP_ENTER) {
cxstack_ix++;
cx = CX_CUR();
assert
(CxTYPE(cx) == CXt_BLOCK);
redo_op = redo_op->op_next;
}
FREETMPS;
CX_LEAVE_SCOPE(cx);
cx_topblock(cx);
PL_curcop = cx->blk_oldcop;
PERL_ASYNC_CHECK();
return
redo_op;
}
#define UNENTERABLE (OP *)1
#define GOTO_DEPTH 64
STATIC OP *
S_dofindlabel(pTHX_ OP *o,
const
char
*label, STRLEN len, U32 flags, OP **opstack, OP **oplimit)
{
OP **ops = opstack;
static
const
char
*
const
too_deep =
"Target of goto is too deeply nested"
;
PERL_ARGS_ASSERT_DOFINDLABEL;
if
(ops >= oplimit)
Perl_croak(aTHX_
"%s"
, too_deep);
if
(o->op_type == OP_LEAVE ||
o->op_type == OP_SCOPE ||
o->op_type == OP_LEAVELOOP ||
o->op_type == OP_LEAVESUB ||
o->op_type == OP_LEAVETRY ||
o->op_type == OP_LEAVEGIVEN)
{
*ops++ = cUNOPo->op_first;
}
else
if
(oplimit - opstack < GOTO_DEPTH) {
if
(o->op_flags & OPf_KIDS
&& cUNOPo->op_first->op_type == OP_PUSHMARK) {
*ops++ = UNENTERABLE;
}
else
if
(o->op_flags & OPf_KIDS && PL_opargs[o->op_type]
&& OP_CLASS(o) != OA_LOGOP
&& o->op_type != OP_LINESEQ
&& o->op_type != OP_SREFGEN
&& o->op_type != OP_ENTEREVAL
&& o->op_type != OP_GLOB
&& o->op_type != OP_RV2CV) {
OP *
const
kid = cUNOPo->op_first;
if
(OP_GIMME(kid, 0) != G_SCALAR || OpHAS_SIBLING(kid))
*ops++ = UNENTERABLE;
}
}
if
(ops >= oplimit)
Perl_croak(aTHX_
"%s"
, too_deep);
*ops = 0;
if
(o->op_flags & OPf_KIDS) {
OP *kid;
OP *
const
kid1 = cUNOPo->op_first;
for
(kid = cUNOPo->op_first; kid; kid = OpSIBLING(kid)) {
if
(kid->op_type == OP_NEXTSTATE || kid->op_type == OP_DBSTATE) {
STRLEN kid_label_len;
U32 kid_label_flags;
const
char
*kid_label = CopLABEL_len_flags(kCOP,
&kid_label_len, &kid_label_flags);
if
(kid_label && (
( (kid_label_flags & SVf_UTF8) != (flags & SVf_UTF8) ) ?
(flags & SVf_UTF8)
? (bytes_cmp_utf8(
(
const
U8*)kid_label, kid_label_len,
(
const
U8*)label, len) == 0)
: (bytes_cmp_utf8(
(
const
U8*)label, len,
(
const
U8*)kid_label, kid_label_len) == 0)
: ( len == kid_label_len && ((kid_label == label)
|| memEQ(kid_label, label, len)))))
return
kid;
}
}
for
(kid = cUNOPo->op_first; kid; kid = OpSIBLING(kid)) {
bool
first_kid_of_binary = FALSE;
if
(kid == PL_lastgotoprobe)
continue
;
if
(kid->op_type == OP_NEXTSTATE || kid->op_type == OP_DBSTATE) {
if
(ops == opstack)
*ops++ = kid;
else
if
(ops[-1] != UNENTERABLE
&& (ops[-1]->op_type == OP_NEXTSTATE ||
ops[-1]->op_type == OP_DBSTATE))
ops[-1] = kid;
else
*ops++ = kid;
}
if
(kid == kid1 && ops != opstack && ops[-1] == UNENTERABLE) {
first_kid_of_binary = TRUE;
ops--;
}
if
((o = dofindlabel(kid, label, len, flags, ops, oplimit))) {
if
(kid->op_type == OP_PUSHDEFER)
Perl_croak(aTHX_
"Can't \"goto\" into a \"defer\" block"
);
return
o;
}
if
(first_kid_of_binary)
*ops++ = UNENTERABLE;
}
}
*ops = 0;
return
0;
}
static
void
S_check_op_type(pTHX_ OP *
const
o)
{
if
(o == UNENTERABLE)
Perl_croak(aTHX_
"Can't \"goto\" into a binary or list expression"
);
if
(o->op_type == OP_ENTERITER)
Perl_croak(aTHX_
"Can't \"goto\" into the middle of a foreach loop"
);
if
(o->op_type == OP_ENTERGIVEN)
Perl_croak(aTHX_
"Can't \"goto\" into a \"given\" block"
);
}
PP(pp_goto)
{
OP *retop = NULL;
I32 ix;
PERL_CONTEXT *cx;
OP *enterops[GOTO_DEPTH];
const
char
*label = NULL;
STRLEN label_len = 0;
U32 label_flags = 0;
const
bool
do_dump = (PL_op->op_type == OP_DUMP);
static
const
char
*
const
must_have_label =
"goto must have label"
;
if
(PL_op->op_flags & OPf_STACKED) {
SV *
const
sv = *PL_stack_sp;
SvGETMAGIC(sv);
if
(SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PVCV) {
I32 cxix;
PERL_CONTEXT *cx;
CV *cv = MUTABLE_CV(SvRV(sv));
AV *arg = GvAV(PL_defgv);
CV *old_cv = NULL;
while
(!CvROOT(cv) && !CvXSUB(cv)) {
const
GV *
const
gv = CvGV(cv);
if
(gv) {
GV *autogv;
SV *tmpstr;
if
(cv != GvCV(gv) && (cv = GvCV(gv)))
continue
;
autogv = gv_autoload_pvn(GvSTASH(gv), GvNAME(gv),
GvNAMELEN(gv),
GvNAMEUTF8(gv) ? SVf_UTF8 : 0);
if
(autogv && (cv = GvCV(autogv)))
continue
;
tmpstr = sv_newmortal();
gv_efullname3(tmpstr, gv, NULL);
DIE(aTHX_
"Goto undefined subroutine &%"
SVf, SVfARG(tmpstr));
}
DIE(aTHX_
"Goto undefined subroutine"
);
}
cxix = dopopto_cursub();
if
(cxix < 0) {
DIE(aTHX_
"Can't goto subroutine outside a subroutine"
);
}
cx = &cxstack[cxix];
if
(CxTYPE(cx) == CXt_EVAL) {
if
(CxREALEVAL(cx))
DIE(aTHX_
"Can't goto subroutine from an eval-string"
);
else
DIE(aTHX_
"Can't goto subroutine from an eval-block"
);
}
else
if
(CxMULTICALL(cx))
DIE(aTHX_
"Can't goto subroutine from a sort sub (or similar callback)"
);
for
(ix = cxstack_ix; ix > cxix; ix--) {
if
(CxTYPE(&cxstack[ix]) == CXt_DEFER)
Perl_croak(aTHX_
"Can't \"%s\" out of a \"%s\" block"
,
"goto"
, S_defer_blockname(&cxstack[ix]));
}
SvREFCNT_inc_simple_void(cv);
rpp_popfree_1_NN();
FREETMPS;
if
(cxix < cxstack_ix) {
dounwind(cxix);
}
cx = CX_CUR();
cx_topblock(cx);
if
(arg)
SvREFCNT_inc_NN(sv_2mortal(MUTABLE_SV(arg)));
assert
(PL_scopestack_ix == cx->blk_oldscopesp);
CX_LEAVE_SCOPE(cx);
if
(CxTYPE(cx) == CXt_SUB && CxHASARGS(cx)) {
AV* av = MUTABLE_AV(PAD_SVl(0));
assert
(AvARRAY(MUTABLE_AV(
PadlistARRAY(CvPADLIST(cx->blk_sub.cv))[
CvDEPTH(cx->blk_sub.cv)])) == PL_curpad);
if
(av != arg && !SvMAGICAL(av) && SvREFCNT(av) == 1
#ifndef PERL_RC_STACK
&& !AvREAL(av)
#endif
)
clear_defarray_simple(av);
else
clear_defarray(av, av == arg);
}
if
(!CvROOT(cv) && !CvXSUB(cv)) {
const
GV *
const
gv = CvGV(cv);
if
(gv) {
SV *
const
tmpstr = sv_newmortal();
gv_efullname3(tmpstr, gv, NULL);
DIE(aTHX_
"Goto undefined subroutine &%"
SVf,
SVfARG(tmpstr));
}
DIE(aTHX_
"Goto undefined subroutine"
);
}
if
(CxTYPE(cx) == CXt_SUB) {
CvDEPTH(cx->blk_sub.cv) = cx->blk_sub.olddepth;
if
(CvISXSUB(cv))
old_cv = cx->blk_sub.cv;
else
SvREFCNT_dec_NN(cx->blk_sub.cv);
}
if
(CvISXSUB(cv)) {
const
SSize_t items = arg ? AvFILL(arg) + 1 : 0;
const
bool
m = arg ? cBOOL(SvRMAGICAL(arg)) : 0;
SV** mark;
UNOP fake_goto_op;
ENTER;
SAVETMPS;
SAVEFREESV(cv);
if
(old_cv)
SAVEFREESV(old_cv);
if
(items)
rpp_extend(items + 1);
mark = PL_stack_sp;
if
(items) {
SSize_t index;
#ifdef PERL_RC_STACK
assert
(AvREAL(arg));
#else
bool
r = cBOOL(AvREAL(arg));
#endif
for
(index=0; index<items; index++)
{
SV *sv;
if
(m) {
SV **
const
svp = av_fetch(arg, index, 0);
sv = svp ? *svp : NULL;
}
else
sv = AvARRAY(arg)[index];
#ifdef PERL_RC_STACK
rpp_push_1(
sv
? sv
: newSVavdefelem(arg, index, 1)
);
#else
rpp_push_1(
sv
? (r ? SvREFCNT_inc_NN(sv_2mortal(sv)) : sv)
: sv_2mortal(newSVavdefelem(arg, index, 1))
);
#endif
}
}
if
(CxTYPE(cx) == CXt_SUB && CxHASARGS(cx)) {
CX_POP_SAVEARRAY(cx);
}
retop = cx->blk_sub.retop;
PL_comppad = cx->blk_sub.prevcomppad;
PL_curpad = LIKELY(PL_comppad) ? AvARRAY(PL_comppad) : NULL;
Copy(PL_op, &fake_goto_op, 1, UNOP);
fake_goto_op.op_flags =
(fake_goto_op.op_flags & ~OPf_WANT)
| (cx->blk_gimme & G_WANT);
PL_op = (OP*)&fake_goto_op;
PL_curcop = cx->blk_oldcop;
PL_curstackinfo->si_cxsubix = cx->blk_sub.old_cxsubix;
CX_POP(cx);
PUSHMARK(mark);
rpp_invoke_xs(cv);
LEAVE;
goto
finish;
}
else
{
PADLIST *
const
padlist = CvPADLIST(cv);
SAVEFREESV(cv);
cx->blk_sub.cv = cv;
cx->blk_sub.olddepth = CvDEPTH(cv);
CvDEPTH(cv)++;
SvREFCNT_inc_simple_void_NN(cv);
if
(CvDEPTH(cv) > 1) {
if
(CvDEPTH(cv) == PERL_SUB_DEPTH_WARN && ckWARN(WARN_RECURSION))
sub_crush_depth(cv);
pad_push(padlist, CvDEPTH(cv));
}
PL_curcop = cx->blk_oldcop;
PAD_SET_CUR_NOSAVE(padlist, CvDEPTH(cv));
if
(CxHASARGS(cx))
{
if
(arg) {
SvREFCNT_dec(PAD_SVl(0));
PAD_SVl(0) = (SV *)arg;
SvREFCNT_inc_simple_void_NN(arg);
}
if
(arg != GvAV(PL_defgv)) {
AV *
const
av = GvAV(PL_defgv);
GvAV(PL_defgv) = (AV *)SvREFCNT_inc_simple(arg);
SvREFCNT_dec(av);
}
}
if
(PERLDB_SUB) {
Perl_get_db_sub(aTHX_ NULL, cv);
if
(PERLDB_GOTO) {
CV *
const
gotocv = get_cvs(
"DB::goto"
, 0);
if
(gotocv) {
PUSHMARK( PL_stack_sp );
call_sv(MUTABLE_SV(gotocv), G_SCALAR | G_NODEBUG);
PL_stack_sp--;
}
}
}
retop = CvSTART(cv);
goto
finish;
}
}
else
{
SvREFCNT_inc_NN(sv);
sv_2mortal(sv);
rpp_popfree_1_NN();
label = SvPV_nomg_const(sv, label_len);
label_flags = SvUTF8(sv);
}
}
else
if
(!(PL_op->op_flags & OPf_SPECIAL)) {
label = cPVOP->op_pv;
label_flags = (cPVOP->op_private & OPpPV_IS_UTF8) ? SVf_UTF8 : 0;
label_len =
strlen
(label);
}
if
(!(do_dump || label_len)) DIE(aTHX_
"%s"
, must_have_label);
PERL_ASYNC_CHECK();
if
(label_len) {
OP *gotoprobe = NULL;
bool
leaving_eval = FALSE;
bool
in_block = FALSE;
bool
pseudo_block = FALSE;
PERL_CONTEXT *last_eval_cx = NULL;
PL_lastgotoprobe = NULL;
*enterops = 0;
for
(ix = cxstack_ix; ix >= 0; ix--) {
cx = &cxstack[ix];
switch
(CxTYPE(cx)) {
case
CXt_EVAL:
leaving_eval = TRUE;
if
(!CxEVALBLOCK(cx)) {
gotoprobe = (last_eval_cx ?
last_eval_cx->blk_eval.old_eval_root :
PL_eval_root);
last_eval_cx = cx;
break
;
}
case
CXt_LOOP_PLAIN:
case
CXt_LOOP_LAZYIV:
case
CXt_LOOP_LAZYSV:
case
CXt_LOOP_LIST:
case
CXt_LOOP_ARY:
case
CXt_GIVEN:
case
CXt_WHEN:
gotoprobe = OpSIBLING(cx->blk_oldcop);
break
;
case
CXt_SUBST:
continue
;
case
CXt_BLOCK:
if
(ix) {
gotoprobe = OpSIBLING(cx->blk_oldcop);
in_block = TRUE;
}
else
gotoprobe = PL_main_root;
break
;
case
CXt_SUB:
gotoprobe = CvROOT(cx->blk_sub.cv);
pseudo_block = cBOOL(CxMULTICALL(cx));
break
;
case
CXt_FORMAT:
case
CXt_NULL:
DIE(aTHX_
"Can't \"goto\" out of a pseudo block"
);
case
CXt_DEFER:
DIE(aTHX_
"Can't \"%s\" out of a \"%s\" block"
,
"goto"
, S_defer_blockname(cx));
default
:
if
(ix)
DIE(aTHX_
"panic: goto, type=%u, ix=%ld"
,
CxTYPE(cx), (
long
) ix);
gotoprobe = PL_main_root;
break
;
}
if
(gotoprobe) {
OP *sibl1, *sibl2;
retop = dofindlabel(gotoprobe, label, label_len, label_flags,
enterops, enterops + GOTO_DEPTH);
if
(retop)
break
;
if
( (sibl1 = OpSIBLING(gotoprobe)) &&
sibl1->op_type == OP_UNSTACK &&
(sibl2 = OpSIBLING(sibl1)))
{
retop = dofindlabel(sibl2,
label, label_len, label_flags, enterops,
enterops + GOTO_DEPTH);
if
(retop)
break
;
}
}
if
(pseudo_block)
DIE(aTHX_
"Can't \"goto\" out of a pseudo block"
);
PL_lastgotoprobe = gotoprobe;
}
if
(!retop)
DIE(aTHX_
"Can't find label %"
UTF8f,
UTF8fARG(label_flags, label_len, label));
if
(leaving_eval && *enterops && enterops[1]) {
I32 i;
for
(i = 1; enterops[i]; i++)
S_check_op_type(aTHX_ enterops[i]);
}
if
(*enterops && enterops[1]) {
I32 i = enterops[1] != UNENTERABLE
&& enterops[1]->op_type == OP_ENTER && in_block
? 2
: 1;
if
(enterops[i])
deprecate_fatal_in(WARN_DEPRECATED__GOTO_CONSTRUCT,
"5.42"
,
"Use of \"goto\" to jump into a construct"
);
}
if
(ix < cxstack_ix) {
if
(ix < 0)
DIE(aTHX_
"panic: docatch: illegal ix=%ld"
, (
long
)ix);
dounwind(ix);
cx = CX_CUR();
cx_topblock(cx);
}
if
(*enterops && enterops[1]) {
OP *
const
oldop = PL_op;
ix = enterops[1] != UNENTERABLE
&& enterops[1]->op_type == OP_ENTER && in_block
? 2
: 1;
for
(; enterops[ix]; ix++) {
PL_op = enterops[ix];
S_check_op_type(aTHX_ PL_op);
DEBUG_l( Perl_deb(aTHX_
"pp_goto: Entering %s\n"
,
OP_NAME(PL_op)));
PL_op->op_ppaddr(aTHX);
}
PL_op = oldop;
}
}
if
(do_dump) {
#ifdef VMS
if
(!retop) retop = PL_main_start;
#endif
PL_restartop = retop;
PL_do_undump = TRUE;
my_unexec();
PL_restartop = 0;
PL_do_undump = FALSE;
}
finish:
PERL_ASYNC_CHECK();
return
retop;
}
PP_wrapped(pp_exit, 1, 0)
{
dSP;
I32 anum;
if
(MAXARG < 1)
anum = 0;
else
if
(!TOPs) {
anum = 0; (
void
)POPs;
}
else
{
anum = SvIVx(POPs);
#ifdef VMS
if
(anum == 1
&& SvTRUE(cop_hints_fetch_pvs(PL_curcop,
"vmsish_exit"
, 0)))
anum = 0;
VMSISH_HUSHED =
VMSISH_HUSHED || (PL_curcop->op_private & OPpHUSH_VMSISH);
#endif
}
PL_exit_flags |= PERL_EXIT_EXPECTED;
my_exit(anum);
PUSHs(&PL_sv_undef);
RETURN;
}
STATIC
void
S_save_lines(pTHX_ AV *array, SV *sv)
{
const
char
*s = SvPVX_const(sv);
const
char
*
const
send = SvPVX_const(sv) + SvCUR(sv);
I32 line = 1;
PERL_ARGS_ASSERT_SAVE_LINES;
while
(s && s < send) {
const
char
*t;
SV *
const
tmpstr = newSV_type(SVt_PVMG);
t = (
const
char
*)
memchr
(s,
'\n'
, send - s);
if
(t)
t++;
else
t = send;
sv_setpvn_fresh(tmpstr, s, t - s);
av_store(array, line++, tmpstr);
s = t;
}
}
STATIC OP *
S_docatch(pTHX_ Perl_ppaddr_t firstpp)
{
int
ret;
OP *
const
oldop = PL_op;
dJMPENV;
assert
(CATCH_GET);
JMPENV_PUSH(ret);
assert
(!CATCH_GET);
switch
(ret) {
case
0:
PL_op = firstpp(aTHX);
redo_body:
if
(PL_op) {
CALLRUNOPS(aTHX);
}
break
;
case
3:
if
(PL_restartjmpenv == PL_top_env) {
if
(!PL_restartop)
break
;
PL_restartjmpenv = NULL;
PL_op = PL_restartop;
PL_restartop = 0;
goto
redo_body;
}
default
:
JMPENV_POP;
PL_op = oldop;
JMPENV_JUMP(ret);
NOT_REACHED;
}
JMPENV_POP;
PL_op = oldop;
return
NULL;
}
CV*
Perl_find_runcv(pTHX_ U32 *db_seqp)
{
return
Perl_find_runcv_where(aTHX_ 0, 0, db_seqp);
}
CV *
Perl_find_runcv_where(pTHX_ U8 cond, IV arg, U32 *db_seqp)
{
PERL_SI *si;
int
level = 0;
if
(db_seqp)
*db_seqp =
PL_curcop == &PL_compiling
? PL_cop_seqmax
: PL_curcop->cop_seq;
for
(si = PL_curstackinfo; si; si = si->si_prev) {
I32 ix;
for
(ix = si->si_cxix; ix >= 0; ix--) {
const
PERL_CONTEXT *cx = &(si->si_cxstack[ix]);
CV *cv = NULL;
if
(CxTYPE(cx) == CXt_SUB || CxTYPE(cx) == CXt_FORMAT) {
cv = cx->blk_sub.cv;
if
(db_seqp && PL_debstash && CvSTASH(cv) == PL_debstash) {
*db_seqp = cx->blk_oldcop->cop_seq;
continue
;
}
if
(cx->cx_type & CXp_SUB_RE)
continue
;
}
else
if
(CxTYPE(cx) == CXt_EVAL && !CxEVALBLOCK(cx))
cv = cx->blk_eval.cv;
if
(cv) {
switch
(cond) {
case
FIND_RUNCV_padid_eq:
if
(!CvPADLIST(cv)
|| CvPADLIST(cv)->xpadl_id != (U32)arg)
continue
;
return
cv;
case
FIND_RUNCV_level_eq:
if
(level++ != arg)
continue
;
default
:
return
cv;
}
}
}
}
return
cond == FIND_RUNCV_padid_eq ? NULL : PL_main_cv;
}
STATIC
int
S_try_yyparse(pTHX_
int
gramtype, OP *caller_op)
{
JMPENV *restartjmpenv = PL_restartjmpenv;
OP *restartop = PL_restartop;
dJMPENV;
int
ret;
PERL_UNUSED_ARG(caller_op);
assert
(CxTYPE(CX_CUR()) == CXt_EVAL);
JMPENV_PUSH(ret);
switch
(ret) {
case
0:
ret = yyparse(gramtype) ? 1 : 0;
break
;
case
3:
assert
(PL_restartop == caller_op->op_next);
PL_restartjmpenv = restartjmpenv;
PL_restartop = restartop;
break
;
default
:
JMPENV_POP;
JMPENV_JUMP(ret);
NOT_REACHED;
}
JMPENV_POP;
return
ret;
}
STATIC
int
S_try_run_unitcheck(pTHX_ OP* caller_op)
{
JMPENV *restartjmpenv = PL_restartjmpenv;
OP *restartop = PL_restartop;
dJMPENV;
int
ret;
PERL_UNUSED_ARG(caller_op);
assert
(CxTYPE(CX_CUR()) == CXt_EVAL);
JMPENV_PUSH(ret);
switch
(ret) {
case
0:
call_list(PL_scopestack_ix, PL_unitcheckav);
break
;
case
3:
assert
(PL_restartop == caller_op->op_next);
PL_restartjmpenv = restartjmpenv;
PL_restartop = restartop;
break
;
default
:
JMPENV_POP;
JMPENV_JUMP(ret);
NOT_REACHED;
}
JMPENV_POP;
return
ret;
}
STATIC
bool
S_doeval_compile(pTHX_ U8 gimme, CV* outside, U32 seq, HV *hh)
{
OP *
const
saveop = PL_op;
bool
clear_hints = saveop->op_type != OP_ENTEREVAL;
COP *
const
oldcurcop = PL_curcop;
bool
in_require = (saveop->op_type == OP_REQUIRE);
int
yystatus;
CV *evalcv;
PL_in_eval = (in_require
? (EVAL_INREQUIRE | (PL_in_eval & EVAL_INEVAL))
: (EVAL_INEVAL |
((PL_op->op_private & OPpEVAL_RE_REPARSING)
? EVAL_RE_REPARSING : 0)));
PUSHMARK(PL_stack_sp);
evalcv = MUTABLE_CV(newSV_type(SVt_PVCV));
CvEVAL_on(evalcv);
assert
(CxTYPE(CX_CUR()) == CXt_EVAL);
CX_CUR()->blk_eval.cv = evalcv;
CX_CUR()->blk_gimme = gimme;
CvOUTSIDE_SEQ(evalcv) = seq;
CvOUTSIDE(evalcv) = MUTABLE_CV(SvREFCNT_inc_simple(outside));
CvPADLIST_set(evalcv, pad_new(padnew_SAVE));
PL_op = NULL;
SAVEMORTALIZESV(evalcv);
if
(CopSTASH_ne(PL_curcop, PL_curstash)) {
SAVEGENERICSV(PL_curstash);
PL_curstash = (HV *)CopSTASH(PL_curcop);
if
(SvTYPE(PL_curstash) != SVt_PVHV) PL_curstash = NULL;
else
{
SvREFCNT_inc_simple_void(PL_curstash);
save_item(PL_curstname);
sv_sethek(PL_curstname, HvNAME_HEK(PL_curstash));
}
}
SAVESPTR(PL_beginav);
PL_beginav = newAV();
SAVEFREESV(PL_beginav);
SAVESPTR(PL_unitcheckav);
PL_unitcheckav = newAV();
SAVEFREESV(PL_unitcheckav);
ENTER_with_name(
"evalcomp"
);
SAVESPTR(PL_compcv);
PL_compcv = evalcv;
PL_eval_root = NULL;
PL_curcop = &PL_compiling;
if
((saveop->op_type != OP_REQUIRE) && (saveop->op_flags & OPf_SPECIAL))
PL_in_eval |= EVAL_KEEPERR;
else
CLEAR_ERRSV();
SAVEHINTS();
if
(clear_hints) {
PL_hints = HINTS_DEFAULT;
PL_prevailing_version = 0;
hv_clear(GvHV(PL_hintgv));
CLEARFEATUREBITS();
}
else
{
PL_hints = saveop->op_private & OPpEVAL_COPHH
? oldcurcop->cop_hints : (U32)saveop->op_targ;
PL_prevailing_version = 0;
if
(PL_in_eval & EVAL_RE_REPARSING)
PL_hints &= ~HINT_RE_EVAL;
if
(hh) {
SvREFCNT_dec(GvHV(PL_hintgv));
GvHV(PL_hintgv) = hh;
FETCHFEATUREBITSHH(hh);
const
U32 wasflags = SvFLAGS(hh);
SvMAGICAL_off(hh);
SV *versv;
if
((versv = hv_deletes(hh,
"CORE/prevailing_version"
, 0)) && SvOK(versv)) {
SAVEI16(PL_prevailing_version);
PL_prevailing_version = SvUV(versv);
}
SvFLAGS(hh) = wasflags;
}
}
SAVECOMPILEWARNINGS();
if
(clear_hints) {
if
(PL_dowarn & G_WARN_ALL_ON)
PL_compiling.cop_warnings = pWARN_ALL ;
else
if
(PL_dowarn & G_WARN_ALL_OFF)
PL_compiling.cop_warnings = pWARN_NONE ;
else
PL_compiling.cop_warnings = pWARN_STD ;
}
else
{
PL_compiling.cop_warnings =
DUP_WARNINGS(oldcurcop->cop_warnings);
cophh_free(CopHINTHASH_get(&PL_compiling));
if
(Perl_cop_fetch_label(aTHX_ oldcurcop, NULL, NULL)) {
PL_compiling.cop_hints_hash
= cophh_copy(oldcurcop->cop_hints_hash->refcounted_he_next);
assert
(Perl_cop_fetch_label(aTHX_ &PL_compiling, NULL, NULL) == NULL);
}
else
PL_compiling.cop_hints_hash = cophh_copy(oldcurcop->cop_hints_hash);
}
CALL_BLOCK_HOOKS(bhk_eval, saveop);
assert
(!CATCH_GET);
yystatus = (!in_require)
? S_try_yyparse(aTHX_ GRAMPROG, saveop)
: yyparse(GRAMPROG);
if
(yystatus || PL_parser->error_count || !PL_eval_root) {
PERL_CONTEXT *cx;
SV *errsv;
PL_op = saveop;
if
(yystatus != 3) {
if
(!in_require)
invoke_exception_hook(ERRSV,FALSE);
op_free(PL_eval_root);
PL_eval_root = NULL;
rpp_popfree_to(PL_stack_base + POPMARK);
cx = CX_CUR();
assert
(CxTYPE(cx) == CXt_EVAL);
S_pop_eval_context_maybe_croak(aTHX_ cx, ERRSV, 2);
}
assert
(!in_require);
errsv = ERRSV;
if
(!*(SvPV_nolen_const(errsv)))
sv_setpvs(errsv,
"Compilation error"
);
if
(gimme == G_SCALAR) {
if
(yystatus == 3) {
assert
(*PL_stack_sp == &PL_sv_undef);
}
else
{
rpp_xpush_1(&PL_sv_undef);
}
}
return
FALSE;
}
LEAVE_with_name(
"evalcomp"
);
CopLINE_set(&PL_compiling, 0);
SAVEFREEOP(PL_eval_root);
cv_forget_slab(evalcv);
DEBUG_x(dump_eval());
if
(PERLDB_INTER && saveop->op_type == OP_REQUIRE) {
CV *
const
cv = get_cvs(
"DB::postponed"
, 0);
if
(cv) {
PUSHMARK(PL_stack_sp);
rpp_xpush_1(MUTABLE_SV(CopFILEGV(&PL_compiling)));
call_sv(MUTABLE_SV(cv), G_DISCARD);
}
}
if
(PL_unitcheckav && av_count(PL_unitcheckav)>0) {
OP *es = PL_eval_start;
if
(in_require) {
call_list(PL_scopestack_ix, PL_unitcheckav);
}
else
if
(S_try_run_unitcheck(aTHX_ saveop)) {
PL_op = saveop;
SV *errsv = ERRSV;
if
(!*(SvPV_nolen_const(errsv))) {
sv_setpvs(errsv,
"Unit check error"
);
}
if
(gimme != G_LIST)
rpp_xpush_1(&PL_sv_undef);
return
FALSE;
}
PL_eval_start = es;
}
CvDEPTH(evalcv) = 1;
rpp_popfree_to_NN(PL_stack_base + POPMARK);
PL_op = saveop;
PL_parser->lex_state = LEX_NOTPARSING;
return
TRUE;
}
STATIC PerlIO *
S_check_type_and_open(pTHX_ SV *name)
{
Stat_t st;
STRLEN len;
PerlIO * retio;
const
char
*p = SvPV_const(name, len);
int
st_rc;
PERL_ARGS_ASSERT_CHECK_TYPE_AND_OPEN;
#ifdef PERL_DISABLE_PMC
if
(!IS_SAFE_PATHNAME(p, len,
"require"
))
return
NULL;
#endif
#ifndef WIN32
st_rc = PerlLIO_stat(p, &st);
if
(st_rc < 0)
return
NULL;
else
{
int
eno;
if
(S_ISBLK(st.st_mode)) {
eno = EINVAL;
goto
not_file;
}
else
if
(S_ISDIR(st.st_mode)) {
eno = EISDIR;
not_file:
errno
= eno;
return
NULL;
}
}
#endif
retio = PerlIO_openn(aTHX_
":"
, PERL_SCRIPT_MODE, -1, 0, 0, NULL, 1, &name);
#ifdef WIN32
if
(!retio &&
errno
== EACCES) {
int
eno;
st_rc = PerlLIO_stat(p, &st);
if
(st_rc >= 0) {
if
(S_ISDIR(st.st_mode))
eno = EISDIR;
else
if
(S_ISBLK(st.st_mode))
eno = EINVAL;
else
eno = EACCES;
errno
= eno;
}
}
#endif
return
retio;
}
#ifndef PERL_DISABLE_PMC
STATIC PerlIO *
S_doopen_pm(pTHX_ SV *name)
{
STRLEN namelen;
const
char
*p = SvPV_const(name, namelen);
PERL_ARGS_ASSERT_DOOPEN_PM;
if
(!IS_SAFE_PATHNAME(p, namelen,
"require"
))
return
NULL;
if
(memENDPs(p, namelen,
".pm"
)) {
SV *
const
pmcsv = sv_newmortal();
PerlIO * pmcio;
SvSetSV_nosteal(pmcsv,name);
sv_catpvs(pmcsv,
"c"
);
pmcio = check_type_and_open(pmcsv);
if
(pmcio)
return
pmcio;
}
return
check_type_and_open(name);
}
#else
# define doopen_pm(name) check_type_and_open(name)
#endif /* !PERL_DISABLE_PMC */
PERL_STATIC_INLINE
bool
S_path_is_searchable(
const
char
*name)
{
PERL_ARGS_ASSERT_PATH_IS_SEARCHABLE;
if
(PERL_FILE_IS_ABSOLUTE(name)
#ifdef WIN32
|| (*name ==
'.'
&& ((name[1] ==
'/'
||
(name[1] ==
'.'
&& name[2] ==
'/'
))
|| (name[1] ==
'\\'
||
( name[1] ==
'.'
&& name[2] ==
'\\'
)))
)
#else
|| (*name ==
'.'
&& (name[1] ==
'/'
||
(name[1] ==
'.'
&& name[2] ==
'/'
)))
#endif
)
{
return
FALSE;
}
else
return
TRUE;
}
static
OP *
S_require_version(pTHX_ SV *sv)
{
sv = sv_2mortal(new_version(sv));
rpp_popfree_1_NN();
if
(!Perl_sv_derived_from_pvn(aTHX_ PL_patchlevel, STR_WITH_LEN(
"version"
), 0))
upg_version(PL_patchlevel, TRUE);
if
(cUNOP->op_first->op_type == OP_CONST && cUNOP->op_first->op_private & OPpCONST_NOVER) {
if
( vcmp(sv,PL_patchlevel) <= 0 )
DIE(aTHX_
"Perls since %"
SVf
" too modern--this is %"
SVf
", stopped"
,
SVfARG(sv_2mortal(vnormal(sv))),
SVfARG(sv_2mortal(vnormal(PL_patchlevel)))
);
}
else
{
if
( vcmp(sv,PL_patchlevel) > 0 ) {
I32 first = 0;
AV *lav;
SV *
const
req = SvRV(sv);
SV *
const
pv = *hv_fetchs(MUTABLE_HV(req),
"original"
, FALSE);
lav = MUTABLE_AV(SvRV(*hv_fetchs(MUTABLE_HV(req),
"version"
, FALSE)));
first = SvIV(*av_fetch(lav,0,0));
if
( first > (
int
)PERL_REVISION
|| hv_exists(MUTABLE_HV(req),
"qv"
, 2 )
|| av_count(lav) > 2
||
strstr
(SvPVX(pv),
".0"
)
) {
DIE(aTHX_
"Perl %"
SVf
" required--this is only "
"%"
SVf
", stopped"
,
SVfARG(sv_2mortal(vnormal(req))),
SVfARG(sv_2mortal(vnormal(PL_patchlevel)))
);
}
else
{
SV *hintsv;
I32 second = 0;
if
(av_count(lav) > 1)
second = SvIV(*av_fetch(lav,1,0));
second /= second >= 600 ? 100 : 10;
hintsv = Perl_newSVpvf(aTHX_
"v%d.%d.0"
,
(
int
)first, (
int
)second);
upg_version(hintsv, TRUE);
DIE(aTHX_
"Perl %"
SVf
" required (did you mean %"
SVf
"?)"
"--this is only %"
SVf
", stopped"
,
SVfARG(sv_2mortal(vnormal(req))),
SVfARG(sv_2mortal(vnormal(sv_2mortal(hintsv)))),
SVfARG(sv_2mortal(vnormal(PL_patchlevel)))
);
}
}
}
rpp_push_IMM(&PL_sv_yes);
return
NORMAL;
}
static
OP *
S_require_file(pTHX_ SV *sv)
{
PERL_CONTEXT *cx;
const
char
*name;
STRLEN len;
char
* unixname;
STRLEN unixlen;
#ifdef VMS
int
vms_unixname = 0;
char
*unixdir;
#endif
const
char
*tryname = NULL;
SV *namesv = NULL;
const
U8 gimme = GIMME_V;
int
filter_has_file = 0;
PerlIO *tryrsfp = NULL;
SV *filter_cache = NULL;
SV *filter_state = NULL;
SV *filter_sub = NULL;
SV *hook_sv = NULL;
OP *op;
int
saved_errno;
bool
path_searchable;
I32 old_savestack_ix;
const
bool
op_is_require = PL_op->op_type == OP_REQUIRE;
const
char
*
const
op_name = op_is_require ?
"require"
:
"do"
;
SV ** svp_cached = NULL;
assert
(op_is_require || PL_op->op_type == OP_DOFILE);
if
(!SvOK(sv))
DIE(aTHX_
"Missing or undefined argument to %s"
, op_name);
name = SvPV_nomg_const(sv, len);
if
(!(name && len > 0 && *name))
DIE(aTHX_
"Missing or undefined argument to %s"
, op_name);
if
(
PL_hook__require__before
&& SvROK(PL_hook__require__before)
&& SvTYPE(SvRV(PL_hook__require__before)) == SVt_PVCV
) {
SV* name_sv = sv_mortalcopy(sv);
SV *post_hook__require__before_sv = NULL;
ENTER_with_name(
"call_PRE_REQUIRE"
);
SAVETMPS;
PUSHMARK(PL_stack_sp);
rpp_xpush_1(name_sv);
call_sv(PL_hook__require__before, G_SCALAR);
SV *rsv = *PL_stack_sp;
if
(SvOK(rsv) && SvROK(rsv) && SvTYPE(SvRV(rsv)) == SVt_PVCV) {
post_hook__require__before_sv = SvREFCNT_inc_simple_NN(rsv);
rpp_popfree_1_NN();
}
if
(!sv_streq(name_sv,sv)) {
name = SvPV_nomg_const(name_sv, len);
if
(!(name && len > 0 && *name))
DIE(aTHX_
"Missing or undefined argument to %s via %%{^HOOK}{require__before}"
,
op_name);
sv = name_sv;
}
FREETMPS;
LEAVE_with_name(
"call_PRE_REQUIRE"
);
if
(post_hook__require__before_sv) {
SV *nsv = newSVsv(sv);
MORTALDESTRUCTOR_SV(post_hook__require__before_sv, nsv);
SvREFCNT_dec_NN(nsv);
SvREFCNT_dec_NN(post_hook__require__before_sv);
}
}
if
(
PL_hook__require__after
&& SvROK(PL_hook__require__after)
&& SvTYPE(SvRV(PL_hook__require__after)) == SVt_PVCV
) {
SV *nsv = newSVsv(sv);
MORTALDESTRUCTOR_SV(PL_hook__require__after, nsv);
SvREFCNT_dec_NN(nsv);
}
#ifndef VMS
if
(op_is_require) {
svp_cached = hv_fetch(GvHVn(PL_incgv), (
char
*) name, len, 0);
if
(svp_cached &&
(SvGETMAGIC(*svp_cached), SvOK(*svp_cached)))
{
rpp_replace_1_IMM_NN(&PL_sv_yes);
return
NORMAL;
}
}
#endif
if
(!IS_SAFE_PATHNAME(name, len, op_name)) {
if
(!op_is_require) {
CLEAR_ERRSV();
rpp_replace_1_IMM_NN(&PL_sv_undef);
return
NORMAL;
}
DIE(aTHX_
"Can't locate %s: %s"
,
pv_escape(newSVpvs_flags(
""
,SVs_TEMP),name,len,len*2,
NULL, SvUTF8(sv)?PERL_PV_ESCAPE_UNI:0),
Strerror(ENOENT));
}
TAINT_PROPER(op_name);
path_searchable = path_is_searchable(name);
#ifdef VMS
if
((unixname =
tounixspec(name, SvPVX(sv_2mortal(newSVpv(
""
, VMS_MAXRSS-1)))))
!= NULL) {
unixlen =
strlen
(unixname);
vms_unixname = 1;
}
else
#endif
{
unixname = (
char
*) name;
unixlen = len;
}
if
(op_is_require) {
SV *
const
*
const
svp = svp_cached ? svp_cached : hv_fetch(GvHVn(PL_incgv), unixname, unixlen, 0);
if
( svp ) {
if
(!svp_cached)
SvGETMAGIC(*svp);
if
(SvOK(*svp)) {
rpp_replace_1_IMM_NN(&PL_sv_yes);
return
NORMAL;
}
else
DIE(aTHX_
"Attempt to reload %s aborted.\n"
"Compilation failed in require"
, unixname);
}
if
(PL_op->op_flags & OPf_KIDS) {
SVOP *
const
kid = cSVOPx(cUNOP->op_first);
if
(kid->op_type == OP_CONST && (kid->op_private & OPpCONST_BARE)) {
const
STRLEN package_len = len - 3;
const
char
slashdot[2] = {
'/'
,
'.'
};
#ifdef DOSISH
const
char
backslashdot[2] = {
'\\'
,
'.'
};
#endif
if
(!path_searchable || len < 3 || name[0] ==
'.'
|| !memEQs(name + package_len, len - package_len,
".pm"
))
DIE(aTHX_
"Bareword in require maps to disallowed filename \"%"
SVf
"\""
, sv);
if
(
memchr
(name, 0, package_len)) {
DIE(aTHX_
"Bareword in require contains \"\\0\""
);
}
if
(ninstr(name, name + package_len, slashdot,
slashdot +
sizeof
(slashdot))) {
DIE(aTHX_
"Bareword in require contains \"/.\""
);
}
#ifdef DOSISH
if
(ninstr(name, name + package_len, backslashdot,
backslashdot +
sizeof
(backslashdot))) {
DIE(aTHX_
"Bareword in require contains \"\\.\""
);
}
#endif
}
}
}
PERL_DTRACE_PROBE_FILE_LOADING(unixname);
if
(!path_searchable) {
tryname = name;
tryrsfp = doopen_pm(sv);
}
AV *inc_checked = (AV*)sv_2mortal((SV*)newAV());
if
(!tryrsfp && !(
errno
== EACCES && !path_searchable)) {
SSize_t inc_idx;
#ifdef VMS
if
(vms_unixname)
#endif
{
AV *incdir_av = (AV*)sv_2mortal((SV*)newAV());
SV *nsv = sv;
namesv = newSV_type(SVt_PV);
AV *inc_ar = GvAVn(PL_incgv);
SSize_t incdir_continue_inc_idx = -1;
for
(
inc_idx = 0;
(AvFILL(incdir_av)>=0
|| inc_idx <= AvFILL(inc_ar));
inc_idx++
) {
SV *dirsv;
if
(AvFILL(incdir_av)>=0) {
dirsv = av_shift(incdir_av);
if
(AvFILL(incdir_av)<0) {
inc_idx = incdir_continue_inc_idx;
}
}
else
{
dirsv = *av_fetch(inc_ar, inc_idx, TRUE);
}
if
(SvGMAGICAL(dirsv)) {
SvGETMAGIC(dirsv);
dirsv = newSVsv_nomg(dirsv);
}
else
{
SvREFCNT_inc(dirsv);
}
if
(!SvOK(dirsv))
continue
;
av_push(inc_checked, dirsv);
if
(SvROK(dirsv)) {
int
count;
SV **svp;
SV *loader = dirsv;
UV diruv = PTR2UV(SvRV(dirsv));
if
(SvTYPE(SvRV(loader)) == SVt_PVAV
&& !SvOBJECT(SvRV(loader)))
{
loader = *av_fetch(MUTABLE_AV(SvRV(loader)), 0, TRUE);
if
(SvGMAGICAL(loader)) {
SvGETMAGIC(loader);
SV *l = sv_newmortal();
sv_setsv_nomg(l, loader);
loader = l;
}
}
if
(SvPADTMP(nsv)) {
nsv = sv_newmortal();
SvSetSV_nosteal(nsv,sv);
}
const
char
*method = NULL;
bool
is_incdir = FALSE;
SV * inc_idx_sv = save_scalar(PL_incgv);
sv_setiv(inc_idx_sv,inc_idx);
if
(sv_isobject(loader)) {
HV *pkg = SvSTASH(SvRV(loader));
GV * gv = gv_fetchmethod_pvn_flags(pkg,
"INC"
, 3, GV_AUTOLOAD);
if
(gv && isGV(gv)) {
method =
"INC"
;
}
else
{
gv = gv_fetchmethod_pvn_flags(pkg,
"INCDIR"
, 6, 0);
if
(gv && isGV(gv)) {
method =
"INCDIR"
;
is_incdir = TRUE;
}
}
if
(!method) {
if
(SvTYPE(SvRV(loader)) != SVt_PVCV) {
if
(amagic_applies(loader,string_amg,AMGf_unary))
goto
treat_as_string;
else
{
croak(
"Can't locate object method \"INC\", nor"
" \"INCDIR\" nor string overload via"
" package %"
HvNAMEf_QUOTEDPREFIX
" %s"
" in @INC"
, pkg,
dirsv == loader
?
"in object hook"
:
"in object in ARRAY hook"
);
}
}
}
}
Perl_sv_setpvf(aTHX_ namesv,
"/loader/0x%"
UVxf
"/%s"
,
diruv, name);
tryname = SvPVX_const(namesv);
tryrsfp = NULL;
ENTER_with_name(
"call_INC_hook"
);
SAVETMPS;
PUSHMARK(PL_stack_sp);
bool
add_dirsv = (method && (loader != dirsv));
rpp_extend(2 + add_dirsv);
rpp_push_2(
method ? loader : dirsv,
nsv
);
if
(add_dirsv)
rpp_push_1(dirsv);
if
(method) {
count = call_method(method, G_LIST|G_EVAL);
}
else
{
count = call_sv(loader, G_LIST|G_EVAL);
}
if
(count > 0) {
int
i = 0;
SV *arg;
SV **base = PL_stack_sp - count + 1;
if
(is_incdir) {
while
(count-->0) {
arg = base[i++];
SvGETMAGIC(arg);
if
(!SvOK(arg))
continue
;
if
(SvROK(arg)) {
STRLEN l;
char
*pv = SvPV(arg,l);
arg = newSVpvn(pv,l);
}
else
if
(SvGMAGICAL(arg)) {
arg = newSVsv_nomg(arg);
}
else
{
SvREFCNT_inc(arg);
}
av_push(incdir_av, arg);
}
inc_idx_sv = GvSVn(PL_incgv);
incdir_continue_inc_idx = SvOK(inc_idx_sv)
? SvIV(inc_idx_sv) : -1;
goto
done_hook;
}
arg = base[i++];
if
(SvROK(arg) && (SvTYPE(SvRV(arg)) <= SVt_PVLV)
&& !isGV_with_GP(SvRV(arg))) {
filter_cache = SvRV(arg);
if
(i < count) {
arg = base[i++];
}
}
if
(SvROK(arg) && isGV_with_GP(SvRV(arg))) {
arg = SvRV(arg);
}
if
(isGV_with_GP(arg)) {
IO *
const
io = GvIO((
const
GV *)arg);
++filter_has_file;
if
(io) {
tryrsfp = IoIFP(io);
if
(IoOFP(io) && IoOFP(io) != IoIFP(io)) {
PerlIO_close(IoOFP(io));
}
IoIFP(io) = NULL;
IoOFP(io) = NULL;
}
if
(i < count) {
arg = base[i++];
}
}
if
(SvROK(arg) && SvTYPE(SvRV(arg)) == SVt_PVCV) {
filter_sub = arg;
SvREFCNT_inc_simple_void_NN(filter_sub);
if
(i < count) {
filter_state = base[i];
SvREFCNT_inc_simple_void(filter_state);
}
}
if
(!tryrsfp && (filter_cache || filter_sub)) {
tryrsfp = PerlIO_open(BIT_BUCKET,
PERL_SCRIPT_MODE);
}
done_hook:
rpp_popfree_to_NN(base - 1);
}
else
{
SV *errsv= ERRSV;
if
(SvTRUE(errsv) && !SvROK(errsv)) {
STRLEN l;
char
*pv= SvPV(errsv,l);
if
(l>=12 && pv[l-1] ==
'\n'
&& pv[l-2] ==
'.'
&& isDIGIT(pv[l-3]))
sv_catpvf(errsv,
"%s %s hook died--halting @INC search"
,
method ? method :
"INC"
,
method ?
"method"
:
"sub"
);
croak_sv(errsv);
}
}
SvREFCNT_inc_simple_void(filter_cache);
inc_idx_sv = GvSVn(PL_incgv);
inc_idx = SvOK(inc_idx_sv) ? SvIV(inc_idx_sv) : -1;
FREETMPS;
LEAVE_with_name(
"call_INC_hook"
);
inc_ar = GvAVn(PL_incgv);
sv_2mortal(filter_cache);
svp = hv_fetch(GvHVn(PL_incgv), name, len, 0);
if
(svp && SvOK(*svp)) {
STRLEN len;
const
char
*tmp_pv = SvPV_const(*svp,len);
if
(len)
tryname = tmp_pv;
}
if
(tryrsfp) {
hook_sv = dirsv;
break
;
}
filter_has_file = 0;
filter_cache = NULL;
if
(filter_state) {
SvREFCNT_dec_NN(filter_state);
filter_state = NULL;
}
if
(filter_sub) {
SvREFCNT_dec_NN(filter_sub);
filter_sub = NULL;
}
}
else
treat_as_string:
if
(path_searchable) {
const
char
*dir;
STRLEN dirlen;
if
(SvOK(dirsv)) {
dir = SvPV_nomg_const(dirsv, dirlen);
}
else
{
dir =
""
;
dirlen = 0;
}
if
(!IS_SAFE_SYSCALL(dir, dirlen,
"@INC entry"
, op_name))
continue
;
#ifdef VMS
if
((unixdir =
tounixpath(dir, SvPVX(sv_2mortal(newSVpv(
""
, VMS_MAXRSS-1)))))
== NULL)
continue
;
sv_setpv(namesv, unixdir);
sv_catpv(namesv, unixname);
#else
{
char
*tmp = SvGROW(namesv, dirlen + len + 2);
memcpy
(tmp, dir, dirlen);
tmp +=dirlen;
if
(!dirlen || *(tmp-1) !=
'/'
) {
*tmp++ =
'/'
;
}
else
{
dirlen--;
}
memcpy
(tmp, name, len + 1);
SvCUR_set(namesv, dirlen + len + 1);
SvPOK_on(namesv);
}
#endif
TAINT_PROPER(op_name);
tryname = SvPVX_const(namesv);
tryrsfp = doopen_pm(namesv);
if
(tryrsfp) {
if
(tryname[0] ==
'.'
&& tryname[1] ==
'/'
) {
++tryname;
while
(*++tryname ==
'/'
) {}
}
break
;
}
else
if
(
errno
== EMFILE ||
errno
== EACCES) {
break
;
}
}
}
}
}
saved_errno =
errno
;
sv_2mortal(namesv);
if
(!tryrsfp) {
if
(op_is_require) {
if
(saved_errno == EMFILE || saved_errno == EACCES) {
DIE(aTHX_
"Can't locate %s: %s: %s"
,
name, tryname, Strerror(saved_errno));
}
else
{
if
(path_searchable) {
SSize_t i;
SV *
const
msg = newSVpvs_flags(
""
, SVs_TEMP);
SV *
const
inc = newSVpvs_flags(
""
, SVs_TEMP);
for
(i = 0; i <= AvFILL(inc_checked); i++) {
SV **svp= av_fetch(inc_checked, i, TRUE);
if
(!svp || !*svp)
continue
;
sv_catpvs(inc,
" "
);
sv_catsv(inc, *svp);
}
if
(memENDPs(name, len,
".pm"
)) {
const
char
*e = name + len - (
sizeof
(
".pm"
) - 1);
const
char
*c;
bool
utf8 = cBOOL(SvUTF8(sv));
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_catpvs(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_catpvs(msg,
" module)"
);
}
}
else
if
(memENDs(name, len,
".h"
)) {
sv_catpvs(msg,
" (change .h to .ph maybe?) (did you run h2ph?)"
);
}
else
if
(memENDs(name, len,
".ph"
)) {
sv_catpvs(msg,
" (did you run h2ph?)"
);
}
DIE(aTHX_
"Can't locate %s in @INC%"
SVf
" (@INC entries checked:%"
SVf
")"
,
name, msg, inc);
}
}
DIE(aTHX_
"Can't locate %s"
, name);
}
else
{
#ifdef DEFAULT_INC_EXCLUDES_DOT
Stat_t st;
PerlIO *io = NULL;
dSAVE_ERRNO;
bool
do_warn = namesv && ckWARN_d(WARN_DEPRECATED__DOT_IN_INC)
&& PerlLIO_stat(name, &st) == 0 && !S_ISDIR(st.st_mode) && !S_ISBLK(st.st_mode)
&& (io = PerlIO_openn(aTHX_
":"
, PERL_SCRIPT_MODE, -1, 0, 0, NULL, 1, &sv)) != NULL;
if
(io)
PerlIO_close(io);
RESTORE_ERRNO;
if
(do_warn) {
Perl_warner(aTHX_ packWARN(WARN_DEPRECATED__DOT_IN_INC),
"do \"%s\" failed, '.' is no longer in @INC; "
"did you mean do \"./%s\"?"
,
name, name);
}
#endif
CLEAR_ERRSV();
rpp_replace_1_IMM_NN(&PL_sv_undef);
return
NORMAL;
}
}
else
SETERRNO(0, SS_NORMAL);
rpp_popfree_1_NN();
if
(!hook_sv) {
(
void
)hv_store(GvHVn(PL_incgv),
unixname, unixlen, newSVpv(tryname,0),0);
}
else
{
SV**
const
svp = hv_fetch(GvHVn(PL_incgv), unixname, unixlen, 0);
if
(!svp)
(
void
)hv_store(GvHVn(PL_incgv),
unixname, unixlen, newSVsv(hook_sv), 0 );
}
old_savestack_ix = PL_savestack_ix;
SAVECOPFILE_FREE(&PL_compiling);
CopFILE_set(&PL_compiling, tryname);
lex_start(NULL, tryrsfp, 0);
if
(filter_sub || filter_cache) {
SV *
const
fc = filter_cache ? newSV_type(SVt_NULL) : NULL;
SV *datasv;
if
(fc) sv_copypv(fc, filter_cache);
datasv = filter_add(S_run_user_filter, fc);
IoLINES(datasv) = filter_has_file;
IoTOP_GV(datasv) = MUTABLE_GV(filter_state);
IoBOTTOM_GV(datasv) = MUTABLE_GV(filter_sub);
}
assert
(!CATCH_GET);
cx = cx_pushblock(CXt_EVAL, gimme, PL_stack_sp, old_savestack_ix);
cx_pusheval(cx, PL_op->op_next, newSVpv(name, 0));
SAVECOPLINE(&PL_compiling);
CopLINE_set(&PL_compiling, 0);
if
(doeval_compile(gimme, NULL, PL_curcop->cop_seq, NULL))
op = PL_eval_start;
else
op = PL_op->op_next;
PERL_DTRACE_PROBE_FILE_LOADED(unixname);
return
op;
}
PP(pp_require)
{
if
(CATCH_GET)
return
docatch(Perl_pp_require);
{
SV *sv = *PL_stack_sp;
SvGETMAGIC(sv);
return
((SvNIOKp(sv) || SvVOK(sv)) && PL_op->op_type != OP_DOFILE)
? S_require_version(aTHX_ sv)
: S_require_file(aTHX_ sv);
}
}
PP(pp_hintseval)
{
rpp_extend(1);
rpp_push_1_norc(MUTABLE_SV(hv_copy_hints_hv(MUTABLE_HV(cSVOP_sv))));
return
NORMAL;
}
PP(pp_entereval)
{
PERL_CONTEXT *cx;
SV *sv;
U8 gimme;
U32 was;
char
tbuf[TYPE_DIGITS(
long
) + 12];
bool
saved_delete;
char
*tmpbuf;
STRLEN len;
CV* runcv;
U32 seq, lex_flags;
HV *saved_hh;
bool
bytes;
I32 old_savestack_ix;
if
(CATCH_GET)
return
docatch(Perl_pp_entereval);
assert
(!CATCH_GET);
gimme = GIMME_V;
was = PL_breakable_sub_gen;
saved_delete = FALSE;
tmpbuf = tbuf;
lex_flags = 0;
saved_hh = NULL;
bytes = PL_op->op_private & OPpEVAL_BYTES;
if
(PL_op->op_private & OPpEVAL_HAS_HH) {
saved_hh = MUTABLE_HV(rpp_pop_1_norc());
}
else
if
(PL_hints & HINT_LOCALIZE_HH || (
PL_op->op_private & OPpEVAL_COPHH
&& PL_curcop->cop_hints & HINT_LOCALIZE_HH
)) {
saved_hh = cop_hints_2hv(PL_curcop, 0);
hv_magic(saved_hh, NULL, PERL_MAGIC_hints);
}
sv = *PL_stack_sp;
if
(!SvPOK(sv)) {
STRLEN len;
const
char
*
const
p = SvPV_const(sv, len);
sv = newSVpvn_flags(p, len, SVs_TEMP | SvUTF8(sv));
lex_flags |= LEX_START_COPIED;
if
(bytes && SvUTF8(sv))
SvPVbyte_force(sv, len);
}
else
if
(bytes && SvUTF8(sv)) {
STRLEN len;
sv = newSVsv(sv);
(
void
)sv_2mortal(sv);
SvPVbyte_force(sv,len);
lex_flags |= LEX_START_COPIED;
}
TAINT_IF(SvTAINTED(sv));
TAINT_PROPER(
"eval"
);
old_savestack_ix = PL_savestack_ix;
lex_start(sv, NULL, lex_flags | (PL_op->op_private & OPpEVAL_UNICODE
? LEX_IGNORE_UTF8_HINTS
: bytes ? LEX_EVALBYTES : LEX_START_SAME_FILTER
)
);
rpp_popfree_1_NN();
if
(PERLDB_NAMEEVAL && CopLINE(PL_curcop)) {
SV *
const
temp_sv = sv_newmortal();
Perl_sv_setpvf(aTHX_ temp_sv,
"_<(eval %lu)[%s:%"
LINE_Tf
"]"
,
(unsigned
long
)++PL_evalseq,
CopFILE(PL_curcop), CopLINE(PL_curcop));
tmpbuf = SvPVX(temp_sv);
len = SvCUR(temp_sv);
}
else
len = my_snprintf(tmpbuf,
sizeof
(tbuf),
"_<(eval %lu)"
, (unsigned
long
)++PL_evalseq);
SAVECOPFILE_FREE(&PL_compiling);
CopFILE_set(&PL_compiling, tmpbuf+2);
SAVECOPLINE(&PL_compiling);
CopLINE_set(&PL_compiling, 1);
runcv = find_runcv(&seq);
assert
(!CATCH_GET);
cx = cx_pushblock((CXt_EVAL|CXp_REAL),
gimme, PL_stack_sp, old_savestack_ix);
cx_pusheval(cx, PL_op->op_next, NULL);
if
(PERLDB_LINE_OR_SAVESRC && PL_curstash != PL_debstash)
save_lines(CopFILEAV(&PL_compiling), PL_parser->linestr);
else
{
char
*
const
safestr = savepvn(tmpbuf, len);
SAVEDELETE(PL_defstash, safestr, len);
saved_delete = TRUE;
}
if
(doeval_compile(gimme, runcv, seq, saved_hh)) {
if
(was != PL_breakable_sub_gen
? PERLDB_LINE_OR_SAVESRC
: PERLDB_SAVESRC_NOSUBS) {
}
else
if
(!saved_delete) {
char
*
const
safestr = savepvn(tmpbuf, len);
SAVEDELETE(PL_defstash, safestr, len);
}
return
PL_eval_start;
}
else
{
if
(was != PL_breakable_sub_gen
? PERLDB_LINE_OR_SAVESRC
: PERLDB_SAVESRC_INVALID) {
}
else
if
(!saved_delete) {
(
void
)hv_delete(PL_defstash, tmpbuf, len, G_DISCARD);
}
if
(PL_op->op_private & OPpEVAL_EVALSV)
*++PL_stack_sp = NULL;
return
PL_op->op_next;
}
}
PP(pp_leaveeval)
{
SV **oldsp;
U8 gimme;
PERL_CONTEXT *cx;
OP *retop;
int
failed;
bool
override_return = FALSE;
CV *evalcv;
bool
keep;
PERL_ASYNC_CHECK();
cx = CX_CUR();
assert
(CxTYPE(cx) == CXt_EVAL);
oldsp = PL_stack_base + cx->blk_oldsp;
gimme = cx->blk_gimme;
bool
is_require= CxOLD_OP_TYPE(cx) == OP_REQUIRE;
if
(is_require) {
if
(OP_TYPE_IS_OR_WAS(PL_op, OP_RETURN)) {
if
(PL_op->op_flags & OPf_SPECIAL)
override_return =
true
;
}
else
if
((PL_op->op_flags & OPf_KIDS) && OP_TYPE_IS_OR_WAS(PL_op, OP_LEAVEEVAL)){
COP *old_pl_curcop = PL_curcop;
OP *check = cUNOPx(PL_op)->op_first;
if
(check) {
if
(!OP_TYPE_IS(check,OP_STUB)) {
const
OP *kid = cLISTOPx(check)->op_first;
const
OP *last_state = NULL;
for
(; kid; kid = OpSIBLING(kid)) {
if
(
OP_TYPE_IS_OR_WAS(kid, OP_NEXTSTATE)
|| OP_TYPE_IS_OR_WAS(kid, OP_DBSTATE)
){
last_state = kid;
}
}
if
(last_state) {
PL_curcop = cCOPx(last_state);
if
(FEATURE_MODULE_TRUE_IS_ENABLED) {
override_return = TRUE;
}
}
else
{
NOT_REACHED;
}
}
}
else
{
NOT_REACHED;
}
PL_curcop = old_pl_curcop;
}
}
failed = is_require
&& !(gimme == G_SCALAR
? SvTRUE_NN(*PL_stack_sp)
: PL_stack_sp > oldsp);
if
(gimme == G_VOID) {
rpp_popfree_to(oldsp);
FREETMPS;
}
else
leave_adjust_stacks(oldsp, oldsp, gimme, 0);
PL_curcop = cx->blk_oldcop;
keep = cBOOL(PL_in_eval & EVAL_KEEPERR);
retop = cx->blk_eval.retop;
evalcv = cx->blk_eval.cv;
#ifdef DEBUGGING
assert
(CvDEPTH(evalcv) == 1);
#endif
CvDEPTH(evalcv) = 0;
if
(override_return) {
if
(gimme == G_SCALAR)
rpp_replace_1_IMM_NN(&PL_sv_yes);
assert
(gimme == G_VOID || gimme == G_SCALAR);
failed = 0;
}
S_pop_eval_context_maybe_croak(aTHX_ cx, NULL, failed);
if
(!keep)
CLEAR_ERRSV();
return
retop;
}
PP(pp_entertrycatch)
{
PERL_CONTEXT *cx;
const
U8 gimme = GIMME_V;
if
(CATCH_GET)
return
docatch(Perl_pp_entertrycatch);
assert
(!CATCH_GET);
Perl_pp_enter(aTHX);
save_scalar(PL_errgv);
CLEAR_ERRSV();
cx = cx_pushblock((CXt_EVAL|CXp_EVALBLOCK|CXp_TRY), gimme,
PL_stack_sp, PL_savestack_ix);
cx_pushtry(cx, cLOGOP->op_other);
PL_in_eval = EVAL_INEVAL;
return
NORMAL;
}
PP(pp_leavetrycatch)
{
return
Perl_pp_leave(aTHX);
}
PP(pp_poptry)
{
return
Perl_pp_leavetry(aTHX);
}
PP(pp_catch)
{
dTARGET;
save_clearsv(&(PAD_SVl(PL_op->op_targ)));
sv_setsv(TARG, ERRSV);
CLEAR_ERRSV();
return
cLOGOP->op_other;
}
void
Perl_delete_eval_scope(pTHX)
{
PERL_CONTEXT *cx;
cx = CX_CUR();
CX_LEAVE_SCOPE(cx);
cx_popeval(cx);
cx_popblock(cx);
CX_POP(cx);
}
void
Perl_create_eval_scope(pTHX_ OP *retop, SV **sp, U32 flags)
{
PERL_CONTEXT *cx;
const
U8 gimme = GIMME_V;
PERL_ARGS_ASSERT_CREATE_EVAL_SCOPE;
cx = cx_pushblock((CXt_EVAL|CXp_EVALBLOCK), gimme,
sp, PL_savestack_ix);
cx_pusheval(cx, retop, NULL);
PL_in_eval = EVAL_INEVAL;
if
(flags & G_KEEPERR)
PL_in_eval |= EVAL_KEEPERR;
else
CLEAR_ERRSV();
if
(flags & G_FAKINGEVAL) {
PL_eval_root = PL_op;
}
}
PP(pp_entertry)
{
OP *retop = cLOGOP->op_other->op_next;
if
(CATCH_GET)
return
docatch(Perl_pp_entertry);
assert
(!CATCH_GET);
create_eval_scope(retop, PL_stack_sp, 0);
return
PL_op->op_next;
}
PP(pp_leavetry)
{
SV **oldsp;
U8 gimme;
PERL_CONTEXT *cx;
OP *retop;
PERL_ASYNC_CHECK();
cx = CX_CUR();
assert
(CxTYPE(cx) == CXt_EVAL);
oldsp = PL_stack_base + cx->blk_oldsp;
gimme = cx->blk_gimme;
if
(gimme == G_VOID) {
rpp_popfree_to_NN(oldsp);
FREETMPS;
}
else
leave_adjust_stacks(oldsp, oldsp, gimme, 1);
CX_LEAVE_SCOPE(cx);
cx_popeval(cx);
cx_popblock(cx);
retop = CxTRY(cx) ? PL_op->op_next : cx->blk_eval.retop;
CX_POP(cx);
CLEAR_ERRSV();
return
retop;
}
PP(pp_entergiven)
{
PERL_CONTEXT *cx;
const
U8 gimme = GIMME_V;
SV *origsv = DEFSV;
assert
(!PL_op->op_targ);
GvSV(PL_defgv) = rpp_pop_1_norc();
cx = cx_pushblock(CXt_GIVEN, gimme, PL_stack_sp, PL_savestack_ix);
cx_pushgiven(cx, origsv);
return
NORMAL;
}
PP(pp_leavegiven)
{
PERL_CONTEXT *cx;
U8 gimme;
SV **oldsp;
PERL_UNUSED_CONTEXT;
cx = CX_CUR();
assert
(CxTYPE(cx) == CXt_GIVEN);
oldsp = PL_stack_base + cx->blk_oldsp;
gimme = cx->blk_gimme;
if
(gimme == G_VOID)
rpp_popfree_to_NN(oldsp);
else
leave_adjust_stacks(oldsp, oldsp, gimme, 1);
CX_LEAVE_SCOPE(cx);
cx_popgiven(cx);
cx_popblock(cx);
CX_POP(cx);
return
NORMAL;
}
STATIC PMOP *
S_make_matcher(pTHX_ REGEXP *re)
{
PMOP *matcher = cPMOPx(newPMOP(OP_MATCH, OPf_WANT_SCALAR | OPf_STACKED));
PERL_ARGS_ASSERT_MAKE_MATCHER;
PM_SETRE(matcher, ReREFCNT_inc(re));
SAVEFREEOP((OP *) matcher);
ENTER_with_name(
"matcher"
); SAVETMPS;
SAVEOP();
return
matcher;
}
STATIC
bool
S_matcher_matches_sv(pTHX_ PMOP *matcher, SV *sv)
{
bool
result;
PERL_ARGS_ASSERT_MATCHER_MATCHES_SV;
PL_op = (OP *) matcher;
rpp_xpush_1(sv);
(
void
) Perl_pp_match(aTHX);
result = SvTRUEx(*PL_stack_sp);
rpp_popfree_1_NN();
return
result;
}
STATIC
void
S_destroy_matcher(pTHX_ PMOP *matcher)
{
PERL_ARGS_ASSERT_DESTROY_MATCHER;
PERL_UNUSED_ARG(matcher);
FREETMPS;
LEAVE_with_name(
"matcher"
);
}
PP(pp_smartmatch)
{
DEBUG_M(Perl_deb(aTHX_
"Starting smart match resolution\n"
));
return
do_smartmatch(NULL, NULL, 0);
}
STATIC OP *
S_do_smartmatch(pTHX_ HV *seen_this, HV *seen_other,
const
bool
copied)
{
bool
object_on_left = FALSE;
SV *e = PL_stack_sp[0];
SV *d = PL_stack_sp[-1];
if
(d) {
if
(!copied && SvGMAGICAL(d))
d = sv_mortalcopy(d);
}
else
d = &PL_sv_undef;
assert
(e);
if
(SvGMAGICAL(e))
e = sv_mortalcopy(e);
if
(SvAMAGIC(e)) {
SV * tmpsv;
DEBUG_M(Perl_deb(aTHX_
" applying rule Any-Object\n"
));
DEBUG_M(Perl_deb(aTHX_
" attempting overload\n"
));
tmpsv = amagic_call(d, e, smart_amg, AMGf_noleft);
if
(tmpsv) {
rpp_replace_2_1_NN(tmpsv);
return
NORMAL;
}
DEBUG_M(Perl_deb(aTHX_
" failed to run overload method; continuing...\n"
));
}
if
(!SvOK(e)) {
DEBUG_M(Perl_deb(aTHX_
" applying rule Any-undef\n"
));
if
(SvOK(d))
goto
ret_no;
else
goto
ret_yes;
}
if
(SvROK(e) && SvOBJECT(SvRV(e)) && (SvTYPE(SvRV(e)) != SVt_REGEXP)) {
DEBUG_M(Perl_deb(aTHX_
" applying rule Any-Object\n"
));
Perl_croak(aTHX_
"Smart matching a non-overloaded object breaks encapsulation"
);
}
if
(SvROK(d) && SvOBJECT(SvRV(d)) && (SvTYPE(SvRV(d)) != SVt_REGEXP))
object_on_left = TRUE;
if
(SvROK(e) && SvTYPE(SvRV(e)) == SVt_PVCV) {
if
(object_on_left) {
goto
sm_any_sub;
}
else
if
(SvROK(d) && SvTYPE(SvRV(d)) == SVt_PVHV) {
HE *he;
bool
andedresults = TRUE;
HV *hv = (HV*) SvRV(d);
I32 numkeys = hv_iterinit(hv);
DEBUG_M(Perl_deb(aTHX_
" applying rule Hash-CodeRef\n"
));
if
(numkeys == 0)
goto
ret_yes;
while
( (he = hv_iternext(hv)) ) {
DEBUG_M(Perl_deb(aTHX_
" testing hash key...\n"
));
ENTER_with_name(
"smartmatch_hash_key_test"
);
SAVETMPS;
PUSHMARK(PL_stack_sp);
rpp_xpush_1(hv_iterkeysv(he));
(
void
)call_sv(e, G_SCALAR);
andedresults = SvTRUEx(PL_stack_sp[0]) && andedresults;
rpp_popfree_1_NN();
FREETMPS;
LEAVE_with_name(
"smartmatch_hash_key_test"
);
}
if
(andedresults)
goto
ret_yes;
else
goto
ret_no;
}
else
if
(SvROK(d) && SvTYPE(SvRV(d)) == SVt_PVAV) {
Size_t i;
bool
andedresults = TRUE;
AV *av = (AV*) SvRV(d);
const
Size_t len = av_count(av);
DEBUG_M(Perl_deb(aTHX_
" applying rule Array-CodeRef\n"
));
if
(len == 0)
goto
ret_yes;
for
(i = 0; i < len; ++i) {
SV *
const
*
const
svp = av_fetch(av, i, FALSE);
DEBUG_M(Perl_deb(aTHX_
" testing array element...\n"
));
ENTER_with_name(
"smartmatch_array_elem_test"
);
SAVETMPS;
PUSHMARK(PL_stack_sp);
if
(svp)
rpp_xpush_1(*svp);
(
void
)call_sv(e, G_SCALAR);
andedresults = SvTRUEx(PL_stack_sp[0]) && andedresults;
rpp_popfree_1_NN();
FREETMPS;
LEAVE_with_name(
"smartmatch_array_elem_test"
);
}
if
(andedresults)
goto
ret_yes;
else
goto
ret_no;
}
else
{
sm_any_sub:
DEBUG_M(Perl_deb(aTHX_
" applying rule Any-CodeRef\n"
));
ENTER_with_name(
"smartmatch_coderef"
);
PUSHMARK(PL_stack_sp);
rpp_xpush_1(d);
(
void
)call_sv(e, G_SCALAR);
LEAVE_with_name(
"smartmatch_coderef"
);
SV *retsv = *PL_stack_sp--;
rpp_replace_2_1(retsv);
#ifdef PERL_RC_STACK
SvREFCNT_dec(retsv);
#endif
return
NORMAL;
}
}
else
if
(SvROK(e) && SvTYPE(SvRV(e)) == SVt_PVHV) {
if
(object_on_left) {
goto
sm_any_hash;
}
else
if
(!SvOK(d)) {
DEBUG_M(Perl_deb(aTHX_
" applying rule Any-Hash ($a undef)\n"
));
goto
ret_no;
}
else
if
(SvROK(d) && SvTYPE(SvRV(d)) == SVt_PVHV) {
HE *he;
HV *other_hv = MUTABLE_HV(SvRV(d));
bool
tied;
bool
other_tied;
U32 this_key_count = 0,
other_key_count = 0;
HV *hv = MUTABLE_HV(SvRV(e));
DEBUG_M(Perl_deb(aTHX_
" applying rule Hash-Hash\n"
));
tied = cBOOL(SvTIED_mg((SV*)hv, PERL_MAGIC_tied));
other_tied = cBOOL(SvTIED_mg((
const
SV *)other_hv, PERL_MAGIC_tied));
if
(!tied ) {
if
(other_tied) {
HV *
const
temp = other_hv;
other_hv = hv;
hv = temp;
tied = TRUE;
other_tied = FALSE;
}
else
if
(HvUSEDKEYS((
const
HV *) hv) != HvUSEDKEYS(other_hv))
goto
ret_no;
}
(
void
) hv_iterinit(hv);
while
( (he = hv_iternext(hv)) ) {
SV *key = hv_iterkeysv(he);
DEBUG_M(Perl_deb(aTHX_
" comparing hash key...\n"
));
++ this_key_count;
if
(!hv_exists_ent(other_hv, key, 0)) {
(
void
) hv_iterinit(hv);
goto
ret_no;
}
}
if
(other_tied) {
(
void
) hv_iterinit(other_hv);
while
( hv_iternext(other_hv) )
++other_key_count;
}
else
other_key_count = HvUSEDKEYS(other_hv);
if
(this_key_count != other_key_count)
goto
ret_no;
else
goto
ret_yes;
}
else
if
(SvROK(d) && SvTYPE(SvRV(d)) == SVt_PVAV) {
AV *
const
other_av = MUTABLE_AV(SvRV(d));
const
Size_t other_len = av_count(other_av);
Size_t i;
HV *hv = MUTABLE_HV(SvRV(e));
DEBUG_M(Perl_deb(aTHX_
" applying rule Array-Hash\n"
));
for
(i = 0; i < other_len; ++i) {
SV **
const
svp = av_fetch(other_av, i, FALSE);
DEBUG_M(Perl_deb(aTHX_
" checking for key existence...\n"
));
if
(svp) {
if
(hv_exists_ent(hv, *svp, 0))
goto
ret_yes;
}
}
goto
ret_no;
}
else
if
(SvROK(d) && SvTYPE(SvRV(d)) == SVt_REGEXP) {
DEBUG_M(Perl_deb(aTHX_
" applying rule Regex-Hash\n"
));
sm_regex_hash:
{
PMOP *
const
matcher = make_matcher((REGEXP*) SvRV(d));
HE *he;
HV *hv = MUTABLE_HV(SvRV(e));
(
void
) hv_iterinit(hv);
while
( (he = hv_iternext(hv)) ) {
DEBUG_M(Perl_deb(aTHX_
" testing key against pattern...\n"
));
if
(matcher_matches_sv(matcher, hv_iterkeysv(he))) {
(
void
) hv_iterinit(hv);
destroy_matcher(matcher);
goto
ret_yes;
}
}
destroy_matcher(matcher);
goto
ret_no;
}
}
else
{
sm_any_hash:
DEBUG_M(Perl_deb(aTHX_
" applying rule Any-Hash\n"
));
if
(hv_exists_ent(MUTABLE_HV(SvRV(e)), d, 0))
goto
ret_yes;
else
goto
ret_no;
}
}
else
if
(SvROK(e) && SvTYPE(SvRV(e)) == SVt_PVAV) {
if
(object_on_left) {
goto
sm_any_array;
}
else
if
(SvROK(d) && SvTYPE(SvRV(d)) == SVt_PVHV) {
AV *
const
other_av = MUTABLE_AV(SvRV(e));
const
Size_t other_len = av_count(other_av);
Size_t i;
DEBUG_M(Perl_deb(aTHX_
" applying rule Hash-Array\n"
));
for
(i = 0; i < other_len; ++i) {
SV **
const
svp = av_fetch(other_av, i, FALSE);
DEBUG_M(Perl_deb(aTHX_
" testing for key existence...\n"
));
if
(svp) {
if
(hv_exists_ent(MUTABLE_HV(SvRV(d)), *svp, 0))
goto
ret_yes;
}
}
goto
ret_no;
}
if
(SvROK(d) && SvTYPE(SvRV(d)) == SVt_PVAV) {
AV *other_av = MUTABLE_AV(SvRV(d));
DEBUG_M(Perl_deb(aTHX_
" applying rule Array-Array\n"
));
if
(av_count(MUTABLE_AV(SvRV(e))) != av_count(other_av))
goto
ret_no;
else
{
Size_t i;
const
Size_t other_len = av_count(other_av);
if
(NULL == seen_this) {
seen_this = (HV*)newSV_type_mortal(SVt_PVHV);
}
if
(NULL == seen_other) {
seen_other = (HV*)newSV_type_mortal(SVt_PVHV);
}
for
(i = 0; i < other_len; ++i) {
SV *
const
*
const
this_elem = av_fetch(MUTABLE_AV(SvRV(e)), i, FALSE);
SV *
const
*
const
other_elem = av_fetch(other_av, i, FALSE);
if
(!this_elem || !other_elem) {
if
((this_elem && SvOK(*this_elem))
|| (other_elem && SvOK(*other_elem)))
goto
ret_no;
}
else
if
(hv_exists_ent(seen_this,
sv_2mortal(newSViv(PTR2IV(*this_elem))), 0) ||
hv_exists_ent(seen_other,
sv_2mortal(newSViv(PTR2IV(*other_elem))), 0))
{
if
(*this_elem != *other_elem)
goto
ret_no;
}
else
{
(
void
)hv_store_ent(seen_this,
sv_2mortal(newSViv(PTR2IV(*this_elem))),
&PL_sv_undef, 0);
(
void
)hv_store_ent(seen_other,
sv_2mortal(newSViv(PTR2IV(*other_elem))),
&PL_sv_undef, 0);
rpp_xpush_2(*other_elem, *this_elem);
DEBUG_M(Perl_deb(aTHX_
" recursively comparing array element...\n"
));
(
void
) do_smartmatch(seen_this, seen_other, 0);
DEBUG_M(Perl_deb(aTHX_
" recursion finished\n"
));
bool
ok = SvTRUEx(PL_stack_sp[0]);
rpp_popfree_1_NN();
if
(!ok)
goto
ret_no;
}
}
goto
ret_yes;
}
}
else
if
(SvROK(d) && SvTYPE(SvRV(d)) == SVt_REGEXP) {
DEBUG_M(Perl_deb(aTHX_
" applying rule Regex-Array\n"
));
sm_regex_array:
{
PMOP *
const
matcher = make_matcher((REGEXP*) SvRV(d));
const
Size_t this_len = av_count(MUTABLE_AV(SvRV(e)));
Size_t i;
for
(i = 0; i < this_len; ++i) {
SV *
const
*
const
svp = av_fetch(MUTABLE_AV(SvRV(e)), i, FALSE);
DEBUG_M(Perl_deb(aTHX_
" testing element against pattern...\n"
));
if
(svp && matcher_matches_sv(matcher, *svp)) {
destroy_matcher(matcher);
goto
ret_yes;
}
}
destroy_matcher(matcher);
goto
ret_no;
}
}
else
if
(!SvOK(d)) {
const
Size_t this_len = av_count(MUTABLE_AV(SvRV(e)));
Size_t i;
DEBUG_M(Perl_deb(aTHX_
" applying rule Undef-Array\n"
));
for
(i = 0; i < this_len; ++i) {
SV *
const
*
const
svp = av_fetch(MUTABLE_AV(SvRV(e)), i, FALSE);
DEBUG_M(Perl_deb(aTHX_
" testing for undef element...\n"
));
if
(!svp || !SvOK(*svp))
goto
ret_yes;
}
goto
ret_no;
}
else
{
sm_any_array:
{
Size_t i;
const
Size_t this_len = av_count(MUTABLE_AV(SvRV(e)));
DEBUG_M(Perl_deb(aTHX_
" applying rule Any-Array\n"
));
for
(i = 0; i < this_len; ++i) {
SV *
const
*
const
svp = av_fetch(MUTABLE_AV(SvRV(e)), i, FALSE);
if
(!svp)
continue
;
rpp_xpush_2(d, *svp);
DEBUG_M(Perl_deb(aTHX_
" recursively testing array element...\n"
));
(
void
) do_smartmatch(NULL, NULL, 1);
DEBUG_M(Perl_deb(aTHX_
" recursion finished\n"
));
bool
ok = SvTRUEx(PL_stack_sp[0]);
rpp_popfree_1_NN();
if
(ok)
goto
ret_yes;
}
goto
ret_no;
}
}
}
else
if
(SvROK(e) && SvTYPE(SvRV(e)) == SVt_REGEXP) {
if
(!object_on_left && SvROK(d) && SvTYPE(SvRV(d)) == SVt_PVHV) {
SV *t = d; d = e; e = t;
DEBUG_M(Perl_deb(aTHX_
" applying rule Hash-Regex\n"
));
goto
sm_regex_hash;
}
else
if
(!object_on_left && SvROK(d) && SvTYPE(SvRV(d)) == SVt_PVAV) {
SV *t = d; d = e; e = t;
DEBUG_M(Perl_deb(aTHX_
" applying rule Array-Regex\n"
));
goto
sm_regex_array;
}
else
{
PMOP *
const
matcher = make_matcher((REGEXP*) SvRV(e));
bool
result;
DEBUG_M(Perl_deb(aTHX_
" applying rule Any-Regex\n"
));
result = matcher_matches_sv(matcher, d);
destroy_matcher(matcher);
if
(result)
goto
ret_yes;
else
goto
ret_no;
}
}
else
if
(object_on_left && SvAMAGIC(d)) {
SV *tmpsv;
DEBUG_M(Perl_deb(aTHX_
" applying rule Object-Any\n"
));
DEBUG_M(Perl_deb(aTHX_
" attempting overload\n"
));
tmpsv = amagic_call(d, e, smart_amg, AMGf_noright);
if
(tmpsv) {
rpp_replace_2_1_NN(tmpsv);
return
NORMAL;
}
DEBUG_M(Perl_deb(aTHX_
" failed to run overload method; falling back...\n"
));
goto
sm_any_scalar;
}
else
if
(!SvOK(d)) {
DEBUG_M(Perl_deb(aTHX_
" applying rule undef-Any\n"
));
goto
ret_no;
}
else
sm_any_scalar:
if
(SvNIOK(e) || (SvPOK(e) && looks_like_number(e) && SvNIOK(d))) {
DEBUG_M(
if
(SvNIOK(e))
Perl_deb(aTHX_
" applying rule Any-Num\n"
);
else
Perl_deb(aTHX_
" applying rule Num-numish\n"
);
);
rpp_xpush_2(d, e);
if
(CopHINTS_get(PL_curcop) & HINT_INTEGER)
(
void
) Perl_pp_i_eq(aTHX);
else
(
void
) Perl_pp_eq(aTHX);
bool
ok = SvTRUEx(PL_stack_sp[0]);
rpp_popfree_1_NN();
if
(ok)
goto
ret_yes;
else
goto
ret_no;
}
DEBUG_M(Perl_deb(aTHX_
" applying rule Any-Any\n"
));
rpp_xpush_2(d, e);
Perl_pp_seq(aTHX);
{
bool
ok = SvTRUEx(PL_stack_sp[0]);
rpp_popfree_1_NN();
if
(ok)
goto
ret_yes;
else
goto
ret_no;
}
ret_no:
rpp_replace_2_IMM_NN(&PL_sv_no);
return
NORMAL;
ret_yes:
rpp_replace_2_IMM_NN(&PL_sv_yes);
return
NORMAL;
}
PP(pp_enterwhen)
{
PERL_CONTEXT *cx;
const
U8 gimme = GIMME_V;
if
(!(PL_op->op_flags & OPf_SPECIAL)) {
bool
tr = SvTRUEx(*PL_stack_sp);
rpp_popfree_1_NN();
if
(!tr) {
if
(gimme == G_SCALAR)
rpp_push_IMM(&PL_sv_undef);
return
cLOGOP->op_other->op_next;
}
}
cx = cx_pushblock(CXt_WHEN, gimme, PL_stack_sp, PL_savestack_ix);
cx_pushwhen(cx);
return
NORMAL;
}
PP(pp_leavewhen)
{
I32 cxix;
PERL_CONTEXT *cx;
U8 gimme;
SV **oldsp;
cx = CX_CUR();
assert
(CxTYPE(cx) == CXt_WHEN);
gimme = cx->blk_gimme;
cxix = dopoptogivenfor(cxstack_ix);
if
(cxix < 0)
DIE(aTHX_
"Can't \"%s\" outside a topicalizer"
,
PL_op->op_flags & OPf_SPECIAL ?
"default"
:
"when"
);
oldsp = PL_stack_base + cx->blk_oldsp;
if
(gimme == G_VOID)
rpp_popfree_to_NN(oldsp);
else
leave_adjust_stacks(oldsp, oldsp, gimme, 1);
assert
(cxix < cxstack_ix);
dounwind(cxix);
cx = &cxstack[cxix];
if
(CxFOREACH(cx)) {
cx = CX_CUR();
cx_topblock(cx);
PL_curcop = cx->blk_oldcop;
return
cx->blk_loop.my_op->op_nextop;
}
else
{
PERL_ASYNC_CHECK();
assert
(cx->blk_givwhen.leave_op->op_type == OP_LEAVEGIVEN);
return
cx->blk_givwhen.leave_op;
}
}
PP(pp_continue)
{
I32 cxix;
PERL_CONTEXT *cx;
OP *nextop;
cxix = dopoptowhen(cxstack_ix);
if
(cxix < 0)
DIE(aTHX_
"Can't \"continue\" outside a when block"
);
if
(cxix < cxstack_ix)
dounwind(cxix);
cx = CX_CUR();
assert
(CxTYPE(cx) == CXt_WHEN);
rpp_popfree_to_NN(PL_stack_base + cx->blk_oldsp);
CX_LEAVE_SCOPE(cx);
cx_popwhen(cx);
cx_popblock(cx);
nextop = cx->blk_givwhen.leave_op->op_next;
CX_POP(cx);
return
nextop;
}
PP(pp_break)
{
I32 cxix;
PERL_CONTEXT *cx;
cxix = dopoptogivenfor(cxstack_ix);
if
(cxix < 0)
DIE(aTHX_
"Can't \"break\" outside a given block"
);
cx = &cxstack[cxix];
if
(CxFOREACH(cx))
DIE(aTHX_
"Can't \"break\" in a loop topicalizer"
);
if
(cxix < cxstack_ix)
dounwind(cxix);
cx = CX_CUR();
rpp_popfree_to_NN(PL_stack_base + cx->blk_oldsp);
return
cx->blk_givwhen.leave_op;
}
static
void
_invoke_defer_block(pTHX_ U8 type,
void
*_arg)
{
OP *start = (OP *)_arg;
#ifdef DEBUGGING
I32 was_cxstack_ix = cxstack_ix;
#endif
cx_pushblock(type, G_VOID, PL_stack_sp, PL_savestack_ix);
ENTER;
SAVETMPS;
SAVEOP();
PL_op = start;
CALLRUNOPS(aTHX);
FREETMPS;
LEAVE;
{
PERL_CONTEXT *cx;
cx = CX_CUR();
assert
(CxTYPE(cx) == CXt_DEFER);
#ifdef PERL_RC_STACK
if
(rpp_stack_is_rc())
rpp_popfree_to_NN(PL_stack_base + cx->blk_oldsp);
else
#endif
PL_stack_sp = PL_stack_base + cx->blk_oldsp;
CX_LEAVE_SCOPE(cx);
cx_popblock(cx);
CX_POP(cx);
}
assert
(cxstack_ix == was_cxstack_ix);
}
static
void
invoke_defer_block(pTHX_
void
*_arg)
{
_invoke_defer_block(aTHX_ CXt_DEFER, _arg);
}
static
void
invoke_finally_block(pTHX_
void
*_arg)
{
_invoke_defer_block(aTHX_ CXt_DEFER|CXp_FINALLY, _arg);
}
PP(pp_pushdefer)
{
if
(PL_op->op_private & OPpDEFER_FINALLY)
SAVEDESTRUCTOR_X(invoke_finally_block, cLOGOP->op_other);
else
SAVEDESTRUCTOR_X(invoke_defer_block, cLOGOP->op_other);
return
NORMAL;
}
static
MAGIC *
S_doparseform(pTHX_ SV *sv)
{
STRLEN len;
char
*s = SvPV(sv, len);
char
*send;
char
*base = NULL;
I32 skipspaces = 0;
bool
noblank = FALSE;
bool
repeat = FALSE;
bool
postspace = FALSE;
U32 *fops;
U32 *fpc;
U32 *linepc = NULL;
I32 arg;
bool
ischop;
bool
unchopnum = FALSE;
int
maxops = 12;
MAGIC *mg = NULL;
SV *sv_copy;
PERL_ARGS_ASSERT_DOPARSEFORM;
if
(len == 0)
Perl_croak(aTHX_
"Null picture in formline"
);
if
(SvTYPE(sv) >= SVt_PVMG) {
mg = mg_find(sv, PERL_MAGIC_fm);
}
else
{
sv_upgrade(sv, SVt_PVMG);
}
if
(mg) {
SV *old = mg->mg_obj;
if
( ! (cBOOL(SvUTF8(old)) ^ cBOOL(SvUTF8(sv)))
&& len == SvCUR(old)
&& strnEQ(SvPVX(old), s, len)
) {
DEBUG_f(PerlIO_printf(Perl_debug_log,
"Re-using compiled format\n"
));
return
mg;
}
DEBUG_f(PerlIO_printf(Perl_debug_log,
"Re-compiling format\n"
));
Safefree(mg->mg_ptr);
mg->mg_ptr = NULL;
SvREFCNT_dec(old);
mg->mg_obj = NULL;
}
else
{
DEBUG_f(PerlIO_printf(Perl_debug_log,
"Compiling format\n"
));
mg = sv_magicext(sv, NULL, PERL_MAGIC_fm, &PL_vtbl_fm, NULL, 0);
}
sv_copy = newSVpvn_utf8(s, len, SvUTF8(sv));
s = SvPV(sv_copy, len);
send = s + len;
for
(base = s; s <= send; s++) {
if
(*s ==
'\n'
|| *s ==
'@'
|| *s ==
'^'
)
maxops += 10;
}
s = base;
base = NULL;
Newx(fops, maxops, U32);
fpc = fops;
if
(s < send) {
linepc = fpc;
*fpc++ = FF_LINEMARK;
noblank = repeat = FALSE;
base = s;
}
while
(s <= send) {
switch
(*s++) {
default
:
skipspaces = 0;
continue
;
case
'~'
:
if
(*s ==
'~'
) {
repeat = TRUE;
skipspaces++;
s++;
}
noblank = TRUE;
case
' '
:
case
'\t'
:
skipspaces++;
continue
;
case
0:
if
(s < send) {
skipspaces = 0;
continue
;
}
case
'\n'
:
arg = s - base;
skipspaces++;
arg -= skipspaces;
if
(arg) {
if
(postspace)
*fpc++ = FF_SPACE;
*fpc++ = FF_LITERAL;
*fpc++ = (U32)arg;
}
postspace = FALSE;
if
(s <= send)
skipspaces--;
if
(skipspaces) {
*fpc++ = FF_SKIP;
*fpc++ = (U32)skipspaces;
}
skipspaces = 0;
if
(s <= send)
*fpc++ = FF_NEWLINE;
if
(noblank) {
*fpc++ = FF_BLANK;
if
(repeat)
arg = fpc - linepc + 1;
else
arg = 0;
*fpc++ = (U32)arg;
}
if
(s < send) {
linepc = fpc;
*fpc++ = FF_LINEMARK;
noblank = repeat = FALSE;
base = s;
}
else
s++;
continue
;
case
'@'
:
case
'^'
:
ischop = s[-1] ==
'^'
;
if
(postspace) {
*fpc++ = FF_SPACE;
postspace = FALSE;
}
arg = (s - base) - 1;
if
(arg) {
*fpc++ = FF_LITERAL;
*fpc++ = (U32)arg;
}
base = s - 1;
*fpc++ = FF_FETCH;
if
(*s ==
'*'
) {
s++;
*fpc++ = 2;
if
(ischop) {
*fpc++ = FF_LINESNGL;
*fpc++ = FF_CHOP;
}
else
*fpc++ = FF_LINEGLOB;
}
else
if
(*s ==
'#'
|| (*s ==
'.'
&& s[1] ==
'#'
)) {
arg = ischop ? FORM_NUM_BLANK : 0;
base = s - 1;
while
(*s ==
'#'
)
s++;
if
(*s ==
'.'
) {
const
char
*
const
f = ++s;
while
(*s ==
'#'
)
s++;
arg |= FORM_NUM_POINT + (s - f);
}
*fpc++ = s - base;
*fpc++ = FF_DECIMAL;
*fpc++ = (U32)arg;
unchopnum |= ! ischop;
}
else
if
(*s ==
'0'
&& s[1] ==
'#'
) {
arg = ischop ? FORM_NUM_BLANK : 0;
base = s - 1;
s++;
while
(*s ==
'#'
)
s++;
if
(*s ==
'.'
) {
const
char
*
const
f = ++s;
while
(*s ==
'#'
)
s++;
arg |= FORM_NUM_POINT + (s - f);
}
*fpc++ = s - base;
*fpc++ = FF_0DECIMAL;
*fpc++ = (U32)arg;
unchopnum |= ! ischop;
}
else
{
I32 prespace = 0;
bool
ismore = FALSE;
if
(*s ==
'>'
) {
while
(*++s ==
'>'
) ;
prespace = FF_SPACE;
}
else
if
(*s ==
'|'
) {
while
(*++s ==
'|'
) ;
prespace = FF_HALFSPACE;
postspace = TRUE;
}
else
{
if
(*s ==
'<'
)
while
(*++s ==
'<'
) ;
postspace = TRUE;
}
if
(*s ==
'.'
&& s[1] ==
'.'
&& s[2] ==
'.'
) {
s += 3;
ismore = TRUE;
}
*fpc++ = s - base;
*fpc++ = ischop ? FF_CHECKCHOP : FF_CHECKNL;
if
(prespace)
*fpc++ = (U32)prespace;
*fpc++ = FF_ITEM;
if
(ismore)
*fpc++ = FF_MORE;
if
(ischop)
*fpc++ = FF_CHOP;
}
base = s;
skipspaces = 0;
continue
;
}
}
*fpc++ = FF_END;
assert
(fpc <= fops + maxops);
arg = fpc - fops;
mg->mg_ptr = (
char
*) fops;
mg->mg_len = arg *
sizeof
(U32);
mg->mg_obj = sv_copy;
mg->mg_flags |= MGf_REFCOUNTED;
if
(unchopnum && repeat)
Perl_die(aTHX_
"Repeated format line will never terminate (~~ and @#)"
);
return
mg;
}
STATIC
bool
S_num_overflow(NV value, I32 fldsize, I32 frcsize)
{
NV pwr = 1;
NV eps = 0.5;
bool
res = FALSE;
int
intsize = fldsize - (value < 0 ? 1 : 0);
if
(frcsize & FORM_NUM_POINT)
intsize--;
frcsize &= ~(FORM_NUM_POINT|FORM_NUM_BLANK);
intsize -= frcsize;
while
(intsize--) pwr *= 10.0;
while
(frcsize--) eps /= 10.0;
if
( value >= 0 ){
if
(value + eps >= pwr)
res = TRUE;
}
else
{
if
(value - eps <= -pwr)
res = TRUE;
}
return
res;
}
static
I32
S_run_user_filter(pTHX_
int
idx, SV *buf_sv,
int
maxlen)
{
SV *
const
datasv = FILTER_DATA(idx);
const
int
filter_has_file = IoLINES(datasv);
SV *
const
filter_state = MUTABLE_SV(IoTOP_GV(datasv));
SV *
const
filter_sub = MUTABLE_SV(IoBOTTOM_GV(datasv));
int
status = 0;
SV *upstream;
STRLEN got_len;
char
*got_p = NULL;
char
*prune_from = NULL;
bool
read_from_cache = FALSE;
STRLEN umaxlen;
SV *err = NULL;
PERL_ARGS_ASSERT_RUN_USER_FILTER;
assert
(maxlen >= 0);
umaxlen = maxlen;
{
SV *
const
cache = datasv;
if
(SvOK(cache)) {
STRLEN cache_len;
const
char
*cache_p = SvPV(cache, cache_len);
STRLEN take = 0;
if
(umaxlen) {
if
(cache_len >= umaxlen) {
take = umaxlen;
}
}
else
{
const
char
*
const
first_nl =
(
const
char
*)
memchr
(cache_p,
'\n'
, cache_len);
if
(first_nl) {
take = first_nl + 1 - cache_p;
}
}
if
(take) {
sv_catpvn(buf_sv, cache_p, take);
sv_chop(cache, cache_p + take);
return
1;
}
sv_catsv(buf_sv, cache);
if
(umaxlen) {
umaxlen -= cache_len;
}
SvOK_off(cache);
read_from_cache = TRUE;
}
}
upstream = ((SvOK(buf_sv) && sv_len(buf_sv)) || SvGMAGICAL(buf_sv))
? newSV_type_mortal(SVt_PV) : buf_sv;
SvUPGRADE(upstream, SVt_PV);
if
(filter_has_file) {
status = FILTER_READ(idx+1, upstream, 0);
}
if
(filter_sub && status >= 0) {
dSP;
int
count;
ENTER_with_name(
"call_filter_sub"
);
SAVE_DEFSV;
SAVETMPS;
EXTEND(SP, 2);
DEFSV_set(upstream);
PUSHMARK(SP);
PUSHs(&PL_sv_zero);
if
(filter_state) {
PUSHs(filter_state);
}
PUTBACK;
count = call_sv(filter_sub, G_SCALAR|G_EVAL);
SPAGAIN;
if
(count > 0) {
SV *out = POPs;
SvGETMAGIC(out);
if
(SvOK(out)) {
status = SvIV(out);
}
else
{
SV *
const
errsv = ERRSV;
if
(SvTRUE_NN(errsv))
err = newSVsv(errsv);
}
}
PUTBACK;
FREETMPS;
LEAVE_with_name(
"call_filter_sub"
);
}
if
(SvGMAGICAL(upstream)) {
mg_get(upstream);
if
(upstream == buf_sv) mg_free(buf_sv);
}
if
(SvIsCOW(upstream)) sv_force_normal(upstream);
if
(!err && SvOK(upstream)) {
got_p = SvPV_nomg(upstream, got_len);
if
(umaxlen) {
if
(got_len > umaxlen) {
prune_from = got_p + umaxlen;
}
}
else
{
char
*
const
first_nl = (
char
*)
memchr
(got_p,
'\n'
, got_len);
if
(first_nl && first_nl + 1 < got_p + got_len) {
prune_from = first_nl + 1;
}
}
}
if
(!err && prune_from) {
STRLEN cached_len = got_p + got_len - prune_from;
SV *
const
cache = datasv;
if
(SvOK(cache)) {
assert
(!SvCUR(cache));
}
sv_setpvn(cache, prune_from, cached_len);
if
(SvUTF8(upstream)) {
SvUTF8_on(cache);
}
if
(SvPOK(upstream)) SvCUR_set(upstream, got_len - cached_len);
else
sv_usepvn(upstream, savepvn(got_p, got_len - cached_len),
got_len - cached_len);
*prune_from = 0;
if
(status == 0)
status = 1;
}
if
(!err && upstream != buf_sv &&
SvOK(upstream)) {
sv_catsv_nomg(buf_sv, upstream);
}
else
if
(SvOK(upstream)) (
void
)SvPV_force_nolen(buf_sv);
if
(status <= 0) {
IoLINES(datasv) = 0;
if
(filter_state) {
SvREFCNT_dec(filter_state);
IoTOP_GV(datasv) = NULL;
}
if
(filter_sub) {
SvREFCNT_dec(filter_sub);
IoBOTTOM_GV(datasv) = NULL;
}
filter_del(S_run_user_filter);
}
if
(err)
croak_sv(err);
if
(status == 0 && read_from_cache) {
return
1;
}
return
status;
}