#include "EXTERN.h"
#define PERL_IN_MG_C
#include "perl.h"
#include "feature.h"
#if defined(HAS_GETGROUPS) || defined(HAS_SETGROUPS)
# ifdef I_GRP
# include <grp.h>
# endif
#endif
#if defined(HAS_SETGROUPS)
# ifndef NGROUPS
# define NGROUPS 32
# endif
#endif
#ifdef __hpux
# include <sys/pstat.h>
#endif
#ifdef HAS_PRCTL_SET_NAME
# include <sys/prctl.h>
#endif
#ifdef __Lynx__
void
setruid(uid_t id);
void
seteuid(uid_t id);
void
setrgid(uid_t id);
void
setegid(uid_t id);
#endif
struct
magic_state {
SV* mgs_sv;
I32 mgs_ss_ix;
U32 mgs_flags;
bool
mgs_bumped;
};
STATIC
void
S_save_magic_flags(pTHX_ I32 mgs_ix, SV *sv, U32 flags)
{
MGS* mgs;
bool
bumped = FALSE;
PERL_ARGS_ASSERT_SAVE_MAGIC_FLAGS;
assert
(SvMAGICAL(sv));
if
(SvREFCNT(sv) > 0) {
SvREFCNT_inc_simple_void_NN(sv);
bumped = TRUE;
}
SAVEDESTRUCTOR_X(S_restore_magic, INT2PTR(
void
*, (IV)mgs_ix));
mgs = SSPTR(mgs_ix, MGS*);
mgs->mgs_sv = sv;
mgs->mgs_flags = SvMAGICAL(sv) | SvREADONLY(sv);
mgs->mgs_ss_ix = PL_savestack_ix;
mgs->mgs_bumped = bumped;
SvFLAGS(sv) &= ~flags;
SvREADONLY_off(sv);
}
#define save_magic(a,b) save_magic_flags(a,b,SVs_GMG|SVs_SMG|SVs_RMG)
void
Perl_mg_magical(SV *sv)
{
const
MAGIC* mg;
PERL_ARGS_ASSERT_MG_MAGICAL;
SvMAGICAL_off(sv);
if
((mg = SvMAGIC(sv))) {
do
{
const
MGVTBL*
const
vtbl = mg->mg_virtual;
if
(vtbl) {
if
(vtbl->svt_get && !(mg->mg_flags & MGf_GSKIP))
SvGMAGICAL_on(sv);
if
(vtbl->svt_set)
SvSMAGICAL_on(sv);
if
(vtbl->svt_clear)
SvRMAGICAL_on(sv);
}
}
while
((mg = mg->mg_moremagic));
if
(!(SvFLAGS(sv) & (SVs_GMG|SVs_SMG)))
SvRMAGICAL_on(sv);
}
}
int
Perl_mg_get(pTHX_ SV *sv)
{
const
I32 mgs_ix = SSNEW(
sizeof
(MGS));
bool
saved = FALSE;
bool
have_new = 0;
bool
taint_only = TRUE;
MAGIC *newmg, *head, *cur, *mg;
PERL_ARGS_ASSERT_MG_GET;
if
(PL_localizing == 1 && sv == DEFSV)
return
0;
newmg = cur = head = mg = SvMAGIC(sv);
while
(mg) {
const
MGVTBL *
const
vtbl = mg->mg_virtual;
MAGIC *
const
nextmg = mg->mg_moremagic;
if
(!(mg->mg_flags & MGf_GSKIP) && vtbl && vtbl->svt_get) {
if
(mg->mg_type != PERL_MAGIC_taint) {
taint_only = FALSE;
if
(!saved) {
save_magic(mgs_ix, sv);
saved = TRUE;
}
}
vtbl->svt_get(aTHX_ sv, mg);
if
(!SvMAGIC(sv)) {
(SSPTR(mgs_ix, MGS *))->mgs_flags &= ~(SVs_GMG|SVs_SMG|SVs_RMG);
break
;
}
if
(mg->mg_flags & MGf_GSKIP)
(SSPTR(mgs_ix, MGS *))->mgs_flags &=
~(SVs_GMG|SVs_SMG|SVs_RMG);
}
else
if
(vtbl == &PL_vtbl_utf8) {
if
(taint_only) {
MAGIC *mg2;
for
(mg2 = nextmg; mg2; mg2 = mg2->mg_moremagic) {
if
( mg2->mg_type != PERL_MAGIC_taint
&& !(mg2->mg_flags & MGf_GSKIP)
&& mg2->mg_virtual
&& mg2->mg_virtual->svt_get
) {
taint_only = FALSE;
break
;
}
}
}
if
(!taint_only)
magic_setutf8(sv, mg);
}
mg = nextmg;
if
(have_new) {
if
(mg == head) {
have_new = 0;
mg = cur;
head = newmg;
}
}
if
(!have_new && (newmg = SvMAGIC(sv)) != head) {
have_new = 1;
cur = mg;
mg = newmg;
(SSPTR(mgs_ix, MGS *))->mgs_flags &= ~(SVs_GMG|SVs_SMG|SVs_RMG);
}
}
if
(saved)
restore_magic(INT2PTR(
void
*, (IV)mgs_ix));
return
0;
}
int
Perl_mg_set(pTHX_ SV *sv)
{
const
I32 mgs_ix = SSNEW(
sizeof
(MGS));
MAGIC* mg;
MAGIC* nextmg;
PERL_ARGS_ASSERT_MG_SET;
if
(PL_localizing == 2 && sv == DEFSV)
return
0;
save_magic_flags(mgs_ix, sv, SVs_GMG|SVs_SMG);
for
(mg = SvMAGIC(sv); mg; mg = nextmg) {
const
MGVTBL* vtbl = mg->mg_virtual;
nextmg = mg->mg_moremagic;
if
(mg->mg_flags & MGf_GSKIP) {
mg->mg_flags &= ~MGf_GSKIP;
(SSPTR(mgs_ix, MGS*))->mgs_flags &= ~(SVs_GMG|SVs_SMG|SVs_RMG);
}
if
(PL_localizing == 2
&& PERL_MAGIC_TYPE_IS_VALUE_MAGIC(mg->mg_type))
continue
;
if
(vtbl && vtbl->svt_set)
vtbl->svt_set(aTHX_ sv, mg);
}
restore_magic(INT2PTR(
void
*, (IV)mgs_ix));
return
0;
}
U32
Perl_mg_length(pTHX_ SV *sv)
{
MAGIC* mg;
STRLEN len;
PERL_ARGS_ASSERT_MG_LENGTH;
for
(mg = SvMAGIC(sv); mg; mg = mg->mg_moremagic) {
const
MGVTBL *
const
vtbl = mg->mg_virtual;
if
(vtbl && vtbl->svt_len) {
const
I32 mgs_ix = SSNEW(
sizeof
(MGS));
save_magic(mgs_ix, sv);
len = vtbl->svt_len(aTHX_ sv, mg);
restore_magic(INT2PTR(
void
*, (IV)mgs_ix));
return
len;
}
}
(
void
)SvPV_const(sv, len);
return
len;
}
I32
Perl_mg_size(pTHX_ SV *sv)
{
MAGIC* mg;
PERL_ARGS_ASSERT_MG_SIZE;
for
(mg = SvMAGIC(sv); mg; mg = mg->mg_moremagic) {
const
MGVTBL*
const
vtbl = mg->mg_virtual;
if
(vtbl && vtbl->svt_len) {
const
I32 mgs_ix = SSNEW(
sizeof
(MGS));
I32 len;
save_magic(mgs_ix, sv);
len = vtbl->svt_len(aTHX_ sv, mg);
restore_magic(INT2PTR(
void
*, (IV)mgs_ix));
return
len;
}
}
switch
(SvTYPE(sv)) {
case
SVt_PVAV:
return
AvFILLp((
const
AV *) sv);
case
SVt_PVHV:
default
:
Perl_croak(aTHX_
"Size magic not implemented"
);
}
NOT_REACHED;
}
int
Perl_mg_clear(pTHX_ SV *sv)
{
const
I32 mgs_ix = SSNEW(
sizeof
(MGS));
MAGIC* mg;
MAGIC *nextmg;
PERL_ARGS_ASSERT_MG_CLEAR;
save_magic(mgs_ix, sv);
for
(mg = SvMAGIC(sv); mg; mg = nextmg) {
const
MGVTBL*
const
vtbl = mg->mg_virtual;
nextmg = mg->mg_moremagic;
if
(vtbl && vtbl->svt_clear)
vtbl->svt_clear(aTHX_ sv, mg);
}
restore_magic(INT2PTR(
void
*, (IV)mgs_ix));
return
0;
}
static
MAGIC*
S_mg_findext_flags(
const
SV *sv,
int
type,
const
MGVTBL *vtbl, U32 flags)
{
assert
(flags <= 1);
if
(sv) {
MAGIC *mg;
for
(mg = SvMAGIC(sv); mg; mg = mg->mg_moremagic) {
if
(mg->mg_type == type && (!flags || mg->mg_virtual == vtbl)) {
return
mg;
}
}
}
return
NULL;
}
MAGIC*
Perl_mg_find(
const
SV *sv,
int
type)
{
return
S_mg_findext_flags(sv, type, NULL, 0);
}
MAGIC*
Perl_mg_findext(
const
SV *sv,
int
type,
const
MGVTBL *vtbl)
{
return
S_mg_findext_flags(sv, type, vtbl, 1);
}
MAGIC *
Perl_mg_find_mglob(pTHX_ SV *sv)
{
PERL_ARGS_ASSERT_MG_FIND_MGLOB;
if
(SvTYPE(sv) == SVt_PVLV && LvTYPE(sv) ==
'y'
) {
vivify_defelem(sv);
sv = LvTARG(sv);
}
if
(SvTYPE(sv) >= SVt_PVMG && SvMAGIC(sv))
return
S_mg_findext_flags(sv, PERL_MAGIC_regex_global, 0, 0);
return
NULL;
}
int
Perl_mg_copy(pTHX_ SV *sv, SV *nsv,
const
char
*key, I32 klen)
{
int
count = 0;
MAGIC* mg;
PERL_ARGS_ASSERT_MG_COPY;
for
(mg = SvMAGIC(sv); mg; mg = mg->mg_moremagic) {
const
MGVTBL*
const
vtbl = mg->mg_virtual;
if
((mg->mg_flags & MGf_COPY) && vtbl->svt_copy){
count += vtbl->svt_copy(aTHX_ sv, mg, nsv, key, klen);
}
else
{
const
char
type = mg->mg_type;
if
(isUPPER(type) && type != PERL_MAGIC_uvar) {
sv_magic(nsv,
(type == PERL_MAGIC_tied)
? SvTIED_obj(sv, mg)
: mg->mg_obj,
toLOWER(type), key, klen);
count++;
}
}
}
return
count;
}
void
Perl_mg_localize(pTHX_ SV *sv, SV *nsv,
bool
setmagic)
{
MAGIC *mg;
PERL_ARGS_ASSERT_MG_LOCALIZE;
if
(nsv == DEFSV)
return
;
for
(mg = SvMAGIC(sv); mg; mg = mg->mg_moremagic) {
const
MGVTBL*
const
vtbl = mg->mg_virtual;
if
(PERL_MAGIC_TYPE_IS_VALUE_MAGIC(mg->mg_type))
continue
;
if
((mg->mg_flags & MGf_LOCAL) && vtbl->svt_local)
(
void
)vtbl->svt_local(aTHX_ nsv, mg);
else
sv_magicext(nsv, mg->mg_obj, mg->mg_type, vtbl,
mg->mg_ptr, mg->mg_len);
SvFLAGS(nsv) |= SvREADONLY(sv);
}
if
(SvTYPE(nsv) >= SVt_PVMG && SvMAGIC(nsv)) {
SvFLAGS(nsv) |= SvMAGICAL(sv);
if
(setmagic) {
PL_localizing = 1;
SvSETMAGIC(nsv);
PL_localizing = 0;
}
}
}
#define mg_free_struct(sv, mg) S_mg_free_struct(aTHX_ sv, mg)
static
void
S_mg_free_struct(pTHX_ SV *sv, MAGIC *mg)
{
const
MGVTBL*
const
vtbl = mg->mg_virtual;
if
(vtbl && vtbl->svt_free)
vtbl->svt_free(aTHX_ sv, mg);
if
(mg->mg_len > 0)
Safefree(mg->mg_ptr);
else
if
(mg->mg_len == HEf_SVKEY)
SvREFCNT_dec(MUTABLE_SV(mg->mg_ptr));
if
(mg->mg_flags & MGf_REFCOUNTED)
SvREFCNT_dec(mg->mg_obj);
Safefree(mg);
}
int
Perl_mg_free(pTHX_ SV *sv)
{
MAGIC* mg;
MAGIC* moremagic;
PERL_ARGS_ASSERT_MG_FREE;
for
(mg = SvMAGIC(sv); mg; mg = moremagic) {
moremagic = mg->mg_moremagic;
mg_free_struct(sv, mg);
SvMAGIC_set(sv, moremagic);
}
SvMAGIC_set(sv, NULL);
SvMAGICAL_off(sv);
return
0;
}
void
Perl_mg_free_type(pTHX_ SV *sv,
int
how)
{
MAGIC *mg, *prevmg, *moremg;
PERL_ARGS_ASSERT_MG_FREE_TYPE;
for
(prevmg = NULL, mg = SvMAGIC(sv); mg; prevmg = mg, mg = moremg) {
moremg = mg->mg_moremagic;
if
(mg->mg_type == how) {
MAGIC *newhead;
if
(prevmg) {
prevmg->mg_moremagic = moremg;
mg->mg_moremagic = SvMAGIC(sv);
SvMAGIC_set(sv, mg);
}
newhead = mg->mg_moremagic;
mg_free_struct(sv, mg);
SvMAGIC_set(sv, newhead);
mg = prevmg;
}
}
mg_magical(sv);
}
void
Perl_mg_freeext(pTHX_ SV *sv,
int
how,
const
MGVTBL *vtbl)
{
MAGIC *mg, *prevmg, *moremg;
PERL_ARGS_ASSERT_MG_FREEEXT;
for
(prevmg = NULL, mg = SvMAGIC(sv); mg; prevmg = mg, mg = moremg) {
MAGIC *newhead;
moremg = mg->mg_moremagic;
if
(mg->mg_type == how && (vtbl == NULL || mg->mg_virtual == vtbl)) {
if
(prevmg) {
prevmg->mg_moremagic = moremg;
mg->mg_moremagic = SvMAGIC(sv);
SvMAGIC_set(sv, mg);
}
newhead = mg->mg_moremagic;
mg_free_struct(sv, mg);
SvMAGIC_set(sv, newhead);
mg = prevmg;
}
}
mg_magical(sv);
}
#include <signal.h>
U32
Perl_magic_regdata_cnt(pTHX_ SV *sv, MAGIC *mg)
{
PERL_UNUSED_ARG(sv);
PERL_ARGS_ASSERT_MAGIC_REGDATA_CNT;
if
(PL_curpm) {
REGEXP *
const
rx = PM_GETRE(PL_curpm);
if
(rx) {
const
SSize_t n = (SSize_t)mg->mg_obj;
if
(n ==
'+'
) {
return
RX_NPARENS(rx);
}
else
{
I32 paren = RX_LASTPAREN(rx);
while
( paren >= 0
&& (RX_OFFS(rx)[paren].start == -1
|| RX_OFFS(rx)[paren].end == -1) )
paren--;
if
(n ==
'-'
) {
return
(U32)paren;
}
else
{
return
paren >= 0 ? (U32)(paren-1) : (U32)-1;
}
}
}
}
return
(U32)-1;
}
int
Perl_magic_regdatum_get(pTHX_ SV *sv, MAGIC *mg)
{
PERL_ARGS_ASSERT_MAGIC_REGDATUM_GET;
if
(PL_curpm) {
REGEXP *
const
rx = PM_GETRE(PL_curpm);
if
(rx) {
const
SSize_t n = (SSize_t)mg->mg_obj;
const
I32 paren = mg->mg_len
+ (n ==
'\003'
? 1 : 0);
SSize_t s;
SSize_t t;
if
(paren < 0)
return
0;
if
(paren <= (I32)RX_NPARENS(rx) &&
(s = RX_OFFS(rx)[paren].start) != -1 &&
(t = RX_OFFS(rx)[paren].end) != -1)
{
SSize_t i;
if
(n ==
'+'
)
i = t;
else
if
(n ==
'-'
)
i = s;
else
{
CALLREG_NUMBUF_FETCH(rx,paren,sv);
return
0;
}
if
(RX_MATCH_UTF8(rx)) {
const
char
*
const
b = RX_SUBBEG(rx);
if
(b)
i = RX_SUBCOFFSET(rx) +
utf8_length((U8*)b,
(U8*)(b-RX_SUBOFFSET(rx)+i));
}
sv_setuv(sv, i);
return
0;
}
}
}
sv_set_undef(sv);
return
0;
}
int
Perl_magic_regdatum_set(pTHX_ SV *sv, MAGIC *mg)
{
PERL_ARGS_ASSERT_MAGIC_REGDATUM_SET;
PERL_UNUSED_CONTEXT;
PERL_UNUSED_ARG(sv);
PERL_UNUSED_ARG(mg);
Perl_croak_no_modify();
NORETURN_FUNCTION_END;
}
#define SvRTRIM(sv) STMT_START { \
if
(SvPOK(sv)) { \
STRLEN len = SvCUR(sv); \
char
*
const
p = SvPVX(sv); \
while
(len > 0 && isSPACE(p[len-1])) \
--len; \
SvCUR_set(sv, len); \
p[len] =
'\0'
; \
} \
} STMT_END
void
Perl_emulate_cop_io(pTHX_
const
COP *
const
c, SV *
const
sv)
{
PERL_ARGS_ASSERT_EMULATE_COP_IO;
if
(!(CopHINTS_get(c) & (HINT_LEXICAL_IO_IN|HINT_LEXICAL_IO_OUT)))
sv_set_undef(sv);
else
{
SvPVCLEAR(sv);
SvUTF8_off(sv);
if
((CopHINTS_get(c) & HINT_LEXICAL_IO_IN)) {
SV *
const
value = cop_hints_fetch_pvs(c,
"open<"
, 0);
assert
(value);
sv_catsv(sv, value);
}
sv_catpvs(sv,
"\0"
);
if
((CopHINTS_get(c) & HINT_LEXICAL_IO_OUT)) {
SV *
const
value = cop_hints_fetch_pvs(c,
"open>"
, 0);
assert
(value);
sv_catsv(sv, value);
}
}
}
STATIC
void
S_fixup_errno_string(pTHX_ SV* sv)
{
PERL_ARGS_ASSERT_FIXUP_ERRNO_STRING;
assert
(SvOK(sv));
if
(strEQ(SvPVX(sv),
""
)) {
sv_catpv(sv, UNKNOWN_ERRNO_MSG);
}
else
{
if
( ! IN_BYTES
&& is_utf8_non_invariant_string((U8*) SvPVX_const(sv), SvCUR(sv))
#ifdef USE_LOCALE_MESSAGES
&& _is_cur_LC_category_utf8(LC_MESSAGES)
#else /* If can't check directly, at least can see if script is consistent,
under UTF-8, which gives us an extra measure of confidence. */
&& isSCRIPT_RUN((
const
U8 *) SvPVX_const(sv), (U8 *) SvEND(sv),
TRUE)
#endif
) {
SvUTF8_on(sv);
}
}
}
SV *
Perl_sv_string_from_errnum(pTHX_
int
errnum, SV *tgtsv)
{
char
const
*errstr;
if
(!tgtsv)
tgtsv = newSV_type_mortal(SVt_PV);
errstr = my_strerror(errnum);
if
(errstr) {
sv_setpv(tgtsv, errstr);
fixup_errno_string(tgtsv);
}
else
{
SvPVCLEAR(tgtsv);
}
return
tgtsv;
}
#ifdef VMS
#include <descrip.h>
#include <starlet.h>
#endif
int
Perl_magic_get(pTHX_ SV *sv, MAGIC *mg)
{
I32 paren;
const
char
*s = NULL;
REGEXP *rx;
const
char
*
const
remaining = mg->mg_ptr + 1;
char
nextchar;
PERL_ARGS_ASSERT_MAGIC_GET;
if
(!mg->mg_ptr) {
paren = mg->mg_len;
if
(PL_curpm && (rx = PM_GETRE(PL_curpm))) {
do_numbuf_fetch:
CALLREG_NUMBUF_FETCH(rx,paren,sv);
}
else
goto
set_undef;
return
0;
}
nextchar = *remaining;
switch
(*mg->mg_ptr) {
case
'\001'
:
if
(SvOK(PL_bodytarget)) sv_copypv(sv, PL_bodytarget);
else
sv_set_undef(sv);
if
(SvTAINTED(PL_bodytarget))
SvTAINTED_on(sv);
break
;
case
'\003'
:
if
(nextchar ==
'\0'
) {
sv_setiv(sv, (IV)PL_minus_c);
}
else
if
(strEQ(remaining,
"HILD_ERROR_NATIVE"
)) {
sv_setiv(sv, (IV)STATUS_NATIVE);
}
break
;
case
'\004'
:
sv_setiv(sv, (IV)(PL_debug & DEBUG_MASK));
break
;
case
'\005'
:
if
(nextchar !=
'\0'
) {
if
(strEQ(remaining,
"NCODING"
))
sv_set_undef(sv);
break
;
}
#if defined(VMS) || defined(OS2) || defined(WIN32)
# if defined(VMS)
{
char
msg[255];
$DESCRIPTOR(msgdsc,msg);
sv_setnv(sv,(NV) vaxc$
errno
);
if
(sys$getmsg(vaxc$
errno
,&msgdsc.dsc$w_length,&msgdsc,0,0) & 1)
sv_setpvn(sv,msgdsc.dsc$a_pointer,msgdsc.dsc$w_length);
else
SvPVCLEAR(sv);
}
#elif defined(OS2)
if
(!(_emx_env & 0x200)) {
sv_setnv(sv, (NV)
errno
);
sv_setpv(sv,
errno
? my_strerror(
errno
) :
""
);
}
else
{
if
(
errno
!= errno_isOS2) {
const
int
tmp = _syserrno();
if
(tmp)
Perl_rc = tmp;
}
sv_setnv(sv, (NV)Perl_rc);
sv_setpv(sv, os2error(Perl_rc));
}
if
(SvOK(sv) && strNE(SvPVX(sv),
""
)) {
fixup_errno_string(sv);
}
# elif defined(WIN32)
{
const
DWORD
dwErr = GetLastError();
sv_setnv(sv, (NV)dwErr);
if
(dwErr) {
PerlProc_GetOSError(sv, dwErr);
fixup_errno_string(sv);
}
else
SvPVCLEAR(sv);
SetLastError(dwErr);
}
# else
# error Missing code for platform
# endif
SvRTRIM(sv);
SvNOK_on(sv);
break
;
#endif /* End of platforms with special handling for $^E; others just fall
through to $! */
case
'!'
:
{
dSAVE_ERRNO;
#ifdef VMS
sv_setnv(sv, (NV)((
errno
== EVMSERR) ? vaxc$
errno
:
errno
));
#else
sv_setnv(sv, (NV)
errno
);
#endif
#ifdef OS2
if
(
errno
== errno_isOS2 ||
errno
== errno_isOS2_set)
sv_setpv(sv, os2error(Perl_rc));
else
#endif
if
(!
errno
) {
SvPVCLEAR(sv);
}
else
{
sv_string_from_errnum(
errno
, sv);
if
(!SvCUR(sv))
SvPOK_off(sv);
}
RESTORE_ERRNO;
}
SvRTRIM(sv);
SvNOK_on(sv);
break
;
case
'\006'
:
if
(nextchar ==
'\0'
) {
sv_setiv(sv, (IV)PL_maxsysfd);
}
break
;
case
'\007'
:
if
(strEQ(remaining,
"LOBAL_PHASE"
)) {
sv_setpvn(sv, PL_phase_names[PL_phase],
strlen
(PL_phase_names[PL_phase]));
}
break
;
case
'\010'
:
sv_setuv(sv, PL_hints);
break
;
case
'\011'
:
sv_setpv(sv, PL_inplace);
break
;
case
'\014'
:
if
(strEQ(remaining,
"AST_FH"
)) {
if
(PL_last_in_gv && (SV*)PL_last_in_gv != &PL_sv_undef) {
assert
(isGV_with_GP(PL_last_in_gv));
sv_setrv_inc(sv, MUTABLE_SV(PL_last_in_gv));
sv_rvweaken(sv);
}
else
sv_set_undef(sv);
}
break
;
case
'\017'
:
if
(nextchar ==
'\0'
) {
sv_setpv(sv, PL_osname);
SvTAINTED_off(sv);
}
else
if
(strEQ(remaining,
"PEN"
)) {
Perl_emulate_cop_io(aTHX_ &PL_compiling, sv);
}
break
;
case
'\020'
:
sv_setiv(sv, (IV)PL_perldb);
break
;
case
'\023'
:
if
(nextchar ==
'\0'
) {
if
(PL_parser && PL_parser->lex_state != LEX_NOTPARSING)
SvOK_off(sv);
else
if
(PL_in_eval)
sv_setiv(sv, PL_in_eval & ~(EVAL_INREQUIRE));
else
sv_setiv(sv, 0);
}
else
if
(strEQ(remaining,
"AFE_LOCALES"
)) {
#if ! defined(USE_ITHREADS) || defined(USE_THREAD_SAFE_LOCALE)
sv_setuv(sv, (UV) 1);
#else
sv_setuv(sv, (UV) 0);
#endif
}
break
;
case
'\024'
:
if
(nextchar ==
'\0'
) {
#ifdef BIG_TIME
sv_setnv(sv, PL_basetime);
#else
sv_setiv(sv, (IV)PL_basetime);
#endif
}
else
if
(strEQ(remaining,
"AINT"
))
sv_setiv(sv, TAINTING_get
? (TAINT_WARN_get || PL_unsafe ? -1 : 1)
: 0);
break
;
case
'\025'
:
if
(strEQ(remaining,
"NICODE"
))
sv_setuv(sv, (UV) PL_unicode);
else
if
(strEQ(remaining,
"TF8LOCALE"
))
sv_setuv(sv, (UV) PL_utf8locale);
else
if
(strEQ(remaining,
"TF8CACHE"
))
sv_setiv(sv, (IV) PL_utf8cache);
break
;
case
'\027'
:
if
(nextchar ==
'\0'
)
sv_setiv(sv, (IV)cBOOL(PL_dowarn & G_WARN_ON));
else
if
(strEQ(remaining,
"ARNING_BITS"
)) {
if
(PL_compiling.cop_warnings == pWARN_NONE) {
sv_setpvn(sv, WARN_NONEstring, WARNsize) ;
}
else
if
(PL_compiling.cop_warnings == pWARN_STD) {
goto
set_undef;
}
else
if
(PL_compiling.cop_warnings == pWARN_ALL) {
sv_setpvn(sv, WARN_ALLstring, WARNsize);
}
else
{
sv_setpvn(sv, (
char
*) (PL_compiling.cop_warnings + 1),
*PL_compiling.cop_warnings);
}
}
break
;
case
'+'
:
if
(PL_curpm && (rx = PM_GETRE(PL_curpm))) {
paren = RX_LASTPAREN(rx);
if
(paren)
goto
do_numbuf_fetch;
}
goto
set_undef;
case
'\016'
:
if
(PL_curpm && (rx = PM_GETRE(PL_curpm))) {
paren = RX_LASTCLOSEPAREN(rx);
if
(paren)
goto
do_numbuf_fetch;
}
goto
set_undef;
case
'.'
:
if
(GvIO(PL_last_in_gv)) {
sv_setiv(sv, (IV)IoLINES(GvIOp(PL_last_in_gv)));
}
break
;
case
'?'
:
{
sv_setiv(sv, (IV)STATUS_CURRENT);
#ifdef COMPLEX_STATUS
SvUPGRADE(sv, SVt_PVLV);
LvTARGOFF(sv) = PL_statusvalue;
LvTARGLEN(sv) = PL_statusvalue_vms;
#endif
}
break
;
case
'^'
:
if
(GvIOp(PL_defoutgv))
s = IoTOP_NAME(GvIOp(PL_defoutgv));
if
(s)
sv_setpv(sv,s);
else
{
sv_setpv(sv,GvENAME(PL_defoutgv));
sv_catpvs(sv,
"_TOP"
);
}
break
;
case
'~'
:
if
(GvIOp(PL_defoutgv))
s = IoFMT_NAME(GvIOp(PL_defoutgv));
if
(!s)
s = GvENAME(PL_defoutgv);
sv_setpv(sv,s);
break
;
case
'='
:
if
(GvIO(PL_defoutgv))
sv_setiv(sv, (IV)IoPAGE_LEN(GvIOp(PL_defoutgv)));
break
;
case
'-'
:
if
(GvIO(PL_defoutgv))
sv_setiv(sv, (IV)IoLINES_LEFT(GvIOp(PL_defoutgv)));
break
;
case
'%'
:
if
(GvIO(PL_defoutgv))
sv_setiv(sv, (IV)IoPAGE(GvIOp(PL_defoutgv)));
break
;
case
':'
:
case
'/'
:
break
;
case
'['
:
sv_setiv(sv, 0);
break
;
case
'|'
:
if
(GvIO(PL_defoutgv))
sv_setiv(sv, (IV)(IoFLAGS(GvIOp(PL_defoutgv)) & IOf_FLUSH) != 0 );
break
;
case
'\\'
:
if
(PL_ors_sv)
sv_copypv(sv, PL_ors_sv);
else
goto
set_undef;
break
;
case
'$'
:
{
IV
const
pid = (IV)PerlProc_getpid();
if
(isGV(mg->mg_obj) || SvIV(mg->mg_obj) != pid) {
sv_setiv(sv, pid);
SvTAINTED_off(sv);
}
}
break
;
case
'<'
:
sv_setuid(sv, PerlProc_getuid());
break
;
case
'>'
:
sv_setuid(sv, PerlProc_geteuid());
break
;
case
'('
:
sv_setgid(sv, PerlProc_getgid());
goto
add_groups;
case
')'
:
sv_setgid(sv, PerlProc_getegid());
add_groups:
#ifdef HAS_GETGROUPS
{
Groups_t *gary = NULL;
I32 num_groups = getgroups(0, gary);
if
(num_groups > 0) {
I32 i;
Newx(gary, num_groups, Groups_t);
num_groups = getgroups(num_groups, gary);
for
(i = 0; i < num_groups; i++)
Perl_sv_catpvf(aTHX_ sv,
" %"
IVdf, (IV)gary[i]);
Safefree(gary);
}
}
(
void
)SvIOKp_on(sv);
#endif
break
;
case
'0'
:
break
;
}
return
0;
set_undef:
sv_set_undef(sv);
return
0;
}
int
Perl_magic_getuvar(pTHX_ SV *sv, MAGIC *mg)
{
struct
ufuncs *
const
uf = (
struct
ufuncs *)mg->mg_ptr;
PERL_ARGS_ASSERT_MAGIC_GETUVAR;
if
(uf && uf->uf_val)
(*uf->uf_val)(aTHX_ uf->uf_index, sv);
return
0;
}
int
Perl_magic_setenv(pTHX_ SV *sv, MAGIC *mg)
{
STRLEN len = 0, klen;
const
char
*key;
const
char
*s =
""
;
SV *keysv = MgSV(mg);
if
(keysv == NULL) {
key = mg->mg_ptr;
klen = mg->mg_len;
}
else
{
if
(!sv_utf8_downgrade(keysv,
TRUE)) {
Perl_ck_warner_d(aTHX_ packWARN(WARN_UTF8),
"Wide character in %s"
,
"setenv key (encoding to utf8)"
);
}
key = SvPV_const(keysv,klen);
}
PERL_ARGS_ASSERT_MAGIC_SETENV;
SvGETMAGIC(sv);
if
(SvOK(sv)) {
(
void
)SvPV_force_nomg_nolen(sv);
sv_utf8_downgrade(sv,
TRUE);
if
(SvUTF8(sv)) {
Perl_ck_warner_d(aTHX_ packWARN(WARN_UTF8),
"Wide character in %s"
,
"setenv"
);
SvUTF8_off(sv);
}
s = SvPVX(sv);
len = SvCUR(sv);
}
my_setenv(key, s);
#ifdef DYNAMIC_ENV_FETCH
if
(!len) {
SV **
const
valp = hv_fetch(GvHVn(PL_envgv), key, klen, FALSE);
if
(valp)
s = SvOK(*valp) ? SvPV_const(*valp, len) :
""
;
}
#endif
#if !defined(OS2) && !defined(WIN32)
if
(TAINTING_get) {
MgTAINTEDDIR_off(mg);
#ifdef VMS
if
(s && memEQs(key, klen,
"DCL$PATH"
)) {
char
pathbuf[256], eltbuf[256], *cp, *elt;
int
i = 0, j = 0;
my_strlcpy(eltbuf, s,
sizeof
(eltbuf));
elt = eltbuf;
do
{
while
(1) {
if
( ((cp =
strchr
(elt,
'['
)) || (cp =
strchr
(elt,
'<'
))) ) {
if
( *(cp+1) ==
'.'
|| *(cp+1) ==
'-'
||
cando_by_name(S_IWUSR,0,elt) ) {
MgTAINTEDDIR_on(mg);
return
0;
}
}
if
((cp =
strchr
(elt,
':'
)) != NULL)
*cp =
'\0'
;
if
(my_trnlnm(elt, eltbuf, j++))
elt = eltbuf;
else
break
;
}
j = 0;
}
while
(my_trnlnm(s, pathbuf, i++) && (elt = pathbuf));
}
#endif /* VMS */
if
(s && memEQs(key, klen,
"PATH"
)) {
const
char
*
const
strend = s + len;
#ifdef __VMS /* Hmm. How do we get $Config{path_sep} from C? */
const
char
path_sep = PL_perllib_sep;
#else
const
char
path_sep =
':'
;
#endif
while
(s < strend) {
char
tmpbuf[256];
Stat_t st;
I32 i;
s = delimcpy_no_escape(tmpbuf, tmpbuf +
sizeof
tmpbuf,
s, strend, path_sep, &i);
s++;
if
(i >= (I32)
sizeof
tmpbuf
#ifdef __VMS
|| (PL_perllib_sep !=
':'
&& !
strchr
(tmpbuf,
':'
))
|| (PL_perllib_sep ==
':'
&& *tmpbuf !=
'/'
)
#else
|| *tmpbuf !=
'/'
#endif
|| (PerlLIO_stat(tmpbuf, &st) == 0 && (st.st_mode & 2)) ) {
MgTAINTEDDIR_on(mg);
return
0;
}
}
}
}
#endif /* neither OS2 nor WIN32 */
return
0;
}
int
Perl_magic_clearenv(pTHX_ SV *sv, MAGIC *mg)
{
PERL_ARGS_ASSERT_MAGIC_CLEARENV;
PERL_UNUSED_ARG(sv);
my_setenv(MgPV_nolen_const(mg),NULL);
return
0;
}
int
Perl_magic_set_all_env(pTHX_ SV *sv, MAGIC *mg)
{
PERL_ARGS_ASSERT_MAGIC_SET_ALL_ENV;
PERL_UNUSED_ARG(mg);
#if defined(VMS)
Perl_die(aTHX_
"Can't make list assignment to %%ENV on this system"
);
#else
if
(PL_localizing) {
HE* entry;
my_clearenv();
hv_iterinit(MUTABLE_HV(sv));
while
((entry = hv_iternext(MUTABLE_HV(sv)))) {
I32 keylen;
my_setenv(hv_iterkey(entry, &keylen),
SvPV_nolen_const(hv_iterval(MUTABLE_HV(sv), entry)));
}
}
#endif
return
0;
}
int
Perl_magic_clear_all_env(pTHX_ SV *sv, MAGIC *mg)
{
PERL_ARGS_ASSERT_MAGIC_CLEAR_ALL_ENV;
PERL_UNUSED_ARG(sv);
PERL_UNUSED_ARG(mg);
#if defined(VMS)
Perl_die(aTHX_
"Can't make list assignment to %%ENV on this system"
);
#else
my_clearenv();
#endif
return
0;
}
#ifndef PERL_MICRO
#ifdef HAS_SIGPROCMASK
static
void
restore_sigmask(pTHX_ SV *save_sv)
{
const
sigset_t *
const
ossetp = (
const
sigset_t *) SvPV_nolen_const( save_sv );
(
void
)sigprocmask(SIG_SETMASK, ossetp, NULL);
}
#endif
int
Perl_magic_getsig(pTHX_ SV *sv, MAGIC *mg)
{
int
i = (I16)mg->mg_private;
PERL_ARGS_ASSERT_MAGIC_GETSIG;
if
(!i) {
STRLEN siglen;
const
char
* sig = MgPV_const(mg, siglen);
mg->mg_private = i = whichsig_pvn(sig, siglen);
}
if
(i > 0) {
if
(PL_psig_ptr[i])
sv_setsv(sv,PL_psig_ptr[i]);
else
{
Sighandler_t sigstate = rsignal_state(i);
#ifdef FAKE_PERSISTENT_SIGNAL_HANDLERS
if
(PL_sig_handlers_initted && PL_sig_ignoring[i])
sigstate = SIG_IGN;
#endif
#ifdef FAKE_DEFAULT_SIGNAL_HANDLERS
if
(PL_sig_handlers_initted && PL_sig_defaulting[i])
sigstate = SIG_DFL;
#endif
if
(sigstate == (Sighandler_t) SIG_IGN)
sv_setpvs(sv,
"IGNORE"
);
else
sv_set_undef(sv);
PL_psig_ptr[i] = SvREFCNT_inc_simple_NN(sv);
SvTEMP_off(sv);
}
}
return
0;
}
int
Perl_magic_clearsig(pTHX_ SV *sv, MAGIC *mg)
{
PERL_ARGS_ASSERT_MAGIC_CLEARSIG;
magic_setsig(NULL, mg);
return
sv_unmagic(sv, mg->mg_type);
}
#ifdef PERL_USE_3ARG_SIGHANDLER
Signal_t
Perl_csighandler(
int
sig, Siginfo_t *sip,
void
*uap)
{
Perl_csighandler3(sig, sip, uap);
}
#else
Signal_t
Perl_csighandler(
int
sig)
{
Perl_csighandler3(sig, NULL, NULL);
}
#endif
Signal_t
Perl_csighandler1(
int
sig)
{
Perl_csighandler3(sig, NULL, NULL);
}
Signal_t
Perl_csighandler3(
int
sig, Siginfo_t *sip PERL_UNUSED_DECL,
void
*uap PERL_UNUSED_DECL)
{
#ifdef PERL_GET_SIG_CONTEXT
dTHXa(PERL_GET_SIG_CONTEXT);
#else
dTHX;
#endif
#ifdef PERL_USE_3ARG_SIGHANDLER
#if defined(__cplusplus) && defined(__GNUC__)
PERL_UNUSED_ARG(sip);
PERL_UNUSED_ARG(uap);
#endif
#endif
#ifdef FAKE_PERSISTENT_SIGNAL_HANDLERS
(
void
) rsignal(sig, PL_csighandlerp);
if
(PL_sig_ignoring[sig])
return
;
#endif
#ifdef FAKE_DEFAULT_SIGNAL_HANDLERS
if
(PL_sig_defaulting[sig])
#ifdef KILL_BY_SIGPRC
exit
((Perl_sig_to_vmscondition(sig)&STS$M_COND_ID)|STS$K_SEVERE|STS$M_INHIB_MSG);
#else
exit
(1);
#endif
#endif
if
(
#ifdef SIGILL
sig == SIGILL ||
#endif
#ifdef SIGBUS
sig == SIGBUS ||
#endif
#ifdef SIGSEGV
sig == SIGSEGV ||
#endif
#ifdef SIGFPE
sig == SIGFPE ||
#endif
(PL_signals & PERL_SIGNALS_UNSAFE_FLAG))
{
if
(PL_sighandlerp == Perl_sighandler)
Perl_perly_sighandler(sig, NULL, NULL, 0
);
else
#ifdef PERL_USE_3ARG_SIGHANDLER
(*PL_sighandlerp)(sig, NULL, NULL);
#else
(*PL_sighandlerp)(sig);
#endif
}
else
{
if
(!PL_psig_pend)
return
;
PL_psig_pend[sig]++;
#ifndef SIG_PENDING_DIE_COUNT
# define SIG_PENDING_DIE_COUNT 120
#endif
if
(++PL_sig_pending >= SIG_PENDING_DIE_COUNT)
Perl_croak(aTHX_
"Maximal count of pending signals (%lu) exceeded"
,
(unsigned
long
)SIG_PENDING_DIE_COUNT);
}
}
#if defined(FAKE_PERSISTENT_SIGNAL_HANDLERS) || defined(FAKE_DEFAULT_SIGNAL_HANDLERS)
void
Perl_csighandler_init(
void
)
{
int
sig;
if
(PL_sig_handlers_initted)
return
;
for
(sig = 1; sig < SIG_SIZE; sig++) {
#ifdef FAKE_DEFAULT_SIGNAL_HANDLERS
dTHX;
PL_sig_defaulting[sig] = 1;
(
void
) rsignal(sig, PL_csighandlerp);
#endif
#ifdef FAKE_PERSISTENT_SIGNAL_HANDLERS
PL_sig_ignoring[sig] = 0;
#endif
}
PL_sig_handlers_initted = 1;
}
#endif
#if defined HAS_SIGPROCMASK
static
void
unblock_sigmask(pTHX_
void
* newset)
{
PERL_UNUSED_CONTEXT;
sigprocmask(SIG_UNBLOCK, (sigset_t*)newset, NULL);
}
#endif
void
Perl_despatch_signals(pTHX)
{
int
sig;
PL_sig_pending = 0;
for
(sig = 1; sig < SIG_SIZE; sig++) {
if
(PL_psig_pend[sig]) {
dSAVE_ERRNO;
#ifdef HAS_SIGPROCMASK
int
was_blocked;
sigset_t newset, oldset;
sigemptyset(&newset);
sigaddset(&newset, sig);
sigprocmask(SIG_BLOCK, &newset, &oldset);
was_blocked = sigismember(&oldset, sig);
if
(!was_blocked) {
SV* save_sv = newSVpvn((
char
*)(&newset),
sizeof
(sigset_t));
ENTER;
SAVEFREESV(save_sv);
SAVEDESTRUCTOR_X(unblock_sigmask, SvPV_nolen(save_sv));
}
#endif
PL_psig_pend[sig] = 0;
if
(PL_sighandlerp == Perl_sighandler)
Perl_perly_sighandler(sig, NULL, NULL, 1
);
else
#ifdef PERL_USE_3ARG_SIGHANDLER
(*PL_sighandlerp)(sig, NULL, NULL);
#else
(*PL_sighandlerp)(sig);
#endif
#ifdef HAS_SIGPROCMASK
if
(!was_blocked)
LEAVE;
#endif
RESTORE_ERRNO;
}
}
}
int
Perl_magic_setsig(pTHX_ SV *sv, MAGIC *mg)
{
I32 i;
SV** svp = NULL;
SV* to_dec = NULL;
STRLEN len;
#ifdef HAS_SIGPROCMASK
sigset_t set, save;
SV* save_sv;
#endif
const
char
*s = MgPV_const(mg,len);
PERL_ARGS_ASSERT_MAGIC_SETSIG;
if
(*s ==
'_'
) {
if
(memEQs(s, len,
"__DIE__"
))
svp = &PL_diehook;
else
if
(memEQs(s, len,
"__WARN__"
)
&& (sv ? 1 : PL_warnhook != PERL_WARNHOOK_FATAL)) {
svp = &PL_warnhook;
}
else
if
(sv) {
SV *tmp = sv_newmortal();
Perl_croak(aTHX_
"No such hook: %s"
,
pv_pretty(tmp, s, len, 0, NULL, NULL, 0));
}
i = 0;
if
(svp && *svp) {
if
(*svp != PERL_WARNHOOK_FATAL)
to_dec = *svp;
*svp = NULL;
}
}
else
{
i = (I16)mg->mg_private;
if
(!i) {
i = whichsig_pvn(s, len);
mg->mg_private = (U16)i;
}
if
(i <= 0) {
if
(sv) {
SV *tmp = sv_newmortal();
Perl_ck_warner(aTHX_ packWARN(WARN_SIGNAL),
"No such signal: SIG%s"
,
pv_pretty(tmp, s, len, 0, NULL, NULL, 0));
}
return
0;
}
#ifdef HAS_SIGPROCMASK
sigemptyset(&set);
sigaddset(&set,i);
sigprocmask(SIG_BLOCK, &set, &save);
ENTER;
save_sv = newSVpvn((
char
*)(&save),
sizeof
(sigset_t));
SAVEFREESV(save_sv);
SAVEDESTRUCTOR_X(restore_sigmask, save_sv);
#endif
PERL_ASYNC_CHECK();
#if defined(FAKE_PERSISTENT_SIGNAL_HANDLERS) || defined(FAKE_DEFAULT_SIGNAL_HANDLERS)
if
(!PL_sig_handlers_initted) Perl_csighandler_init();
#endif
#ifdef FAKE_PERSISTENT_SIGNAL_HANDLERS
PL_sig_ignoring[i] = 0;
#endif
#ifdef FAKE_DEFAULT_SIGNAL_HANDLERS
PL_sig_defaulting[i] = 0;
#endif
to_dec = PL_psig_ptr[i];
if
(sv) {
PL_psig_ptr[i] = SvREFCNT_inc_simple_NN(sv);
SvTEMP_off(sv);
if
(!PL_psig_name[i]) {
const
char
* name = PL_sig_name[i];
PL_psig_name[i] = newSVpvn(name,
strlen
(name));
SvREADONLY_on(PL_psig_name[i]);
}
}
else
{
SvREFCNT_dec(PL_psig_name[i]);
PL_psig_name[i] = NULL;
PL_psig_ptr[i] = NULL;
}
}
if
(sv && (isGV_with_GP(sv) || SvROK(sv))) {
if
(i) {
(
void
)rsignal(i, PL_csighandlerp);
}
else
*svp = SvREFCNT_inc_simple_NN(sv);
}
else
{
if
(sv && SvOK(sv)) {
s = SvPV_force(sv, len);
}
else
{
sv = NULL;
}
if
(sv && memEQs(s, len,
"IGNORE"
)) {
if
(i) {
#ifdef FAKE_PERSISTENT_SIGNAL_HANDLERS
PL_sig_ignoring[i] = 1;
(
void
)rsignal(i, PL_csighandlerp);
#else
(
void
)rsignal(i, (Sighandler_t) SIG_IGN);
#endif
}
}
else
if
(!sv || memEQs(s, len,
"DEFAULT"
) || !len) {
if
(i) {
#ifdef FAKE_DEFAULT_SIGNAL_HANDLERS
PL_sig_defaulting[i] = 1;
(
void
)rsignal(i, PL_csighandlerp);
#else
(
void
)rsignal(i, (Sighandler_t) SIG_DFL);
#endif
}
}
else
{
if
(!
memchr
(s,
':'
, len) && !
memchr
(s,
'\''
, len))
Perl_sv_insert_flags(aTHX_ sv, 0, 0, STR_WITH_LEN(
"main::"
),
SV_GMAGIC);
if
(i)
(
void
)rsignal(i, PL_csighandlerp);
else
*svp = SvREFCNT_inc_simple_NN(sv);
}
}
#ifdef HAS_SIGPROCMASK
if
(i)
LEAVE;
#endif
SvREFCNT_dec(to_dec);
return
0;
}
#endif /* !PERL_MICRO */
int
Perl_magic_setsigall(pTHX_ SV* sv, MAGIC* mg)
{
PERL_ARGS_ASSERT_MAGIC_SETSIGALL;
PERL_UNUSED_ARG(mg);
if
(PL_localizing == 2) {
HV* hv = (HV*)sv;
HE* current;
hv_iterinit(hv);
while
((current = hv_iternext(hv))) {
SV* sigelem = hv_iterval(hv, current);
mg_set(sigelem);
}
}
return
0;
}
int
Perl_magic_setisa(pTHX_ SV *sv, MAGIC *mg)
{
PERL_ARGS_ASSERT_MAGIC_SETISA;
PERL_UNUSED_ARG(sv);
if
(PL_delaymagic & DM_ARRAY_ISA && mg->mg_type == PERL_MAGIC_isaelem)
return
0;
return
magic_clearisa(NULL, mg);
}
int
Perl_magic_clearisa(pTHX_ SV *sv, MAGIC *mg)
{
HV* stash;
PERL_ARGS_ASSERT_MAGIC_CLEARISA;
if
(PL_phase == PERL_PHASE_DESTRUCT)
return
0;
if
(sv)
av_clear(MUTABLE_AV(sv));
if
(SvTYPE(mg->mg_obj) != SVt_PVGV && SvSMAGICAL(mg->mg_obj))
mg = mg_find(mg->mg_obj, PERL_MAGIC_isa);
assert
(mg);
if
(SvTYPE(mg->mg_obj) == SVt_PVAV) {
SV **svp = AvARRAY((AV *)mg->mg_obj);
I32 items = AvFILLp((AV *)mg->mg_obj) + 1;
while
(items--) {
stash = GvSTASH((GV *)*svp++);
if
(stash && HvENAME(stash)) mro_isa_changed_in(stash);
}
return
0;
}
stash = GvSTASH(
(
const
GV *)mg->mg_obj
);
if
(stash && HvENAME_get(stash))
mro_isa_changed_in(stash);
return
0;
}
int
Perl_magic_getnkeys(pTHX_ SV *sv, MAGIC *mg)
{
HV *
const
hv = MUTABLE_HV(LvTARG(sv));
I32 i = 0;
PERL_ARGS_ASSERT_MAGIC_GETNKEYS;
PERL_UNUSED_ARG(mg);
if
(hv) {
(
void
) hv_iterinit(hv);
if
(! SvTIED_mg((
const
SV *)hv, PERL_MAGIC_tied))
i = HvUSEDKEYS(hv);
else
{
while
(hv_iternext(hv))
i++;
}
}
sv_setiv(sv, (IV)i);
return
0;
}
int
Perl_magic_setnkeys(pTHX_ SV *sv, MAGIC *mg)
{
PERL_ARGS_ASSERT_MAGIC_SETNKEYS;
PERL_UNUSED_ARG(mg);
if
(LvTARG(sv)) {
hv_ksplit(MUTABLE_HV(LvTARG(sv)), SvIV(sv));
}
return
0;
}
SV*
Perl_magic_methcall(pTHX_ SV *sv,
const
MAGIC *mg, SV *meth, U32 flags,
U32 argc, ...)
{
dSP;
SV* ret = NULL;
PERL_ARGS_ASSERT_MAGIC_METHCALL;
ENTER;
if
(flags & G_WRITING_TO_STDERR) {
SAVETMPS;
save_re_context();
SAVESPTR(PL_stderrgv);
PL_stderrgv = NULL;
}
PUSHSTACKi(PERLSI_MAGIC);
PUSHMARK(SP);
assert
(argc <= I32_MAX);
EXTEND(SP, (I32)argc+1);
PUSHs(SvTIED_obj(sv, mg));
if
(flags & G_UNDEF_FILL) {
while
(argc--) {
PUSHs(&PL_sv_undef);
}
}
else
if
(argc > 0) {
va_list
args;
va_start
(args, argc);
do
{
SV *
const
this_sv =
va_arg
(args, SV *);
PUSHs(this_sv);
}
while
(--argc);
va_end
(args);
}
PUTBACK;
if
(flags & G_DISCARD) {
call_sv(meth, G_SCALAR|G_DISCARD|G_METHOD_NAMED);
}
else
{
if
(call_sv(meth, G_SCALAR|G_METHOD_NAMED))
ret = *PL_stack_sp--;
}
POPSTACK;
if
(flags & G_WRITING_TO_STDERR)
FREETMPS;
LEAVE;
return
ret;
}
STATIC SV*
S_magic_methcall1(pTHX_ SV *sv,
const
MAGIC *mg, SV *meth, U32 flags,
int
n, SV *val)
{
SV* arg1 = NULL;
PERL_ARGS_ASSERT_MAGIC_METHCALL1;
if
(mg->mg_ptr) {
if
(mg->mg_len >= 0) {
arg1 = newSVpvn_flags(mg->mg_ptr, mg->mg_len, SVs_TEMP);
}
else
if
(mg->mg_len == HEf_SVKEY)
arg1 = MUTABLE_SV(mg->mg_ptr);
}
else
if
(mg->mg_type == PERL_MAGIC_tiedelem) {
arg1 = newSViv((IV)(mg->mg_len));
sv_2mortal(arg1);
}
if
(!arg1) {
return
Perl_magic_methcall(aTHX_ sv, mg, meth, flags, n - 1, val);
}
return
Perl_magic_methcall(aTHX_ sv, mg, meth, flags, n, arg1, val);
}
STATIC
int
S_magic_methpack(pTHX_ SV *sv,
const
MAGIC *mg, SV *meth)
{
SV* ret;
PERL_ARGS_ASSERT_MAGIC_METHPACK;
ret = magic_methcall1(sv, mg, meth, 0, 1, NULL);
if
(ret)
sv_setsv(sv, ret);
return
0;
}
int
Perl_magic_getpack(pTHX_ SV *sv, MAGIC *mg)
{
PERL_ARGS_ASSERT_MAGIC_GETPACK;
if
(mg->mg_type == PERL_MAGIC_tiedelem)
mg->mg_flags |= MGf_GSKIP;
magic_methpack(sv,mg,SV_CONST(FETCH));
return
0;
}
int
Perl_magic_setpack(pTHX_ SV *sv, MAGIC *mg)
{
MAGIC *tmg;
SV *val;
PERL_ARGS_ASSERT_MAGIC_SETPACK;
if
(TAINTING_get && (tmg = mg_find(sv, PERL_MAGIC_taint))
&& (tmg->mg_len & 1))
{
val = sv_mortalcopy(sv);
SvTAINTED_on(val);
}
else
val = sv;
magic_methcall1(sv, mg, SV_CONST(STORE), G_DISCARD, 2, val);
return
0;
}
int
Perl_magic_clearpack(pTHX_ SV *sv, MAGIC *mg)
{
PERL_ARGS_ASSERT_MAGIC_CLEARPACK;
if
(mg->mg_type == PERL_MAGIC_tiedscalar)
return
0;
return
magic_methpack(sv,mg,SV_CONST(DELETE));
}
U32
Perl_magic_sizepack(pTHX_ SV *sv, MAGIC *mg)
{
I32 retval = 0;
SV* retsv;
PERL_ARGS_ASSERT_MAGIC_SIZEPACK;
retsv = magic_methcall1(sv, mg, SV_CONST(FETCHSIZE), 0, 1, NULL);
if
(retsv) {
retval = SvIV(retsv)-1;
if
(retval < -1)
Perl_croak(aTHX_
"FETCHSIZE returned a negative value"
);
}
return
(U32) retval;
}
int
Perl_magic_wipepack(pTHX_ SV *sv, MAGIC *mg)
{
PERL_ARGS_ASSERT_MAGIC_WIPEPACK;
Perl_magic_methcall(aTHX_ sv, mg, SV_CONST(CLEAR), G_DISCARD, 0);
return
0;
}
int
Perl_magic_nextpack(pTHX_ SV *sv, MAGIC *mg, SV *key)
{
SV* ret;
PERL_ARGS_ASSERT_MAGIC_NEXTPACK;
ret = SvOK(key) ? Perl_magic_methcall(aTHX_ sv, mg, SV_CONST(NEXTKEY), 0, 1, key)
: Perl_magic_methcall(aTHX_ sv, mg, SV_CONST(FIRSTKEY), 0, 0);
if
(ret)
sv_setsv(key,ret);
return
0;
}
int
Perl_magic_existspack(pTHX_ SV *sv,
const
MAGIC *mg)
{
PERL_ARGS_ASSERT_MAGIC_EXISTSPACK;
return
magic_methpack(sv,mg,SV_CONST(EXISTS));
}
SV *
Perl_magic_scalarpack(pTHX_ HV *hv, MAGIC *mg)
{
SV *retval;
SV *
const
tied = SvTIED_obj(MUTABLE_SV(hv), mg);
HV *
const
pkg = SvSTASH((
const
SV *)SvRV(tied));
PERL_ARGS_ASSERT_MAGIC_SCALARPACK;
if
(!gv_fetchmethod_autoload(pkg,
"SCALAR"
, FALSE)) {
SV *key;
if
(HvEITER_get(hv))
return
&PL_sv_yes;
key = sv_newmortal();
magic_nextpack(MUTABLE_SV(hv), mg, key);
HvEITER_set(hv, NULL);
return
SvOK(key) ? &PL_sv_yes : &PL_sv_no;
}
retval = Perl_magic_methcall(aTHX_ MUTABLE_SV(hv), mg, SV_CONST(SCALAR), 0, 0);
if
(!retval)
retval = &PL_sv_undef;
return
retval;
}
int
Perl_magic_setdbline(pTHX_ SV *sv, MAGIC *mg)
{
SV **svp;
PERL_ARGS_ASSERT_MAGIC_SETDBLINE;
if
(UNLIKELY(mg->mg_len != HEf_SVKEY)) {
Perl_croak(aTHX_
"panic: magic_setdbline len=%"
IVdf
", ptr='%s'"
,
(IV)mg->mg_len, mg->mg_ptr);
}
svp = av_fetch(MUTABLE_AV(mg->mg_obj),
sv_2iv(MUTABLE_SV((mg)->mg_ptr)), FALSE);
if
(svp && SvIOKp(*svp)) {
OP *
const
o = INT2PTR(OP*,SvIVX(*svp));
if
(o) {
#ifdef PERL_DEBUG_READONLY_OPS
Slab_to_rw(OpSLAB(o));
#endif
if
(SvTRUE(sv))
o->op_flags |= OPf_SPECIAL;
else
o->op_flags &= ~OPf_SPECIAL;
#ifdef PERL_DEBUG_READONLY_OPS
Slab_to_ro(OpSLAB(o));
#endif
}
}
return
0;
}
int
Perl_magic_getarylen(pTHX_ SV *sv,
const
MAGIC *mg)
{
AV *
const
obj = MUTABLE_AV(mg->mg_obj);
PERL_ARGS_ASSERT_MAGIC_GETARYLEN;
if
(obj) {
sv_setiv(sv, AvFILL(obj));
}
else
{
sv_set_undef(sv);
}
return
0;
}
int
Perl_magic_setarylen(pTHX_ SV *sv, MAGIC *mg)
{
AV *
const
obj = MUTABLE_AV(mg->mg_obj);
PERL_ARGS_ASSERT_MAGIC_SETARYLEN;
if
(obj) {
av_fill(obj, SvIV(sv));
}
else
{
Perl_ck_warner(aTHX_ packWARN(WARN_MISC),
"Attempt to set length of freed array"
);
}
return
0;
}
int
Perl_magic_cleararylen_p(pTHX_ SV *sv, MAGIC *mg)
{
PERL_ARGS_ASSERT_MAGIC_CLEARARYLEN_P;
PERL_UNUSED_ARG(sv);
PERL_UNUSED_CONTEXT;
if
(
sizeof
(IV) ==
sizeof
(SSize_t)) {
*((IV *) &(mg->mg_len)) = 0;
}
else
{
if
(mg->mg_ptr)
*((IV *) mg->mg_ptr) = 0;
}
return
0;
}
int
Perl_magic_freearylen_p(pTHX_ SV *sv, MAGIC *mg)
{
PERL_ARGS_ASSERT_MAGIC_FREEARYLEN_P;
PERL_UNUSED_ARG(sv);
if
(PL_in_clean_all)
return
0;
mg = mg_find (mg->mg_obj, PERL_MAGIC_arylen);
if
(mg) {
mg->mg_obj = 0;
}
return
0;
}
int
Perl_magic_getpos(pTHX_ SV *sv, MAGIC *mg)
{
SV*
const
lsv = LvTARG(sv);
MAGIC *
const
found = mg_find_mglob(lsv);
PERL_ARGS_ASSERT_MAGIC_GETPOS;
PERL_UNUSED_ARG(mg);
if
(found && found->mg_len != -1) {
STRLEN i = found->mg_len;
if
(found->mg_flags & MGf_BYTES && DO_UTF8(lsv))
i = sv_pos_b2u_flags(lsv, i, SV_GMAGIC|SV_CONST_RETURN);
sv_setuv(sv, i);
return
0;
}
sv_set_undef(sv);
return
0;
}
int
Perl_magic_setpos(pTHX_ SV *sv, MAGIC *mg)
{
SV*
const
lsv = LvTARG(sv);
SSize_t pos;
STRLEN len;
MAGIC* found;
const
char
*s;
PERL_ARGS_ASSERT_MAGIC_SETPOS;
PERL_UNUSED_ARG(mg);
found = mg_find_mglob(lsv);
if
(!found) {
if
(!SvOK(sv))
return
0;
found = sv_magicext_mglob(lsv);
}
else
if
(!SvOK(sv)) {
found->mg_len = -1;
return
0;
}
s = SvPV_const(lsv, len);
pos = SvIV(sv);
if
(DO_UTF8(lsv)) {
const
STRLEN ulen = sv_or_pv_len_utf8(lsv, s, len);
if
(ulen)
len = ulen;
}
if
(pos < 0) {
pos += len;
if
(pos < 0)
pos = 0;
}
else
if
(pos > (SSize_t)len)
pos = len;
found->mg_len = pos;
found->mg_flags &= ~(MGf_MINMATCH|MGf_BYTES);
return
0;
}
int
Perl_magic_getsubstr(pTHX_ SV *sv, MAGIC *mg)
{
STRLEN len;
SV *
const
lsv = LvTARG(sv);
const
char
*
const
tmps = SvPV_const(lsv,len);
STRLEN offs = LvTARGOFF(sv);
STRLEN rem = LvTARGLEN(sv);
const
bool
negoff = LvFLAGS(sv) & LVf_NEG_OFF;
const
bool
negrem = LvFLAGS(sv) & LVf_NEG_LEN;
PERL_ARGS_ASSERT_MAGIC_GETSUBSTR;
PERL_UNUSED_ARG(mg);
if
(!translate_substr_offsets(
SvUTF8(lsv) ? sv_or_pv_len_utf8(lsv, tmps, len) : len,
negoff ? -(IV)offs : (IV)offs, !negoff,
negrem ? -(IV)rem : (IV)rem, !negrem, &offs, &rem
)) {
Perl_ck_warner(aTHX_ packWARN(WARN_SUBSTR),
"substr outside of string"
);
sv_set_undef(sv);
return
0;
}
if
(SvUTF8(lsv))
offs = sv_or_pv_pos_u2b(lsv, tmps, offs, &rem);
sv_setpvn(sv, tmps + offs, rem);
if
(SvUTF8(lsv))
SvUTF8_on(sv);
return
0;
}
int
Perl_magic_setsubstr(pTHX_ SV *sv, MAGIC *mg)
{
STRLEN len, lsv_len, oldtarglen, newtarglen;
const
char
*
const
tmps = SvPV_const(sv, len);
SV *
const
lsv = LvTARG(sv);
STRLEN lvoff = LvTARGOFF(sv);
STRLEN lvlen = LvTARGLEN(sv);
const
bool
negoff = LvFLAGS(sv) & LVf_NEG_OFF;
const
bool
neglen = LvFLAGS(sv) & LVf_NEG_LEN;
PERL_ARGS_ASSERT_MAGIC_SETSUBSTR;
PERL_UNUSED_ARG(mg);
SvGETMAGIC(lsv);
if
(SvROK(lsv))
Perl_ck_warner(aTHX_ packWARN(WARN_SUBSTR),
"Attempt to use reference as lvalue in substr"
);
SvPV_force_nomg(lsv,lsv_len);
if
(SvUTF8(lsv)) lsv_len = sv_len_utf8_nomg(lsv);
if
(!translate_substr_offsets(
lsv_len,
negoff ? -(IV)lvoff : (IV)lvoff, !negoff,
neglen ? -(IV)lvlen : (IV)lvlen, !neglen, &lvoff, &lvlen
))
Perl_croak(aTHX_
"substr outside of string"
);
oldtarglen = lvlen;
if
(DO_UTF8(sv)) {
sv_utf8_upgrade_nomg(lsv);
lvoff = sv_pos_u2b_flags(lsv, lvoff, &lvlen, SV_CONST_RETURN);
sv_insert_flags(lsv, lvoff, lvlen, tmps, len, 0);
newtarglen = sv_or_pv_len_utf8(sv, tmps, len);
SvUTF8_on(lsv);
}
else
if
(SvUTF8(lsv)) {
const
char
*utf8;
lvoff = sv_pos_u2b_flags(lsv, lvoff, &lvlen, SV_CONST_RETURN);
newtarglen = len;
utf8 = (
char
*)bytes_to_utf8((U8*)tmps, &len);
sv_insert_flags(lsv, lvoff, lvlen, utf8, len, 0);
Safefree(utf8);
}
else
{
sv_insert_flags(lsv, lvoff, lvlen, tmps, len, 0);
newtarglen = len;
}
if
(!neglen) LvTARGLEN(sv) = newtarglen;
if
(negoff) LvTARGOFF(sv) += newtarglen - oldtarglen;
return
0;
}
int
Perl_magic_gettaint(pTHX_ SV *sv, MAGIC *mg)
{
PERL_ARGS_ASSERT_MAGIC_GETTAINT;
PERL_UNUSED_ARG(sv);
#ifdef NO_TAINT_SUPPORT
PERL_UNUSED_ARG(mg);
#endif
TAINT_IF((PL_localizing != 1) && (mg->mg_len & 1) && IN_PERL_RUNTIME);
return
0;
}
int
Perl_magic_settaint(pTHX_ SV *sv, MAGIC *mg)
{
PERL_ARGS_ASSERT_MAGIC_SETTAINT;
PERL_UNUSED_ARG(sv);
if
(TAINT_get)
mg->mg_len |= 1;
else
mg->mg_len &= ~1;
return
0;
}
int
Perl_magic_getvec(pTHX_ SV *sv, MAGIC *mg)
{
SV *
const
lsv = LvTARG(sv);
char
errflags = LvFLAGS(sv);
PERL_ARGS_ASSERT_MAGIC_GETVEC;
PERL_UNUSED_ARG(mg);
assert
(!(errflags & ~(LVf_NEG_OFF|LVf_OUT_OF_RANGE)));
sv_setuv(sv, errflags ? 0 : do_vecget(lsv, LvTARGOFF(sv), LvTARGLEN(sv)));
return
0;
}
int
Perl_magic_setvec(pTHX_ SV *sv, MAGIC *mg)
{
PERL_ARGS_ASSERT_MAGIC_SETVEC;
PERL_UNUSED_ARG(mg);
do_vecset(sv);
return
0;
}
SV *
Perl_defelem_target(pTHX_ SV *sv, MAGIC *mg)
{
SV *targ = NULL;
PERL_ARGS_ASSERT_DEFELEM_TARGET;
if
(!mg) mg = mg_find(sv, PERL_MAGIC_defelem);
assert
(mg);
if
(LvTARGLEN(sv)) {
if
(mg->mg_obj) {
SV *
const
ahv = LvTARG(sv);
HE *
const
he = hv_fetch_ent(MUTABLE_HV(ahv), mg->mg_obj, FALSE, 0);
if
(he)
targ = HeVAL(he);
}
else
if
(LvSTARGOFF(sv) >= 0) {
AV *
const
av = MUTABLE_AV(LvTARG(sv));
if
(LvSTARGOFF(sv) <= AvFILL(av))
{
if
(SvRMAGICAL(av)) {
SV *
const
*
const
svp = av_fetch(av, LvSTARGOFF(sv), 0);
targ = svp ? *svp : NULL;
}
else
targ = AvARRAY(av)[LvSTARGOFF(sv)];
}
}
if
(targ && (targ != &PL_sv_undef)) {
SvREFCNT_dec(LvTARG(sv));
LvTARG(sv) = SvREFCNT_inc_simple_NN(targ);
LvTARGLEN(sv) = 0;
SvREFCNT_dec(mg->mg_obj);
mg->mg_obj = NULL;
mg->mg_flags &= ~MGf_REFCOUNTED;
}
return
targ;
}
else
return
LvTARG(sv);
}
int
Perl_magic_getdefelem(pTHX_ SV *sv, MAGIC *mg)
{
PERL_ARGS_ASSERT_MAGIC_GETDEFELEM;
sv_setsv(sv, defelem_target(sv, mg));
return
0;
}
int
Perl_magic_setdefelem(pTHX_ SV *sv, MAGIC *mg)
{
PERL_ARGS_ASSERT_MAGIC_SETDEFELEM;
PERL_UNUSED_ARG(mg);
if
(LvTARGLEN(sv))
vivify_defelem(sv);
if
(LvTARG(sv)) {
sv_setsv(LvTARG(sv), sv);
SvSETMAGIC(LvTARG(sv));
}
return
0;
}
void
Perl_vivify_defelem(pTHX_ SV *sv)
{
MAGIC *mg;
SV *value = NULL;
PERL_ARGS_ASSERT_VIVIFY_DEFELEM;
if
(!LvTARGLEN(sv) || !(mg = mg_find(sv, PERL_MAGIC_defelem)))
return
;
if
(mg->mg_obj) {
SV *
const
ahv = LvTARG(sv);
HE *
const
he = hv_fetch_ent(MUTABLE_HV(ahv), mg->mg_obj, TRUE, 0);
if
(he)
value = HeVAL(he);
if
(!value || value == &PL_sv_undef)
Perl_croak(aTHX_ PL_no_helem_sv, SVfARG(mg->mg_obj));
}
else
if
(LvSTARGOFF(sv) < 0)
Perl_croak(aTHX_ PL_no_aelem, LvSTARGOFF(sv));
else
{
AV *
const
av = MUTABLE_AV(LvTARG(sv));
if
((I32)LvTARGLEN(sv) < 0 && LvSTARGOFF(sv) > AvFILL(av))
LvTARG(sv) = NULL;
else
{
SV*
const
*
const
svp = av_fetch(av, LvSTARGOFF(sv), TRUE);
if
(!svp || !(value = *svp))
Perl_croak(aTHX_ PL_no_aelem, LvSTARGOFF(sv));
}
}
SvREFCNT_inc_simple_void(value);
SvREFCNT_dec(LvTARG(sv));
LvTARG(sv) = value;
LvTARGLEN(sv) = 0;
SvREFCNT_dec(mg->mg_obj);
mg->mg_obj = NULL;
mg->mg_flags &= ~MGf_REFCOUNTED;
}
int
Perl_magic_setnonelem(pTHX_ SV *sv, MAGIC *mg)
{
PERL_ARGS_ASSERT_MAGIC_SETNONELEM;
PERL_UNUSED_ARG(mg);
sv_unmagic(sv, PERL_MAGIC_nonelem);
return
0;
}
int
Perl_magic_killbackrefs(pTHX_ SV *sv, MAGIC *mg)
{
PERL_ARGS_ASSERT_MAGIC_KILLBACKREFS;
Perl_sv_kill_backrefs(aTHX_ sv, MUTABLE_AV(mg->mg_obj));
return
0;
}
int
Perl_magic_setmglob(pTHX_ SV *sv, MAGIC *mg)
{
PERL_ARGS_ASSERT_MAGIC_SETMGLOB;
PERL_UNUSED_CONTEXT;
PERL_UNUSED_ARG(sv);
mg->mg_len = -1;
return
0;
}
int
Perl_magic_freemglob(pTHX_ SV *sv, MAGIC *mg)
{
PERL_ARGS_ASSERT_MAGIC_FREEMGLOB;
PERL_UNUSED_ARG(sv);
assert
(mg->mg_type == PERL_MAGIC_regex_global && mg->mg_len >= -1);
mg->mg_ptr = NULL;
return
0;
}
int
Perl_magic_setuvar(pTHX_ SV *sv, MAGIC *mg)
{
const
struct
ufuncs *
const
uf = (
struct
ufuncs *)mg->mg_ptr;
PERL_ARGS_ASSERT_MAGIC_SETUVAR;
if
(uf && uf->uf_set)
(*uf->uf_set)(aTHX_ uf->uf_index, sv);
return
0;
}
int
Perl_magic_setregexp(pTHX_ SV *sv, MAGIC *mg)
{
const
char
type = mg->mg_type;
PERL_ARGS_ASSERT_MAGIC_SETREGEXP;
assert
( type == PERL_MAGIC_fm
|| type == PERL_MAGIC_qr
|| type == PERL_MAGIC_bm);
return
sv_unmagic(sv, type);
}
#ifdef USE_LOCALE_COLLATE
int
Perl_magic_setcollxfrm(pTHX_ SV *sv, MAGIC *mg)
{
PERL_ARGS_ASSERT_MAGIC_SETCOLLXFRM;
PERL_UNUSED_CONTEXT;
PERL_UNUSED_ARG(sv);
if
(mg->mg_ptr) {
Safefree(mg->mg_ptr);
mg->mg_ptr = NULL;
mg->mg_len = -1;
}
return
0;
}
int
Perl_magic_freecollxfrm(pTHX_ SV *sv, MAGIC *mg)
{
PERL_ARGS_ASSERT_MAGIC_FREECOLLXFRM;
PERL_UNUSED_ARG(sv);
if
(mg->mg_len >= 0) {
assert
(mg->mg_type == PERL_MAGIC_collxfrm);
Safefree(mg->mg_ptr);
mg->mg_ptr = NULL;
}
return
0;
}
#endif /* USE_LOCALE_COLLATE */
int
Perl_magic_setutf8(pTHX_ SV *sv, MAGIC *mg)
{
PERL_ARGS_ASSERT_MAGIC_SETUTF8;
PERL_UNUSED_CONTEXT;
PERL_UNUSED_ARG(sv);
Safefree(mg->mg_ptr);
mg->mg_ptr = NULL;
mg->mg_len = -1;
return
0;
}
int
Perl_magic_freeutf8(pTHX_ SV *sv, MAGIC *mg)
{
PERL_ARGS_ASSERT_MAGIC_FREEUTF8;
PERL_UNUSED_ARG(sv);
assert
(mg->mg_type == PERL_MAGIC_utf8 && mg->mg_len >= -1);
Safefree(mg->mg_ptr);
mg->mg_ptr = NULL;
return
0;
}
int
Perl_magic_setlvref(pTHX_ SV *sv, MAGIC *mg)
{
const
char
*bad = NULL;
PERL_ARGS_ASSERT_MAGIC_SETLVREF;
if
(!SvROK(sv)) Perl_croak(aTHX_
"Assigned value is not a reference"
);
switch
(mg->mg_private & OPpLVREF_TYPE) {
case
OPpLVREF_SV:
if
(SvTYPE(SvRV(sv)) > SVt_PVLV)
bad =
" SCALAR"
;
break
;
case
OPpLVREF_AV:
if
(SvTYPE(SvRV(sv)) != SVt_PVAV)
bad =
"n ARRAY"
;
break
;
case
OPpLVREF_HV:
if
(SvTYPE(SvRV(sv)) != SVt_PVHV)
bad =
" HASH"
;
break
;
case
OPpLVREF_CV:
if
(SvTYPE(SvRV(sv)) != SVt_PVCV)
bad =
" CODE"
;
}
if
(bad)
Perl_croak(aTHX_
"Assigned value is not a%s reference"
, bad);
switch
(mg->mg_obj ? SvTYPE(mg->mg_obj) : 0) {
case
0:
{
SV *
const
old = PAD_SV(mg->mg_len);
PAD_SETSV(mg->mg_len, SvREFCNT_inc_NN(SvRV(sv)));
SvREFCNT_dec(old);
break
;
}
case
SVt_PVGV:
gv_setref(mg->mg_obj, sv);
SvSETMAGIC(mg->mg_obj);
break
;
case
SVt_PVAV:
av_store((AV *)mg->mg_obj, SvIV((SV *)mg->mg_ptr),
SvREFCNT_inc_simple_NN(SvRV(sv)));
break
;
case
SVt_PVHV:
(
void
)hv_store_ent((HV *)mg->mg_obj, (SV *)mg->mg_ptr,
SvREFCNT_inc_simple_NN(SvRV(sv)), 0);
}
if
(mg->mg_flags & MGf_PERSIST)
NOOP;
else
sv_unmagic(sv, PERL_MAGIC_lvref);
return
0;
}
static
void
S_set_dollarzero(pTHX_ SV *sv)
PERL_TSA_REQUIRES(PL_dollarzero_mutex)
{
const
char
*s;
STRLEN len;
#ifdef HAS_SETPROCTITLE
if
(PL_origalen != 1) {
s = SvPV_const(sv, len);
# if __FreeBSD_version > 410001 || defined(__DragonFly__)
setproctitle(
"-%s"
, s);
# else /* old FreeBSDs, NetBSD, OpenBSD, anyBSD */
setproctitle(
"%s"
, s);
# endif
}
#elif defined(__hpux) && defined(PSTAT_SETCMD)
if
(PL_origalen != 1) {
union
pstun un;
s = SvPV_const(sv, len);
un.pst_command = (
char
*)s;
pstat(PSTAT_SETCMD, un, len, 0, 0);
}
#else
if
(PL_origalen > 1) {
I32 i;
s = SvPV_force(sv,len);
if
(len >= (STRLEN)PL_origalen-1) {
Copy(s, PL_origargv[0], PL_origalen-1,
char
);
}
else
{
#ifdef PERL_DARWIN
const
int
pad = 0;
#else
const
int
pad =
' '
;
#endif
Copy(s, PL_origargv[0], len,
char
);
PL_origargv[0][len] = 0;
memset
(PL_origargv[0] + len + 1,
pad, PL_origalen - len - 1);
}
PL_origargv[0][PL_origalen-1] = 0;
for
(i = 1; i < PL_origargc; i++)
PL_origargv[i] = 0;
#ifdef HAS_PRCTL_SET_NAME
if
(prctl(PR_SET_NAME, (unsigned
long
)s, 0, 0, 0) != 0) {
Perl_croak(aTHX_
"Can't set $0 with prctl(): %s"
, Strerror(
errno
));
}
#endif
}
#endif
}
int
Perl_magic_set(pTHX_ SV *sv, MAGIC *mg)
{
I32 paren;
const
REGEXP * rx;
I32 i;
STRLEN len;
MAGIC *tmg;
PERL_ARGS_ASSERT_MAGIC_SET;
if
(!mg->mg_ptr) {
paren = mg->mg_len;
if
(PL_curpm && (rx = PM_GETRE(PL_curpm))) {
setparen_got_rx:
CALLREG_NUMBUF_STORE((REGEXP *)rx,paren,sv);
}
else
{
croakparen:
if
(!PL_localizing) {
Perl_croak_no_modify();
}
}
return
0;
}
switch
(*mg->mg_ptr) {
case
'\001'
:
if
(SvOK(sv)) sv_copypv(PL_bodytarget, sv);
else
SvOK_off(PL_bodytarget);
FmLINES(PL_bodytarget) = 0;
if
(SvPOK(PL_bodytarget)) {
char
*s = SvPVX(PL_bodytarget);
char
*e = SvEND(PL_bodytarget);
while
( ((s = (
char
*)
memchr
(s,
'\n'
, e - s))) ) {
FmLINES(PL_bodytarget)++;
s++;
}
}
if
(TAINTING_get) {
if
((tmg = mg_find(sv,PERL_MAGIC_taint)) && tmg->mg_len & 1)
SvTAINTED_on(PL_bodytarget);
else
SvTAINTED_off(PL_bodytarget);
}
break
;
case
'\003'
:
PL_minus_c = cBOOL(SvIV(sv));
break
;
case
'\004'
:
#ifdef DEBUGGING
{
const
char
*s = SvPV_nolen_const(sv);
PL_debug = get_debug_opts(&s, 0) | DEBUG_TOP_FLAG;
if
(DEBUG_x_TEST || DEBUG_B_TEST)
dump_all_perl(!DEBUG_B_TEST);
}
#else
PL_debug = (SvIV(sv)) | DEBUG_TOP_FLAG;
#endif
break
;
case
'\005'
:
if
(*(mg->mg_ptr+1) ==
'\0'
) {
#ifdef VMS
set_vaxc_errno(SvIV(sv));
#elif defined(WIN32)
SetLastError( SvIV(sv) );
#elif defined(OS2)
os2_setsyserrno(SvIV(sv));
#else
SETERRNO(SvIV(sv), 4);
#endif
}
else
if
(strEQ(mg->mg_ptr + 1,
"NCODING"
) && SvOK(sv))
Perl_croak(aTHX_
"${^ENCODING} is no longer supported"
);
break
;
case
'\006'
:
if
(mg->mg_ptr[1] ==
'\0'
) {
PL_maxsysfd = SvIV(sv);
}
break
;
case
'\010'
:
{
U32 save_hints = PL_hints;
PL_hints = SvUV(sv);
if
((PL_hints & HINT_UTF8) && ! (save_hints & HINT_UTF8)) {
notify_parser_that_changed_to_utf8();
}
}
break
;
case
'\011'
:
Safefree(PL_inplace);
PL_inplace = SvOK(sv) ? savesvpv(sv) : NULL;
break
;
case
'\016'
:
if
(PL_curpm && (rx = PM_GETRE(PL_curpm))
&& (paren = RX_LASTCLOSEPAREN(rx)))
goto
setparen_got_rx;
goto
croakparen;
case
'\017'
:
if
(*(mg->mg_ptr+1) ==
'\0'
) {
Safefree(PL_osname);
PL_osname = NULL;
if
(SvOK(sv)) {
TAINT_PROPER(
"assigning to $^O"
);
PL_osname = savesvpv(sv);
}
}
else
if
(strEQ(mg->mg_ptr,
"\017PEN"
)) {
STRLEN len;
const
char
*
const
start = SvPV(sv, len);
const
char
*out = (
const
char
*)
memchr
(start,
'\0'
, len);
SV *tmp;
PL_compiling.cop_hints |= HINT_LEXICAL_IO_IN | HINT_LEXICAL_IO_OUT;
PL_hints |= HINT_LEXICAL_IO_IN | HINT_LEXICAL_IO_OUT;
tmp = out ? newSVpvn_flags(out + 1, start + len - out - 1,
SvUTF8(sv))
: newSVpvs_flags(
""
, SvUTF8(sv));
(
void
)hv_stores(GvHV(PL_hintgv),
"open>"
, tmp);
mg_set(tmp);
tmp = newSVpvn_flags(start, out ? (STRLEN)(out - start) : len,
SvUTF8(sv));
(
void
)hv_stores(GvHV(PL_hintgv),
"open<"
, tmp);
mg_set(tmp);
}
break
;
case
'\020'
:
PL_perldb = SvIV(sv);
if
(PL_perldb && !PL_DBsingle)
init_debugger();
break
;
case
'\024'
:
#ifdef BIG_TIME
PL_basetime = (Time_t)(SvNOK(sv) ? SvNVX(sv) : sv_2nv(sv));
#else
PL_basetime = (Time_t)SvIV(sv);
#endif
break
;
case
'\025'
:
if
(strEQ(mg->mg_ptr+1,
"TF8CACHE"
)) {
PL_utf8cache = (
signed
char
) sv_2iv(sv);
}
break
;
case
'\027'
:
if
(*(mg->mg_ptr+1) ==
'\0'
) {
if
( ! (PL_dowarn & G_WARN_ALL_MASK)) {
i = SvIV(sv);
PL_dowarn = (PL_dowarn & ~G_WARN_ON)
| (i ? G_WARN_ON : G_WARN_OFF) ;
}
}
else
if
(strEQ(mg->mg_ptr+1,
"ARNING_BITS"
)) {
if
( ! (PL_dowarn & G_WARN_ALL_MASK)) {
if
(!SvPOK(sv)) {
free_and_set_cop_warnings(&PL_compiling, pWARN_STD);
break
;
}
{
STRLEN len, i;
int
not_none = 0, not_all = 0;
const
U8 *
const
ptr = (
const
U8 *)SvPV_const(sv, len) ;
for
(i = 0 ; i < len ; ++i) {
not_none |= ptr[i];
not_all |= ptr[i] ^ 0x55;
}
if
(!not_none) {
free_and_set_cop_warnings(&PL_compiling, pWARN_NONE);
}
else
if
(len >= WARNsize && !not_all) {
free_and_set_cop_warnings(&PL_compiling, pWARN_ALL);
PL_dowarn |= G_WARN_ONCE ;
}
else
{
STRLEN len;
const
char
*
const
p = SvPV_const(sv, len);
PL_compiling.cop_warnings
= Perl_new_warnings_bitfield(aTHX_ PL_compiling.cop_warnings,
p, len);
if
(isWARN_on(PL_compiling.cop_warnings, WARN_ONCE))
PL_dowarn |= G_WARN_ONCE ;
}
}
}
}
break
;
case
'.'
:
if
(PL_localizing) {
if
(PL_localizing == 1)
SAVESPTR(PL_last_in_gv);
}
else
if
(SvOK(sv) && GvIO(PL_last_in_gv))
IoLINES(GvIOp(PL_last_in_gv)) = SvIV(sv);
break
;
case
'^'
:
Safefree(IoTOP_NAME(GvIOp(PL_defoutgv)));
IoTOP_NAME(GvIOp(PL_defoutgv)) = savesvpv(sv);
IoTOP_GV(GvIOp(PL_defoutgv)) = gv_fetchsv(sv, GV_ADD, SVt_PVIO);
break
;
case
'~'
:
Safefree(IoFMT_NAME(GvIOp(PL_defoutgv)));
IoFMT_NAME(GvIOp(PL_defoutgv)) = savesvpv(sv);
IoFMT_GV(GvIOp(PL_defoutgv)) = gv_fetchsv(sv, GV_ADD, SVt_PVIO);
break
;
case
'='
:
IoPAGE_LEN(GvIOp(PL_defoutgv)) = (SvIV(sv));
break
;
case
'-'
:
IoLINES_LEFT(GvIOp(PL_defoutgv)) = (SvIV(sv));
if
(IoLINES_LEFT(GvIOp(PL_defoutgv)) < 0L)
IoLINES_LEFT(GvIOp(PL_defoutgv)) = 0L;
break
;
case
'%'
:
IoPAGE(GvIOp(PL_defoutgv)) = (SvIV(sv));
break
;
case
'|'
:
{
IO *
const
io = GvIO(PL_defoutgv);
if
(!io)
break
;
if
((SvIV(sv)) == 0)
IoFLAGS(io) &= ~IOf_FLUSH;
else
{
if
(!(IoFLAGS(io) & IOf_FLUSH)) {
PerlIO *ofp = IoOFP(io);
if
(ofp)
(
void
)PerlIO_flush(ofp);
IoFLAGS(io) |= IOf_FLUSH;
}
}
}
break
;
case
'/'
:
{
if
(SvROK(sv)) {
SV *referent = SvRV(sv);
const
char
*reftype = sv_reftype(referent, 0);
if
(reftype[0] ==
'S'
|| reftype[0] ==
'L'
) {
IV val = SvIV(referent);
if
(val <= 0) {
sv_setsv(sv, PL_rs);
Perl_croak(aTHX_
"Setting $/ to a reference to %s is forbidden"
,
val < 0 ?
"a negative integer"
:
"zero"
);
}
}
else
{
sv_setsv(sv, PL_rs);
Perl_croak(aTHX_
"Setting $/ to a%s %s reference is forbidden"
,
*reftype ==
'A'
?
"n"
:
""
, reftype);
}
}
SvREFCNT_dec(PL_rs);
PL_rs = newSVsv(sv);
}
break
;
case
'\\'
:
SvREFCNT_dec(PL_ors_sv);
if
(SvOK(sv)) {
PL_ors_sv = newSVsv(sv);
}
else
{
PL_ors_sv = NULL;
}
break
;
case
'['
:
if
(SvIV(sv) != 0)
Perl_croak(aTHX_
"Assigning non-zero to $[ is no longer possible"
);
break
;
case
'?'
:
#ifdef COMPLEX_STATUS
if
(PL_localizing == 2) {
SvUPGRADE(sv, SVt_PVLV);
PL_statusvalue = LvTARGOFF(sv);
PL_statusvalue_vms = LvTARGLEN(sv);
}
else
#endif
#ifdef VMSISH_STATUS
if
(VMSISH_STATUS)
STATUS_NATIVE_CHILD_SET((U32)SvIV(sv));
else
#endif
STATUS_UNIX_EXIT_SET(SvIV(sv));
break
;
case
'!'
:
{
#ifdef VMS
# define PERL_VMS_BANG vaxc$errno
#else
# define PERL_VMS_BANG 0
#endif
#if defined(WIN32)
SETERRNO(win32_get_errno(SvIOK(sv) ? SvIVX(sv) : SvOK(sv) ? sv_2iv(sv) : 0),
(SvIV(sv) == EVMSERR) ? 4 : PERL_VMS_BANG);
#else
SETERRNO(SvIOK(sv) ? SvIVX(sv) : SvOK(sv) ? sv_2iv(sv) : 0,
(SvIV(sv) == EVMSERR) ? 4 : PERL_VMS_BANG);
#endif
}
break
;
case
'<'
:
{
const
Uid_t new_uid = SvUID(sv);
PL_delaymagic_uid = new_uid;
if
(PL_delaymagic) {
PL_delaymagic |= DM_RUID;
break
;
}
#ifdef HAS_SETRUID
PERL_UNUSED_RESULT(setruid(new_uid));
#elif defined(HAS_SETREUID)
PERL_UNUSED_RESULT(setreuid(new_uid, (Uid_t)-1));
#elif defined(HAS_SETRESUID)
PERL_UNUSED_RESULT(setresuid(new_uid, (Uid_t)-1, (Uid_t)-1));
#else
if
(new_uid == PerlProc_geteuid()) {
# ifdef PERL_DARWIN
if
(new_uid != 0 && PerlProc_getuid() == 0)
PERL_UNUSED_RESULT(PerlProc_setuid(0));
# endif
PERL_UNUSED_RESULT(PerlProc_setuid(new_uid));
}
else
{
Perl_croak(aTHX_
"setruid() not implemented"
);
}
#endif
break
;
}
case
'>'
:
{
const
Uid_t new_euid = SvUID(sv);
PL_delaymagic_euid = new_euid;
if
(PL_delaymagic) {
PL_delaymagic |= DM_EUID;
break
;
}
#ifdef HAS_SETEUID
PERL_UNUSED_RESULT(seteuid(new_euid));
#elif defined(HAS_SETREUID)
PERL_UNUSED_RESULT(setreuid((Uid_t)-1, new_euid));
#elif defined(HAS_SETRESUID)
PERL_UNUSED_RESULT(setresuid((Uid_t)-1, new_euid, (Uid_t)-1));
#else
if
(new_euid == PerlProc_getuid())
PERL_UNUSED_RESULT(PerlProc_setuid(new_euid));
else
{
Perl_croak(aTHX_
"seteuid() not implemented"
);
}
#endif
break
;
}
case
'('
:
{
const
Gid_t new_gid = SvGID(sv);
PL_delaymagic_gid = new_gid;
if
(PL_delaymagic) {
PL_delaymagic |= DM_RGID;
break
;
}
#ifdef HAS_SETRGID
PERL_UNUSED_RESULT(setrgid(new_gid));
#elif defined(HAS_SETREGID)
PERL_UNUSED_RESULT(setregid(new_gid, (Gid_t)-1));
#elif defined(HAS_SETRESGID)
PERL_UNUSED_RESULT(setresgid(new_gid, (Gid_t)-1, (Gid_t) -1));
#else
if
(new_gid == PerlProc_getegid())
PERL_UNUSED_RESULT(PerlProc_setgid(new_gid));
else
{
Perl_croak(aTHX_
"setrgid() not implemented"
);
}
#endif
break
;
}
case
')'
:
{
#ifndef INVALID_GID
#define INVALID_GID ((Gid_t)-1)
#endif
Gid_t new_egid;
#ifdef HAS_SETGROUPS
{
const
char
*p = SvPV_const(sv, len);
Groups_t *gary = NULL;
const
char
* p_end = p + len;
const
char
* endptr = p_end;
UV uv;
#ifdef _SC_NGROUPS_MAX
int
maxgrp = sysconf(_SC_NGROUPS_MAX);
if
(maxgrp < 0)
maxgrp = NGROUPS;
#else
int
maxgrp = NGROUPS;
#endif
while
(isSPACE(*p))
++p;
if
(grok_atoUV(p, &uv, &endptr))
new_egid = (Gid_t)uv;
else
{
new_egid = INVALID_GID;
endptr = NULL;
}
for
(i = 0; i < maxgrp; ++i) {
if
(endptr == NULL)
break
;
p = endptr;
endptr = p_end;
while
(isSPACE(*p))
++p;
if
(!*p)
break
;
if
(!gary)
Newx(gary, i + 1, Groups_t);
else
Renew(gary, i + 1, Groups_t);
if
(grok_atoUV(p, &uv, &endptr))
gary[i] = (Groups_t)uv;
else
{
gary[i] = INVALID_GID;
endptr = NULL;
}
}
if
(i)
PERL_UNUSED_RESULT(setgroups(i, gary));
Safefree(gary);
}
#else /* HAS_SETGROUPS */
new_egid = SvGID(sv);
#endif /* HAS_SETGROUPS */
PL_delaymagic_egid = new_egid;
if
(PL_delaymagic) {
PL_delaymagic |= DM_EGID;
break
;
}
#ifdef HAS_SETEGID
PERL_UNUSED_RESULT(setegid(new_egid));
#elif defined(HAS_SETREGID)
PERL_UNUSED_RESULT(setregid((Gid_t)-1, new_egid));
#elif defined(HAS_SETRESGID)
PERL_UNUSED_RESULT(setresgid((Gid_t)-1, new_egid, (Gid_t)-1));
#else
if
(new_egid == PerlProc_getgid())
PERL_UNUSED_RESULT(PerlProc_setgid(new_egid));
else
{
Perl_croak(aTHX_
"setegid() not implemented"
);
}
#endif
break
;
}
case
':'
:
PL_chopset = SvPV_force(sv,len);
break
;
case
'$'
:
if
(isGV(mg->mg_obj)) {
if
(mg->mg_flags & MGf_REFCOUNTED)
SvREFCNT_dec(mg->mg_obj);
mg->mg_flags |= MGf_REFCOUNTED;
mg->mg_obj = newSViv((IV)PerlProc_getpid());
}
else
sv_setiv(mg->mg_obj, (IV)PerlProc_getpid());
break
;
case
'0'
:
if
(!sv_utf8_downgrade(sv,
TRUE)) {
sv_utf8_encode(GvSV(mg->mg_obj));
Perl_ck_warner_d(aTHX_ packWARN(WARN_UTF8),
"Wide character in %s"
,
"$0"
);
}
LOCK_DOLLARZERO_MUTEX;
S_set_dollarzero(aTHX_ sv);
UNLOCK_DOLLARZERO_MUTEX;
break
;
}
return
0;
}
I32
Perl_whichsig_sv(pTHX_ SV *sigsv)
{
const
char
*sigpv;
STRLEN siglen;
PERL_ARGS_ASSERT_WHICHSIG_SV;
sigpv = SvPV_const(sigsv, siglen);
return
whichsig_pvn(sigpv, siglen);
}
I32
Perl_whichsig_pv(pTHX_
const
char
*sig)
{
PERL_ARGS_ASSERT_WHICHSIG_PV;
return
whichsig_pvn(sig,
strlen
(sig));
}
I32
Perl_whichsig_pvn(pTHX_
const
char
*sig, STRLEN len)
{
char
*
const
* sigv;
PERL_ARGS_ASSERT_WHICHSIG_PVN;
PERL_UNUSED_CONTEXT;
for
(sigv = (
char
*
const
*)PL_sig_name; *sigv; sigv++)
if
(
strlen
(*sigv) == len && memEQ(sig,*sigv, len))
return
PL_sig_num[sigv - (
char
*
const
*)PL_sig_name];
#ifdef SIGCLD
if
(memEQs(sig, len,
"CHLD"
))
return
SIGCLD;
#endif
#ifdef SIGCHLD
if
(memEQs(sig, len,
"CLD"
))
return
SIGCHLD;
#endif
return
-1;
}
#ifdef PERL_USE_3ARG_SIGHANDLER
Signal_t
Perl_sighandler(
int
sig, Siginfo_t *sip,
void
*uap)
{
Perl_perly_sighandler(sig, sip, uap, 0);
}
#else
Signal_t
Perl_sighandler(
int
sig)
{
Perl_perly_sighandler(sig, NULL, NULL, 0);
}
#endif
Signal_t
Perl_sighandler1(
int
sig)
{
Perl_perly_sighandler(sig, NULL, NULL, 0);
}
Signal_t
Perl_sighandler3(
int
sig, Siginfo_t *sip PERL_UNUSED_DECL,
void
*uap PERL_UNUSED_DECL)
{
Perl_perly_sighandler(sig, sip, uap, 0);
}
Signal_t
Perl_perly_sighandler(
int
sig, Siginfo_t *sip PERL_UNUSED_DECL,
void
*uap PERL_UNUSED_DECL,
bool
safe)
{
#ifdef PERL_GET_SIG_CONTEXT
dTHXa(PERL_GET_SIG_CONTEXT);
#else
dTHX;
#endif
dSP;
GV *gv = NULL;
SV *sv = NULL;
SV *
const
tSv = PL_Sv;
CV *cv = NULL;
OP *myop = PL_op;
U32 flags = 0;
XPV *
const
tXpv = PL_Xpv;
I32 old_ss_ix = PL_savestack_ix;
SV *errsv_save = NULL;
if
(!PL_psig_ptr[sig]) {
PerlIO_printf(Perl_error_log,
"Signal SIG%s received, but no signal handler set.\n"
,
PL_sig_name[sig]);
exit
(sig);
}
if
(PL_signals & PERL_SIGNALS_UNSAFE_FLAG) {
if
(PL_savestack_ix + 15 <= PL_savestack_max) {
flags |= 1;
PL_savestack_ix += 5;
SAVEDESTRUCTOR_X(S_unwind_handler_stack, NULL);
}
}
if
(!SvROK(PL_psig_ptr[sig]) || !(cv = MUTABLE_CV(SvRV(PL_psig_ptr[sig])))
|| SvTYPE(cv) != SVt_PVCV) {
HV *st;
cv = sv_2cv(PL_psig_ptr[sig], &st, &gv, GV_ADD);
}
if
(!cv || !CvROOT(cv)) {
const
HEK *
const
hek = gv
? GvENAME_HEK(gv)
: cv && CvNAMED(cv)
? CvNAME_HEK(cv)
: cv && CvGV(cv) ? GvENAME_HEK(CvGV(cv)) : NULL;
if
(hek)
Perl_ck_warner(aTHX_ packWARN(WARN_SIGNAL),
"SIG%s handler \"%"
HEKf
"\" not defined.\n"
,
PL_sig_name[sig], HEKfARG(hek));
else
Perl_ck_warner(aTHX_ packWARN(WARN_SIGNAL),
"SIG%s handler \"__ANON__\" not defined.\n"
,
PL_sig_name[sig]);
goto
cleanup;
}
sv = PL_psig_name[sig]
? SvREFCNT_inc_NN(PL_psig_name[sig])
: newSVpv(PL_sig_name[sig],0);
flags |= 8;
SAVEFREESV(sv);
if
(PL_signals & PERL_SIGNALS_UNSAFE_FLAG) {
assert
(old_ss_ix + 2 + ((flags & 1) ? 3+5 : 0) == PL_savestack_ix);
}
PUSHSTACKi(PERLSI_SIGNAL);
PUSHMARK(SP);
PUSHs(sv);
#if defined(HAS_SIGACTION) && defined(SA_SIGINFO)
{
struct
sigaction oact;
if
(sip && sigaction(sig, 0, &oact) == 0 && oact.sa_flags & SA_SIGINFO) {
HV *sih = newHV();
SV *rv = newRV_noinc(MUTABLE_SV(sih));
(
void
)hv_stores(sih,
"signo"
, newSViv(sip->si_signo));
(
void
)hv_stores(sih,
"code"
, newSViv(sip->si_code));
# ifdef HAS_SIGINFO_SI_ERRNO
(
void
)hv_stores(sih,
"errno"
, newSViv(sip->si_errno));
# endif
# ifdef HAS_SIGINFO_SI_STATUS
(
void
)hv_stores(sih,
"status"
, newSViv(sip->si_status));
# endif
# ifdef HAS_SIGINFO_SI_UID
{
SV *uid = newSV(0);
sv_setuid(uid, sip->si_uid);
(
void
)hv_stores(sih,
"uid"
, uid);
}
# endif
# ifdef HAS_SIGINFO_SI_PID
(
void
)hv_stores(sih,
"pid"
, newSViv(sip->si_pid));
# endif
# ifdef HAS_SIGINFO_SI_ADDR
(
void
)hv_stores(sih,
"addr"
, newSVuv(PTR2UV(sip->si_addr)));
# endif
# ifdef HAS_SIGINFO_SI_BAND
(
void
)hv_stores(sih,
"band"
, newSViv(sip->si_band));
# endif
EXTEND(SP, 2);
PUSHs(rv);
mPUSHp((
char
*)sip,
sizeof
(*sip));
}
}
#endif
PUTBACK;
errsv_save = newSVsv(ERRSV);
call_sv(MUTABLE_SV(cv), G_DISCARD|G_EVAL);
POPSTACK;
{
SV *
const
errsv = ERRSV;
if
(SvTRUE_NN(errsv)) {
SvREFCNT_dec(errsv_save);
#ifndef PERL_MICRO
# ifdef HAS_SIGPROCMASK
if
(!safe) {
sigset_t set;
sigemptyset(&set);
sigaddset(&set,sig);
sigprocmask(SIG_UNBLOCK, &set, NULL);
}
# else
(
void
)rsignal(sig, SIG_IGN);
(
void
)rsignal(sig, PL_csighandlerp);
# endif
#endif /* !PERL_MICRO */
die_sv(errsv);
}
else
{
sv_setsv(errsv, errsv_save);
SvREFCNT_dec(errsv_save);
}
}
cleanup:
PL_savestack_ix = old_ss_ix;
if
(flags & 8)
SvREFCNT_dec_NN(sv);
PL_op = myop;
PL_Sv = tSv;
PL_Xpv = tXpv;
return
;
}
static
void
S_restore_magic(pTHX_
const
void
*p)
{
MGS*
const
mgs = SSPTR(PTR2IV(p), MGS*);
SV*
const
sv = mgs->mgs_sv;
bool
bumped;
if
(!sv)
return
;
if
(SvTYPE(sv) >= SVt_PVMG && SvMAGIC(sv)) {
SvTEMP_off(sv);
if
(mgs->mgs_flags)
SvFLAGS(sv) |= mgs->mgs_flags;
else
mg_magical(sv);
}
bumped = mgs->mgs_bumped;
mgs->mgs_sv = NULL;
if
(PL_savestack_ix == mgs->mgs_ss_ix)
{
UV popval = SSPOPUV;
assert
(popval == SAVEt_DESTRUCTOR_X);
PL_savestack_ix -= 2;
popval = SSPOPUV;
assert
((popval & SAVE_MASK) == SAVEt_ALLOC);
PL_savestack_ix -= popval >> SAVE_TIGHT_SHIFT;
}
if
(bumped) {
if
(SvREFCNT(sv) == 1) {
sv_2mortal(sv);
SvTEMP_off(sv);
}
else
SvREFCNT_dec_NN(sv);
}
}
static
void
S_unwind_handler_stack(pTHX_
const
void
*p)
{
PERL_UNUSED_ARG(p);
PL_savestack_ix -= 5;
}
int
Perl_magic_sethint(pTHX_ SV *sv, MAGIC *mg)
{
SV *key = (mg->mg_len == HEf_SVKEY) ? MUTABLE_SV(mg->mg_ptr)
: newSVpvn_flags(mg->mg_ptr, mg->mg_len, SVs_TEMP);
PERL_ARGS_ASSERT_MAGIC_SETHINT;
PL_hints |= HINT_LOCALIZE_HH;
CopHINTHASH_set(&PL_compiling,
cophh_store_sv(CopHINTHASH_get(&PL_compiling), key, 0, sv, 0));
magic_sethint_feature(key, NULL, 0, sv, 0);
return
0;
}
int
Perl_magic_clearhint(pTHX_ SV *sv, MAGIC *mg)
{
PERL_ARGS_ASSERT_MAGIC_CLEARHINT;
PERL_UNUSED_ARG(sv);
PL_hints |= HINT_LOCALIZE_HH;
CopHINTHASH_set(&PL_compiling,
mg->mg_len == HEf_SVKEY
? cophh_delete_sv(CopHINTHASH_get(&PL_compiling),
MUTABLE_SV(mg->mg_ptr), 0, 0)
: cophh_delete_pvn(CopHINTHASH_get(&PL_compiling),
mg->mg_ptr, mg->mg_len, 0, 0));
if
(mg->mg_len == HEf_SVKEY)
magic_sethint_feature(MUTABLE_SV(mg->mg_ptr), NULL, 0, NULL, FALSE);
else
magic_sethint_feature(NULL, mg->mg_ptr, mg->mg_len, NULL, FALSE);
return
0;
}
int
Perl_magic_clearhints(pTHX_ SV *sv, MAGIC *mg)
{
PERL_ARGS_ASSERT_MAGIC_CLEARHINTS;
PERL_UNUSED_ARG(sv);
PERL_UNUSED_ARG(mg);
cophh_free(CopHINTHASH_get(&PL_compiling));
CopHINTHASH_set(&PL_compiling, cophh_new_empty());
CLEARFEATUREBITS();
return
0;
}
int
Perl_magic_copycallchecker(pTHX_ SV *sv, MAGIC *mg, SV *nsv,
const
char
*name, I32 namlen)
{
MAGIC *nmg;
PERL_ARGS_ASSERT_MAGIC_COPYCALLCHECKER;
PERL_UNUSED_ARG(sv);
PERL_UNUSED_ARG(name);
PERL_UNUSED_ARG(namlen);
sv_magic(nsv, &PL_sv_undef, mg->mg_type, NULL, 0);
nmg = mg_find(nsv, mg->mg_type);
assert
(nmg);
if
(nmg->mg_flags & MGf_REFCOUNTED) SvREFCNT_dec(nmg->mg_obj);
nmg->mg_ptr = mg->mg_ptr;
nmg->mg_obj = SvREFCNT_inc_simple(mg->mg_obj);
nmg->mg_flags |= MGf_REFCOUNTED;
return
1;
}
int
Perl_magic_setdebugvar(pTHX_ SV *sv, MAGIC *mg) {
PERL_ARGS_ASSERT_MAGIC_SETDEBUGVAR;
#if DBVARMG_SINGLE != 0
assert
(mg->mg_private >= DBVARMG_SINGLE);
#endif
assert
(mg->mg_private < DBVARMG_COUNT);
PL_DBcontrol[mg->mg_private] = SvIV_nomg(sv);
return
1;
}
int
Perl_magic_getdebugvar(pTHX_ SV *sv, MAGIC *mg) {
PERL_ARGS_ASSERT_MAGIC_GETDEBUGVAR;
#if DBVARMG_SINGLE != 0
assert
(mg->mg_private >= DBVARMG_SINGLE);
#endif
assert
(mg->mg_private < DBVARMG_COUNT);
sv_setiv(sv, PL_DBcontrol[mg->mg_private]);
return
0;
}