mirror of
https://git.FreeBSD.org/src.git
synced 2024-12-21 11:13:30 +00:00
8414 lines
187 KiB
C
8414 lines
187 KiB
C
/* sv.c
|
|
*
|
|
* Copyright (c) 1991-2001, Larry Wall
|
|
*
|
|
* You may distribute under the terms of either the GNU General Public
|
|
* License or the Artistic License, as specified in the README file.
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* "I wonder what the Entish is for 'yes' and 'no'," he thought.
|
|
*/
|
|
|
|
#include "EXTERN.h"
|
|
#define PERL_IN_SV_C
|
|
#include "perl.h"
|
|
|
|
#define FCALL *f
|
|
#define SV_CHECK_THINKFIRST(sv) if (SvTHINKFIRST(sv)) sv_force_normal(sv)
|
|
|
|
static void do_report_used(pTHXo_ SV *sv);
|
|
static void do_clean_objs(pTHXo_ SV *sv);
|
|
#ifndef DISABLE_DESTRUCTOR_KLUDGE
|
|
static void do_clean_named_objs(pTHXo_ SV *sv);
|
|
#endif
|
|
static void do_clean_all(pTHXo_ SV *sv);
|
|
|
|
/*
|
|
* "A time to plant, and a time to uproot what was planted..."
|
|
*/
|
|
|
|
#define plant_SV(p) \
|
|
STMT_START { \
|
|
SvANY(p) = (void *)PL_sv_root; \
|
|
SvFLAGS(p) = SVTYPEMASK; \
|
|
PL_sv_root = (p); \
|
|
--PL_sv_count; \
|
|
} STMT_END
|
|
|
|
/* sv_mutex must be held while calling uproot_SV() */
|
|
#define uproot_SV(p) \
|
|
STMT_START { \
|
|
(p) = PL_sv_root; \
|
|
PL_sv_root = (SV*)SvANY(p); \
|
|
++PL_sv_count; \
|
|
} STMT_END
|
|
|
|
#define new_SV(p) \
|
|
STMT_START { \
|
|
LOCK_SV_MUTEX; \
|
|
if (PL_sv_root) \
|
|
uproot_SV(p); \
|
|
else \
|
|
(p) = more_sv(); \
|
|
UNLOCK_SV_MUTEX; \
|
|
SvANY(p) = 0; \
|
|
SvREFCNT(p) = 1; \
|
|
SvFLAGS(p) = 0; \
|
|
} STMT_END
|
|
|
|
#ifdef DEBUGGING
|
|
|
|
#define del_SV(p) \
|
|
STMT_START { \
|
|
LOCK_SV_MUTEX; \
|
|
if (PL_debug & 32768) \
|
|
del_sv(p); \
|
|
else \
|
|
plant_SV(p); \
|
|
UNLOCK_SV_MUTEX; \
|
|
} STMT_END
|
|
|
|
STATIC void
|
|
S_del_sv(pTHX_ SV *p)
|
|
{
|
|
if (PL_debug & 32768) {
|
|
SV* sva;
|
|
SV* sv;
|
|
SV* svend;
|
|
int ok = 0;
|
|
for (sva = PL_sv_arenaroot; sva; sva = (SV *) SvANY(sva)) {
|
|
sv = sva + 1;
|
|
svend = &sva[SvREFCNT(sva)];
|
|
if (p >= sv && p < svend)
|
|
ok = 1;
|
|
}
|
|
if (!ok) {
|
|
if (ckWARN_d(WARN_INTERNAL))
|
|
Perl_warner(aTHX_ WARN_INTERNAL,
|
|
"Attempt to free non-arena SV: 0x%"UVxf,
|
|
PTR2UV(p));
|
|
return;
|
|
}
|
|
}
|
|
plant_SV(p);
|
|
}
|
|
|
|
#else /* ! DEBUGGING */
|
|
|
|
#define del_SV(p) plant_SV(p)
|
|
|
|
#endif /* DEBUGGING */
|
|
|
|
void
|
|
Perl_sv_add_arena(pTHX_ char *ptr, U32 size, U32 flags)
|
|
{
|
|
SV* sva = (SV*)ptr;
|
|
register SV* sv;
|
|
register SV* svend;
|
|
Zero(ptr, size, char);
|
|
|
|
/* The first SV in an arena isn't an SV. */
|
|
SvANY(sva) = (void *) PL_sv_arenaroot; /* ptr to next arena */
|
|
SvREFCNT(sva) = size / sizeof(SV); /* number of SV slots */
|
|
SvFLAGS(sva) = flags; /* FAKE if not to be freed */
|
|
|
|
PL_sv_arenaroot = sva;
|
|
PL_sv_root = sva + 1;
|
|
|
|
svend = &sva[SvREFCNT(sva) - 1];
|
|
sv = sva + 1;
|
|
while (sv < svend) {
|
|
SvANY(sv) = (void *)(SV*)(sv + 1);
|
|
SvFLAGS(sv) = SVTYPEMASK;
|
|
sv++;
|
|
}
|
|
SvANY(sv) = 0;
|
|
SvFLAGS(sv) = SVTYPEMASK;
|
|
}
|
|
|
|
/* sv_mutex must be held while calling more_sv() */
|
|
STATIC SV*
|
|
S_more_sv(pTHX)
|
|
{
|
|
register SV* sv;
|
|
|
|
if (PL_nice_chunk) {
|
|
sv_add_arena(PL_nice_chunk, PL_nice_chunk_size, 0);
|
|
PL_nice_chunk = Nullch;
|
|
}
|
|
else {
|
|
char *chunk; /* must use New here to match call to */
|
|
New(704,chunk,1008,char); /* Safefree() in sv_free_arenas() */
|
|
sv_add_arena(chunk, 1008, 0);
|
|
}
|
|
uproot_SV(sv);
|
|
return sv;
|
|
}
|
|
|
|
STATIC I32
|
|
S_visit(pTHX_ SVFUNC_t f)
|
|
{
|
|
SV* sva;
|
|
SV* sv;
|
|
register SV* svend;
|
|
I32 visited = 0;
|
|
|
|
for (sva = PL_sv_arenaroot; sva; sva = (SV*)SvANY(sva)) {
|
|
svend = &sva[SvREFCNT(sva)];
|
|
for (sv = sva + 1; sv < svend; ++sv) {
|
|
if (SvTYPE(sv) != SVTYPEMASK && SvREFCNT(sv)) {
|
|
(FCALL)(aTHXo_ sv);
|
|
++visited;
|
|
}
|
|
}
|
|
}
|
|
return visited;
|
|
}
|
|
|
|
void
|
|
Perl_sv_report_used(pTHX)
|
|
{
|
|
visit(do_report_used);
|
|
}
|
|
|
|
void
|
|
Perl_sv_clean_objs(pTHX)
|
|
{
|
|
PL_in_clean_objs = TRUE;
|
|
visit(do_clean_objs);
|
|
#ifndef DISABLE_DESTRUCTOR_KLUDGE
|
|
/* some barnacles may yet remain, clinging to typeglobs */
|
|
visit(do_clean_named_objs);
|
|
#endif
|
|
PL_in_clean_objs = FALSE;
|
|
}
|
|
|
|
I32
|
|
Perl_sv_clean_all(pTHX)
|
|
{
|
|
I32 cleaned;
|
|
PL_in_clean_all = TRUE;
|
|
cleaned = visit(do_clean_all);
|
|
PL_in_clean_all = FALSE;
|
|
return cleaned;
|
|
}
|
|
|
|
void
|
|
Perl_sv_free_arenas(pTHX)
|
|
{
|
|
SV* sva;
|
|
SV* svanext;
|
|
XPV *arena, *arenanext;
|
|
|
|
/* Free arenas here, but be careful about fake ones. (We assume
|
|
contiguity of the fake ones with the corresponding real ones.) */
|
|
|
|
for (sva = PL_sv_arenaroot; sva; sva = svanext) {
|
|
svanext = (SV*) SvANY(sva);
|
|
while (svanext && SvFAKE(svanext))
|
|
svanext = (SV*) SvANY(svanext);
|
|
|
|
if (!SvFAKE(sva))
|
|
Safefree((void *)sva);
|
|
}
|
|
|
|
for (arena = PL_xiv_arenaroot; arena; arena = arenanext) {
|
|
arenanext = (XPV*)arena->xpv_pv;
|
|
Safefree(arena);
|
|
}
|
|
PL_xiv_arenaroot = 0;
|
|
|
|
for (arena = PL_xnv_arenaroot; arena; arena = arenanext) {
|
|
arenanext = (XPV*)arena->xpv_pv;
|
|
Safefree(arena);
|
|
}
|
|
PL_xnv_arenaroot = 0;
|
|
|
|
for (arena = PL_xrv_arenaroot; arena; arena = arenanext) {
|
|
arenanext = (XPV*)arena->xpv_pv;
|
|
Safefree(arena);
|
|
}
|
|
PL_xrv_arenaroot = 0;
|
|
|
|
for (arena = PL_xpv_arenaroot; arena; arena = arenanext) {
|
|
arenanext = (XPV*)arena->xpv_pv;
|
|
Safefree(arena);
|
|
}
|
|
PL_xpv_arenaroot = 0;
|
|
|
|
for (arena = (XPV*)PL_xpviv_arenaroot; arena; arena = arenanext) {
|
|
arenanext = (XPV*)arena->xpv_pv;
|
|
Safefree(arena);
|
|
}
|
|
PL_xpviv_arenaroot = 0;
|
|
|
|
for (arena = (XPV*)PL_xpvnv_arenaroot; arena; arena = arenanext) {
|
|
arenanext = (XPV*)arena->xpv_pv;
|
|
Safefree(arena);
|
|
}
|
|
PL_xpvnv_arenaroot = 0;
|
|
|
|
for (arena = (XPV*)PL_xpvcv_arenaroot; arena; arena = arenanext) {
|
|
arenanext = (XPV*)arena->xpv_pv;
|
|
Safefree(arena);
|
|
}
|
|
PL_xpvcv_arenaroot = 0;
|
|
|
|
for (arena = (XPV*)PL_xpvav_arenaroot; arena; arena = arenanext) {
|
|
arenanext = (XPV*)arena->xpv_pv;
|
|
Safefree(arena);
|
|
}
|
|
PL_xpvav_arenaroot = 0;
|
|
|
|
for (arena = (XPV*)PL_xpvhv_arenaroot; arena; arena = arenanext) {
|
|
arenanext = (XPV*)arena->xpv_pv;
|
|
Safefree(arena);
|
|
}
|
|
PL_xpvhv_arenaroot = 0;
|
|
|
|
for (arena = (XPV*)PL_xpvmg_arenaroot; arena; arena = arenanext) {
|
|
arenanext = (XPV*)arena->xpv_pv;
|
|
Safefree(arena);
|
|
}
|
|
PL_xpvmg_arenaroot = 0;
|
|
|
|
for (arena = (XPV*)PL_xpvlv_arenaroot; arena; arena = arenanext) {
|
|
arenanext = (XPV*)arena->xpv_pv;
|
|
Safefree(arena);
|
|
}
|
|
PL_xpvlv_arenaroot = 0;
|
|
|
|
for (arena = (XPV*)PL_xpvbm_arenaroot; arena; arena = arenanext) {
|
|
arenanext = (XPV*)arena->xpv_pv;
|
|
Safefree(arena);
|
|
}
|
|
PL_xpvbm_arenaroot = 0;
|
|
|
|
for (arena = (XPV*)PL_he_arenaroot; arena; arena = arenanext) {
|
|
arenanext = (XPV*)arena->xpv_pv;
|
|
Safefree(arena);
|
|
}
|
|
PL_he_arenaroot = 0;
|
|
|
|
if (PL_nice_chunk)
|
|
Safefree(PL_nice_chunk);
|
|
PL_nice_chunk = Nullch;
|
|
PL_nice_chunk_size = 0;
|
|
PL_sv_arenaroot = 0;
|
|
PL_sv_root = 0;
|
|
}
|
|
|
|
void
|
|
Perl_report_uninit(pTHX)
|
|
{
|
|
if (PL_op)
|
|
Perl_warner(aTHX_ WARN_UNINITIALIZED, PL_warn_uninit,
|
|
" in ", PL_op_desc[PL_op->op_type]);
|
|
else
|
|
Perl_warner(aTHX_ WARN_UNINITIALIZED, PL_warn_uninit, "", "");
|
|
}
|
|
|
|
STATIC XPVIV*
|
|
S_new_xiv(pTHX)
|
|
{
|
|
IV* xiv;
|
|
LOCK_SV_MUTEX;
|
|
if (!PL_xiv_root)
|
|
more_xiv();
|
|
xiv = PL_xiv_root;
|
|
/*
|
|
* See comment in more_xiv() -- RAM.
|
|
*/
|
|
PL_xiv_root = *(IV**)xiv;
|
|
UNLOCK_SV_MUTEX;
|
|
return (XPVIV*)((char*)xiv - STRUCT_OFFSET(XPVIV, xiv_iv));
|
|
}
|
|
|
|
STATIC void
|
|
S_del_xiv(pTHX_ XPVIV *p)
|
|
{
|
|
IV* xiv = (IV*)((char*)(p) + STRUCT_OFFSET(XPVIV, xiv_iv));
|
|
LOCK_SV_MUTEX;
|
|
*(IV**)xiv = PL_xiv_root;
|
|
PL_xiv_root = xiv;
|
|
UNLOCK_SV_MUTEX;
|
|
}
|
|
|
|
STATIC void
|
|
S_more_xiv(pTHX)
|
|
{
|
|
register IV* xiv;
|
|
register IV* xivend;
|
|
XPV* ptr;
|
|
New(705, ptr, 1008/sizeof(XPV), XPV);
|
|
ptr->xpv_pv = (char*)PL_xiv_arenaroot; /* linked list of xiv arenas */
|
|
PL_xiv_arenaroot = ptr; /* to keep Purify happy */
|
|
|
|
xiv = (IV*) ptr;
|
|
xivend = &xiv[1008 / sizeof(IV) - 1];
|
|
xiv += (sizeof(XPV) - 1) / sizeof(IV) + 1; /* fudge by size of XPV */
|
|
PL_xiv_root = xiv;
|
|
while (xiv < xivend) {
|
|
*(IV**)xiv = (IV *)(xiv + 1);
|
|
xiv++;
|
|
}
|
|
*(IV**)xiv = 0;
|
|
}
|
|
|
|
STATIC XPVNV*
|
|
S_new_xnv(pTHX)
|
|
{
|
|
NV* xnv;
|
|
LOCK_SV_MUTEX;
|
|
if (!PL_xnv_root)
|
|
more_xnv();
|
|
xnv = PL_xnv_root;
|
|
PL_xnv_root = *(NV**)xnv;
|
|
UNLOCK_SV_MUTEX;
|
|
return (XPVNV*)((char*)xnv - STRUCT_OFFSET(XPVNV, xnv_nv));
|
|
}
|
|
|
|
STATIC void
|
|
S_del_xnv(pTHX_ XPVNV *p)
|
|
{
|
|
NV* xnv = (NV*)((char*)(p) + STRUCT_OFFSET(XPVNV, xnv_nv));
|
|
LOCK_SV_MUTEX;
|
|
*(NV**)xnv = PL_xnv_root;
|
|
PL_xnv_root = xnv;
|
|
UNLOCK_SV_MUTEX;
|
|
}
|
|
|
|
STATIC void
|
|
S_more_xnv(pTHX)
|
|
{
|
|
register NV* xnv;
|
|
register NV* xnvend;
|
|
XPV *ptr;
|
|
New(711, ptr, 1008/sizeof(XPV), XPV);
|
|
ptr->xpv_pv = (char*)PL_xnv_arenaroot;
|
|
PL_xnv_arenaroot = ptr;
|
|
|
|
xnv = (NV*) ptr;
|
|
xnvend = &xnv[1008 / sizeof(NV) - 1];
|
|
xnv += (sizeof(XPVIV) - 1) / sizeof(NV) + 1; /* fudge by sizeof XPVIV */
|
|
PL_xnv_root = xnv;
|
|
while (xnv < xnvend) {
|
|
*(NV**)xnv = (NV*)(xnv + 1);
|
|
xnv++;
|
|
}
|
|
*(NV**)xnv = 0;
|
|
}
|
|
|
|
STATIC XRV*
|
|
S_new_xrv(pTHX)
|
|
{
|
|
XRV* xrv;
|
|
LOCK_SV_MUTEX;
|
|
if (!PL_xrv_root)
|
|
more_xrv();
|
|
xrv = PL_xrv_root;
|
|
PL_xrv_root = (XRV*)xrv->xrv_rv;
|
|
UNLOCK_SV_MUTEX;
|
|
return xrv;
|
|
}
|
|
|
|
STATIC void
|
|
S_del_xrv(pTHX_ XRV *p)
|
|
{
|
|
LOCK_SV_MUTEX;
|
|
p->xrv_rv = (SV*)PL_xrv_root;
|
|
PL_xrv_root = p;
|
|
UNLOCK_SV_MUTEX;
|
|
}
|
|
|
|
STATIC void
|
|
S_more_xrv(pTHX)
|
|
{
|
|
register XRV* xrv;
|
|
register XRV* xrvend;
|
|
XPV *ptr;
|
|
New(712, ptr, 1008/sizeof(XPV), XPV);
|
|
ptr->xpv_pv = (char*)PL_xrv_arenaroot;
|
|
PL_xrv_arenaroot = ptr;
|
|
|
|
xrv = (XRV*) ptr;
|
|
xrvend = &xrv[1008 / sizeof(XRV) - 1];
|
|
xrv += (sizeof(XPV) - 1) / sizeof(XRV) + 1;
|
|
PL_xrv_root = xrv;
|
|
while (xrv < xrvend) {
|
|
xrv->xrv_rv = (SV*)(xrv + 1);
|
|
xrv++;
|
|
}
|
|
xrv->xrv_rv = 0;
|
|
}
|
|
|
|
STATIC XPV*
|
|
S_new_xpv(pTHX)
|
|
{
|
|
XPV* xpv;
|
|
LOCK_SV_MUTEX;
|
|
if (!PL_xpv_root)
|
|
more_xpv();
|
|
xpv = PL_xpv_root;
|
|
PL_xpv_root = (XPV*)xpv->xpv_pv;
|
|
UNLOCK_SV_MUTEX;
|
|
return xpv;
|
|
}
|
|
|
|
STATIC void
|
|
S_del_xpv(pTHX_ XPV *p)
|
|
{
|
|
LOCK_SV_MUTEX;
|
|
p->xpv_pv = (char*)PL_xpv_root;
|
|
PL_xpv_root = p;
|
|
UNLOCK_SV_MUTEX;
|
|
}
|
|
|
|
STATIC void
|
|
S_more_xpv(pTHX)
|
|
{
|
|
register XPV* xpv;
|
|
register XPV* xpvend;
|
|
New(713, xpv, 1008/sizeof(XPV), XPV);
|
|
xpv->xpv_pv = (char*)PL_xpv_arenaroot;
|
|
PL_xpv_arenaroot = xpv;
|
|
|
|
xpvend = &xpv[1008 / sizeof(XPV) - 1];
|
|
PL_xpv_root = ++xpv;
|
|
while (xpv < xpvend) {
|
|
xpv->xpv_pv = (char*)(xpv + 1);
|
|
xpv++;
|
|
}
|
|
xpv->xpv_pv = 0;
|
|
}
|
|
|
|
STATIC XPVIV*
|
|
S_new_xpviv(pTHX)
|
|
{
|
|
XPVIV* xpviv;
|
|
LOCK_SV_MUTEX;
|
|
if (!PL_xpviv_root)
|
|
more_xpviv();
|
|
xpviv = PL_xpviv_root;
|
|
PL_xpviv_root = (XPVIV*)xpviv->xpv_pv;
|
|
UNLOCK_SV_MUTEX;
|
|
return xpviv;
|
|
}
|
|
|
|
STATIC void
|
|
S_del_xpviv(pTHX_ XPVIV *p)
|
|
{
|
|
LOCK_SV_MUTEX;
|
|
p->xpv_pv = (char*)PL_xpviv_root;
|
|
PL_xpviv_root = p;
|
|
UNLOCK_SV_MUTEX;
|
|
}
|
|
|
|
STATIC void
|
|
S_more_xpviv(pTHX)
|
|
{
|
|
register XPVIV* xpviv;
|
|
register XPVIV* xpvivend;
|
|
New(714, xpviv, 1008/sizeof(XPVIV), XPVIV);
|
|
xpviv->xpv_pv = (char*)PL_xpviv_arenaroot;
|
|
PL_xpviv_arenaroot = xpviv;
|
|
|
|
xpvivend = &xpviv[1008 / sizeof(XPVIV) - 1];
|
|
PL_xpviv_root = ++xpviv;
|
|
while (xpviv < xpvivend) {
|
|
xpviv->xpv_pv = (char*)(xpviv + 1);
|
|
xpviv++;
|
|
}
|
|
xpviv->xpv_pv = 0;
|
|
}
|
|
|
|
STATIC XPVNV*
|
|
S_new_xpvnv(pTHX)
|
|
{
|
|
XPVNV* xpvnv;
|
|
LOCK_SV_MUTEX;
|
|
if (!PL_xpvnv_root)
|
|
more_xpvnv();
|
|
xpvnv = PL_xpvnv_root;
|
|
PL_xpvnv_root = (XPVNV*)xpvnv->xpv_pv;
|
|
UNLOCK_SV_MUTEX;
|
|
return xpvnv;
|
|
}
|
|
|
|
STATIC void
|
|
S_del_xpvnv(pTHX_ XPVNV *p)
|
|
{
|
|
LOCK_SV_MUTEX;
|
|
p->xpv_pv = (char*)PL_xpvnv_root;
|
|
PL_xpvnv_root = p;
|
|
UNLOCK_SV_MUTEX;
|
|
}
|
|
|
|
STATIC void
|
|
S_more_xpvnv(pTHX)
|
|
{
|
|
register XPVNV* xpvnv;
|
|
register XPVNV* xpvnvend;
|
|
New(715, xpvnv, 1008/sizeof(XPVNV), XPVNV);
|
|
xpvnv->xpv_pv = (char*)PL_xpvnv_arenaroot;
|
|
PL_xpvnv_arenaroot = xpvnv;
|
|
|
|
xpvnvend = &xpvnv[1008 / sizeof(XPVNV) - 1];
|
|
PL_xpvnv_root = ++xpvnv;
|
|
while (xpvnv < xpvnvend) {
|
|
xpvnv->xpv_pv = (char*)(xpvnv + 1);
|
|
xpvnv++;
|
|
}
|
|
xpvnv->xpv_pv = 0;
|
|
}
|
|
|
|
STATIC XPVCV*
|
|
S_new_xpvcv(pTHX)
|
|
{
|
|
XPVCV* xpvcv;
|
|
LOCK_SV_MUTEX;
|
|
if (!PL_xpvcv_root)
|
|
more_xpvcv();
|
|
xpvcv = PL_xpvcv_root;
|
|
PL_xpvcv_root = (XPVCV*)xpvcv->xpv_pv;
|
|
UNLOCK_SV_MUTEX;
|
|
return xpvcv;
|
|
}
|
|
|
|
STATIC void
|
|
S_del_xpvcv(pTHX_ XPVCV *p)
|
|
{
|
|
LOCK_SV_MUTEX;
|
|
p->xpv_pv = (char*)PL_xpvcv_root;
|
|
PL_xpvcv_root = p;
|
|
UNLOCK_SV_MUTEX;
|
|
}
|
|
|
|
STATIC void
|
|
S_more_xpvcv(pTHX)
|
|
{
|
|
register XPVCV* xpvcv;
|
|
register XPVCV* xpvcvend;
|
|
New(716, xpvcv, 1008/sizeof(XPVCV), XPVCV);
|
|
xpvcv->xpv_pv = (char*)PL_xpvcv_arenaroot;
|
|
PL_xpvcv_arenaroot = xpvcv;
|
|
|
|
xpvcvend = &xpvcv[1008 / sizeof(XPVCV) - 1];
|
|
PL_xpvcv_root = ++xpvcv;
|
|
while (xpvcv < xpvcvend) {
|
|
xpvcv->xpv_pv = (char*)(xpvcv + 1);
|
|
xpvcv++;
|
|
}
|
|
xpvcv->xpv_pv = 0;
|
|
}
|
|
|
|
STATIC XPVAV*
|
|
S_new_xpvav(pTHX)
|
|
{
|
|
XPVAV* xpvav;
|
|
LOCK_SV_MUTEX;
|
|
if (!PL_xpvav_root)
|
|
more_xpvav();
|
|
xpvav = PL_xpvav_root;
|
|
PL_xpvav_root = (XPVAV*)xpvav->xav_array;
|
|
UNLOCK_SV_MUTEX;
|
|
return xpvav;
|
|
}
|
|
|
|
STATIC void
|
|
S_del_xpvav(pTHX_ XPVAV *p)
|
|
{
|
|
LOCK_SV_MUTEX;
|
|
p->xav_array = (char*)PL_xpvav_root;
|
|
PL_xpvav_root = p;
|
|
UNLOCK_SV_MUTEX;
|
|
}
|
|
|
|
STATIC void
|
|
S_more_xpvav(pTHX)
|
|
{
|
|
register XPVAV* xpvav;
|
|
register XPVAV* xpvavend;
|
|
New(717, xpvav, 1008/sizeof(XPVAV), XPVAV);
|
|
xpvav->xav_array = (char*)PL_xpvav_arenaroot;
|
|
PL_xpvav_arenaroot = xpvav;
|
|
|
|
xpvavend = &xpvav[1008 / sizeof(XPVAV) - 1];
|
|
PL_xpvav_root = ++xpvav;
|
|
while (xpvav < xpvavend) {
|
|
xpvav->xav_array = (char*)(xpvav + 1);
|
|
xpvav++;
|
|
}
|
|
xpvav->xav_array = 0;
|
|
}
|
|
|
|
STATIC XPVHV*
|
|
S_new_xpvhv(pTHX)
|
|
{
|
|
XPVHV* xpvhv;
|
|
LOCK_SV_MUTEX;
|
|
if (!PL_xpvhv_root)
|
|
more_xpvhv();
|
|
xpvhv = PL_xpvhv_root;
|
|
PL_xpvhv_root = (XPVHV*)xpvhv->xhv_array;
|
|
UNLOCK_SV_MUTEX;
|
|
return xpvhv;
|
|
}
|
|
|
|
STATIC void
|
|
S_del_xpvhv(pTHX_ XPVHV *p)
|
|
{
|
|
LOCK_SV_MUTEX;
|
|
p->xhv_array = (char*)PL_xpvhv_root;
|
|
PL_xpvhv_root = p;
|
|
UNLOCK_SV_MUTEX;
|
|
}
|
|
|
|
STATIC void
|
|
S_more_xpvhv(pTHX)
|
|
{
|
|
register XPVHV* xpvhv;
|
|
register XPVHV* xpvhvend;
|
|
New(718, xpvhv, 1008/sizeof(XPVHV), XPVHV);
|
|
xpvhv->xhv_array = (char*)PL_xpvhv_arenaroot;
|
|
PL_xpvhv_arenaroot = xpvhv;
|
|
|
|
xpvhvend = &xpvhv[1008 / sizeof(XPVHV) - 1];
|
|
PL_xpvhv_root = ++xpvhv;
|
|
while (xpvhv < xpvhvend) {
|
|
xpvhv->xhv_array = (char*)(xpvhv + 1);
|
|
xpvhv++;
|
|
}
|
|
xpvhv->xhv_array = 0;
|
|
}
|
|
|
|
STATIC XPVMG*
|
|
S_new_xpvmg(pTHX)
|
|
{
|
|
XPVMG* xpvmg;
|
|
LOCK_SV_MUTEX;
|
|
if (!PL_xpvmg_root)
|
|
more_xpvmg();
|
|
xpvmg = PL_xpvmg_root;
|
|
PL_xpvmg_root = (XPVMG*)xpvmg->xpv_pv;
|
|
UNLOCK_SV_MUTEX;
|
|
return xpvmg;
|
|
}
|
|
|
|
STATIC void
|
|
S_del_xpvmg(pTHX_ XPVMG *p)
|
|
{
|
|
LOCK_SV_MUTEX;
|
|
p->xpv_pv = (char*)PL_xpvmg_root;
|
|
PL_xpvmg_root = p;
|
|
UNLOCK_SV_MUTEX;
|
|
}
|
|
|
|
STATIC void
|
|
S_more_xpvmg(pTHX)
|
|
{
|
|
register XPVMG* xpvmg;
|
|
register XPVMG* xpvmgend;
|
|
New(719, xpvmg, 1008/sizeof(XPVMG), XPVMG);
|
|
xpvmg->xpv_pv = (char*)PL_xpvmg_arenaroot;
|
|
PL_xpvmg_arenaroot = xpvmg;
|
|
|
|
xpvmgend = &xpvmg[1008 / sizeof(XPVMG) - 1];
|
|
PL_xpvmg_root = ++xpvmg;
|
|
while (xpvmg < xpvmgend) {
|
|
xpvmg->xpv_pv = (char*)(xpvmg + 1);
|
|
xpvmg++;
|
|
}
|
|
xpvmg->xpv_pv = 0;
|
|
}
|
|
|
|
STATIC XPVLV*
|
|
S_new_xpvlv(pTHX)
|
|
{
|
|
XPVLV* xpvlv;
|
|
LOCK_SV_MUTEX;
|
|
if (!PL_xpvlv_root)
|
|
more_xpvlv();
|
|
xpvlv = PL_xpvlv_root;
|
|
PL_xpvlv_root = (XPVLV*)xpvlv->xpv_pv;
|
|
UNLOCK_SV_MUTEX;
|
|
return xpvlv;
|
|
}
|
|
|
|
STATIC void
|
|
S_del_xpvlv(pTHX_ XPVLV *p)
|
|
{
|
|
LOCK_SV_MUTEX;
|
|
p->xpv_pv = (char*)PL_xpvlv_root;
|
|
PL_xpvlv_root = p;
|
|
UNLOCK_SV_MUTEX;
|
|
}
|
|
|
|
STATIC void
|
|
S_more_xpvlv(pTHX)
|
|
{
|
|
register XPVLV* xpvlv;
|
|
register XPVLV* xpvlvend;
|
|
New(720, xpvlv, 1008/sizeof(XPVLV), XPVLV);
|
|
xpvlv->xpv_pv = (char*)PL_xpvlv_arenaroot;
|
|
PL_xpvlv_arenaroot = xpvlv;
|
|
|
|
xpvlvend = &xpvlv[1008 / sizeof(XPVLV) - 1];
|
|
PL_xpvlv_root = ++xpvlv;
|
|
while (xpvlv < xpvlvend) {
|
|
xpvlv->xpv_pv = (char*)(xpvlv + 1);
|
|
xpvlv++;
|
|
}
|
|
xpvlv->xpv_pv = 0;
|
|
}
|
|
|
|
STATIC XPVBM*
|
|
S_new_xpvbm(pTHX)
|
|
{
|
|
XPVBM* xpvbm;
|
|
LOCK_SV_MUTEX;
|
|
if (!PL_xpvbm_root)
|
|
more_xpvbm();
|
|
xpvbm = PL_xpvbm_root;
|
|
PL_xpvbm_root = (XPVBM*)xpvbm->xpv_pv;
|
|
UNLOCK_SV_MUTEX;
|
|
return xpvbm;
|
|
}
|
|
|
|
STATIC void
|
|
S_del_xpvbm(pTHX_ XPVBM *p)
|
|
{
|
|
LOCK_SV_MUTEX;
|
|
p->xpv_pv = (char*)PL_xpvbm_root;
|
|
PL_xpvbm_root = p;
|
|
UNLOCK_SV_MUTEX;
|
|
}
|
|
|
|
STATIC void
|
|
S_more_xpvbm(pTHX)
|
|
{
|
|
register XPVBM* xpvbm;
|
|
register XPVBM* xpvbmend;
|
|
New(721, xpvbm, 1008/sizeof(XPVBM), XPVBM);
|
|
xpvbm->xpv_pv = (char*)PL_xpvbm_arenaroot;
|
|
PL_xpvbm_arenaroot = xpvbm;
|
|
|
|
xpvbmend = &xpvbm[1008 / sizeof(XPVBM) - 1];
|
|
PL_xpvbm_root = ++xpvbm;
|
|
while (xpvbm < xpvbmend) {
|
|
xpvbm->xpv_pv = (char*)(xpvbm + 1);
|
|
xpvbm++;
|
|
}
|
|
xpvbm->xpv_pv = 0;
|
|
}
|
|
|
|
#ifdef LEAKTEST
|
|
# define my_safemalloc(s) (void*)safexmalloc(717,s)
|
|
# define my_safefree(p) safexfree((char*)p)
|
|
#else
|
|
# define my_safemalloc(s) (void*)safemalloc(s)
|
|
# define my_safefree(p) safefree((char*)p)
|
|
#endif
|
|
|
|
#ifdef PURIFY
|
|
|
|
#define new_XIV() my_safemalloc(sizeof(XPVIV))
|
|
#define del_XIV(p) my_safefree(p)
|
|
|
|
#define new_XNV() my_safemalloc(sizeof(XPVNV))
|
|
#define del_XNV(p) my_safefree(p)
|
|
|
|
#define new_XRV() my_safemalloc(sizeof(XRV))
|
|
#define del_XRV(p) my_safefree(p)
|
|
|
|
#define new_XPV() my_safemalloc(sizeof(XPV))
|
|
#define del_XPV(p) my_safefree(p)
|
|
|
|
#define new_XPVIV() my_safemalloc(sizeof(XPVIV))
|
|
#define del_XPVIV(p) my_safefree(p)
|
|
|
|
#define new_XPVNV() my_safemalloc(sizeof(XPVNV))
|
|
#define del_XPVNV(p) my_safefree(p)
|
|
|
|
#define new_XPVCV() my_safemalloc(sizeof(XPVCV))
|
|
#define del_XPVCV(p) my_safefree(p)
|
|
|
|
#define new_XPVAV() my_safemalloc(sizeof(XPVAV))
|
|
#define del_XPVAV(p) my_safefree(p)
|
|
|
|
#define new_XPVHV() my_safemalloc(sizeof(XPVHV))
|
|
#define del_XPVHV(p) my_safefree(p)
|
|
|
|
#define new_XPVMG() my_safemalloc(sizeof(XPVMG))
|
|
#define del_XPVMG(p) my_safefree(p)
|
|
|
|
#define new_XPVLV() my_safemalloc(sizeof(XPVLV))
|
|
#define del_XPVLV(p) my_safefree(p)
|
|
|
|
#define new_XPVBM() my_safemalloc(sizeof(XPVBM))
|
|
#define del_XPVBM(p) my_safefree(p)
|
|
|
|
#else /* !PURIFY */
|
|
|
|
#define new_XIV() (void*)new_xiv()
|
|
#define del_XIV(p) del_xiv((XPVIV*) p)
|
|
|
|
#define new_XNV() (void*)new_xnv()
|
|
#define del_XNV(p) del_xnv((XPVNV*) p)
|
|
|
|
#define new_XRV() (void*)new_xrv()
|
|
#define del_XRV(p) del_xrv((XRV*) p)
|
|
|
|
#define new_XPV() (void*)new_xpv()
|
|
#define del_XPV(p) del_xpv((XPV *)p)
|
|
|
|
#define new_XPVIV() (void*)new_xpviv()
|
|
#define del_XPVIV(p) del_xpviv((XPVIV *)p)
|
|
|
|
#define new_XPVNV() (void*)new_xpvnv()
|
|
#define del_XPVNV(p) del_xpvnv((XPVNV *)p)
|
|
|
|
#define new_XPVCV() (void*)new_xpvcv()
|
|
#define del_XPVCV(p) del_xpvcv((XPVCV *)p)
|
|
|
|
#define new_XPVAV() (void*)new_xpvav()
|
|
#define del_XPVAV(p) del_xpvav((XPVAV *)p)
|
|
|
|
#define new_XPVHV() (void*)new_xpvhv()
|
|
#define del_XPVHV(p) del_xpvhv((XPVHV *)p)
|
|
|
|
#define new_XPVMG() (void*)new_xpvmg()
|
|
#define del_XPVMG(p) del_xpvmg((XPVMG *)p)
|
|
|
|
#define new_XPVLV() (void*)new_xpvlv()
|
|
#define del_XPVLV(p) del_xpvlv((XPVLV *)p)
|
|
|
|
#define new_XPVBM() (void*)new_xpvbm()
|
|
#define del_XPVBM(p) del_xpvbm((XPVBM *)p)
|
|
|
|
#endif /* PURIFY */
|
|
|
|
#define new_XPVGV() my_safemalloc(sizeof(XPVGV))
|
|
#define del_XPVGV(p) my_safefree(p)
|
|
|
|
#define new_XPVFM() my_safemalloc(sizeof(XPVFM))
|
|
#define del_XPVFM(p) my_safefree(p)
|
|
|
|
#define new_XPVIO() my_safemalloc(sizeof(XPVIO))
|
|
#define del_XPVIO(p) my_safefree(p)
|
|
|
|
/*
|
|
=for apidoc sv_upgrade
|
|
|
|
Upgrade an SV to a more complex form. Use C<SvUPGRADE>. See
|
|
C<svtype>.
|
|
|
|
=cut
|
|
*/
|
|
|
|
bool
|
|
Perl_sv_upgrade(pTHX_ register SV *sv, U32 mt)
|
|
{
|
|
char* pv;
|
|
U32 cur;
|
|
U32 len;
|
|
IV iv;
|
|
NV nv;
|
|
MAGIC* magic;
|
|
HV* stash;
|
|
|
|
if (SvTYPE(sv) == mt)
|
|
return TRUE;
|
|
|
|
if (mt < SVt_PVIV)
|
|
(void)SvOOK_off(sv);
|
|
|
|
switch (SvTYPE(sv)) {
|
|
case SVt_NULL:
|
|
pv = 0;
|
|
cur = 0;
|
|
len = 0;
|
|
iv = 0;
|
|
nv = 0.0;
|
|
magic = 0;
|
|
stash = 0;
|
|
break;
|
|
case SVt_IV:
|
|
pv = 0;
|
|
cur = 0;
|
|
len = 0;
|
|
iv = SvIVX(sv);
|
|
nv = (NV)SvIVX(sv);
|
|
del_XIV(SvANY(sv));
|
|
magic = 0;
|
|
stash = 0;
|
|
if (mt == SVt_NV)
|
|
mt = SVt_PVNV;
|
|
else if (mt < SVt_PVIV)
|
|
mt = SVt_PVIV;
|
|
break;
|
|
case SVt_NV:
|
|
pv = 0;
|
|
cur = 0;
|
|
len = 0;
|
|
nv = SvNVX(sv);
|
|
iv = I_V(nv);
|
|
magic = 0;
|
|
stash = 0;
|
|
del_XNV(SvANY(sv));
|
|
SvANY(sv) = 0;
|
|
if (mt < SVt_PVNV)
|
|
mt = SVt_PVNV;
|
|
break;
|
|
case SVt_RV:
|
|
pv = (char*)SvRV(sv);
|
|
cur = 0;
|
|
len = 0;
|
|
iv = PTR2IV(pv);
|
|
nv = PTR2NV(pv);
|
|
del_XRV(SvANY(sv));
|
|
magic = 0;
|
|
stash = 0;
|
|
break;
|
|
case SVt_PV:
|
|
pv = SvPVX(sv);
|
|
cur = SvCUR(sv);
|
|
len = SvLEN(sv);
|
|
iv = 0;
|
|
nv = 0.0;
|
|
magic = 0;
|
|
stash = 0;
|
|
del_XPV(SvANY(sv));
|
|
if (mt <= SVt_IV)
|
|
mt = SVt_PVIV;
|
|
else if (mt == SVt_NV)
|
|
mt = SVt_PVNV;
|
|
break;
|
|
case SVt_PVIV:
|
|
pv = SvPVX(sv);
|
|
cur = SvCUR(sv);
|
|
len = SvLEN(sv);
|
|
iv = SvIVX(sv);
|
|
nv = 0.0;
|
|
magic = 0;
|
|
stash = 0;
|
|
del_XPVIV(SvANY(sv));
|
|
break;
|
|
case SVt_PVNV:
|
|
pv = SvPVX(sv);
|
|
cur = SvCUR(sv);
|
|
len = SvLEN(sv);
|
|
iv = SvIVX(sv);
|
|
nv = SvNVX(sv);
|
|
magic = 0;
|
|
stash = 0;
|
|
del_XPVNV(SvANY(sv));
|
|
break;
|
|
case SVt_PVMG:
|
|
pv = SvPVX(sv);
|
|
cur = SvCUR(sv);
|
|
len = SvLEN(sv);
|
|
iv = SvIVX(sv);
|
|
nv = SvNVX(sv);
|
|
magic = SvMAGIC(sv);
|
|
stash = SvSTASH(sv);
|
|
del_XPVMG(SvANY(sv));
|
|
break;
|
|
default:
|
|
Perl_croak(aTHX_ "Can't upgrade that kind of scalar");
|
|
}
|
|
|
|
switch (mt) {
|
|
case SVt_NULL:
|
|
Perl_croak(aTHX_ "Can't upgrade to undef");
|
|
case SVt_IV:
|
|
SvANY(sv) = new_XIV();
|
|
SvIVX(sv) = iv;
|
|
break;
|
|
case SVt_NV:
|
|
SvANY(sv) = new_XNV();
|
|
SvNVX(sv) = nv;
|
|
break;
|
|
case SVt_RV:
|
|
SvANY(sv) = new_XRV();
|
|
SvRV(sv) = (SV*)pv;
|
|
break;
|
|
case SVt_PV:
|
|
SvANY(sv) = new_XPV();
|
|
SvPVX(sv) = pv;
|
|
SvCUR(sv) = cur;
|
|
SvLEN(sv) = len;
|
|
break;
|
|
case SVt_PVIV:
|
|
SvANY(sv) = new_XPVIV();
|
|
SvPVX(sv) = pv;
|
|
SvCUR(sv) = cur;
|
|
SvLEN(sv) = len;
|
|
SvIVX(sv) = iv;
|
|
if (SvNIOK(sv))
|
|
(void)SvIOK_on(sv);
|
|
SvNOK_off(sv);
|
|
break;
|
|
case SVt_PVNV:
|
|
SvANY(sv) = new_XPVNV();
|
|
SvPVX(sv) = pv;
|
|
SvCUR(sv) = cur;
|
|
SvLEN(sv) = len;
|
|
SvIVX(sv) = iv;
|
|
SvNVX(sv) = nv;
|
|
break;
|
|
case SVt_PVMG:
|
|
SvANY(sv) = new_XPVMG();
|
|
SvPVX(sv) = pv;
|
|
SvCUR(sv) = cur;
|
|
SvLEN(sv) = len;
|
|
SvIVX(sv) = iv;
|
|
SvNVX(sv) = nv;
|
|
SvMAGIC(sv) = magic;
|
|
SvSTASH(sv) = stash;
|
|
break;
|
|
case SVt_PVLV:
|
|
SvANY(sv) = new_XPVLV();
|
|
SvPVX(sv) = pv;
|
|
SvCUR(sv) = cur;
|
|
SvLEN(sv) = len;
|
|
SvIVX(sv) = iv;
|
|
SvNVX(sv) = nv;
|
|
SvMAGIC(sv) = magic;
|
|
SvSTASH(sv) = stash;
|
|
LvTARGOFF(sv) = 0;
|
|
LvTARGLEN(sv) = 0;
|
|
LvTARG(sv) = 0;
|
|
LvTYPE(sv) = 0;
|
|
break;
|
|
case SVt_PVAV:
|
|
SvANY(sv) = new_XPVAV();
|
|
if (pv)
|
|
Safefree(pv);
|
|
SvPVX(sv) = 0;
|
|
AvMAX(sv) = -1;
|
|
AvFILLp(sv) = -1;
|
|
SvIVX(sv) = 0;
|
|
SvNVX(sv) = 0.0;
|
|
SvMAGIC(sv) = magic;
|
|
SvSTASH(sv) = stash;
|
|
AvALLOC(sv) = 0;
|
|
AvARYLEN(sv) = 0;
|
|
AvFLAGS(sv) = 0;
|
|
break;
|
|
case SVt_PVHV:
|
|
SvANY(sv) = new_XPVHV();
|
|
if (pv)
|
|
Safefree(pv);
|
|
SvPVX(sv) = 0;
|
|
HvFILL(sv) = 0;
|
|
HvMAX(sv) = 0;
|
|
HvKEYS(sv) = 0;
|
|
SvNVX(sv) = 0.0;
|
|
SvMAGIC(sv) = magic;
|
|
SvSTASH(sv) = stash;
|
|
HvRITER(sv) = 0;
|
|
HvEITER(sv) = 0;
|
|
HvPMROOT(sv) = 0;
|
|
HvNAME(sv) = 0;
|
|
break;
|
|
case SVt_PVCV:
|
|
SvANY(sv) = new_XPVCV();
|
|
Zero(SvANY(sv), 1, XPVCV);
|
|
SvPVX(sv) = pv;
|
|
SvCUR(sv) = cur;
|
|
SvLEN(sv) = len;
|
|
SvIVX(sv) = iv;
|
|
SvNVX(sv) = nv;
|
|
SvMAGIC(sv) = magic;
|
|
SvSTASH(sv) = stash;
|
|
break;
|
|
case SVt_PVGV:
|
|
SvANY(sv) = new_XPVGV();
|
|
SvPVX(sv) = pv;
|
|
SvCUR(sv) = cur;
|
|
SvLEN(sv) = len;
|
|
SvIVX(sv) = iv;
|
|
SvNVX(sv) = nv;
|
|
SvMAGIC(sv) = magic;
|
|
SvSTASH(sv) = stash;
|
|
GvGP(sv) = 0;
|
|
GvNAME(sv) = 0;
|
|
GvNAMELEN(sv) = 0;
|
|
GvSTASH(sv) = 0;
|
|
GvFLAGS(sv) = 0;
|
|
break;
|
|
case SVt_PVBM:
|
|
SvANY(sv) = new_XPVBM();
|
|
SvPVX(sv) = pv;
|
|
SvCUR(sv) = cur;
|
|
SvLEN(sv) = len;
|
|
SvIVX(sv) = iv;
|
|
SvNVX(sv) = nv;
|
|
SvMAGIC(sv) = magic;
|
|
SvSTASH(sv) = stash;
|
|
BmRARE(sv) = 0;
|
|
BmUSEFUL(sv) = 0;
|
|
BmPREVIOUS(sv) = 0;
|
|
break;
|
|
case SVt_PVFM:
|
|
SvANY(sv) = new_XPVFM();
|
|
Zero(SvANY(sv), 1, XPVFM);
|
|
SvPVX(sv) = pv;
|
|
SvCUR(sv) = cur;
|
|
SvLEN(sv) = len;
|
|
SvIVX(sv) = iv;
|
|
SvNVX(sv) = nv;
|
|
SvMAGIC(sv) = magic;
|
|
SvSTASH(sv) = stash;
|
|
break;
|
|
case SVt_PVIO:
|
|
SvANY(sv) = new_XPVIO();
|
|
Zero(SvANY(sv), 1, XPVIO);
|
|
SvPVX(sv) = pv;
|
|
SvCUR(sv) = cur;
|
|
SvLEN(sv) = len;
|
|
SvIVX(sv) = iv;
|
|
SvNVX(sv) = nv;
|
|
SvMAGIC(sv) = magic;
|
|
SvSTASH(sv) = stash;
|
|
IoPAGE_LEN(sv) = 60;
|
|
break;
|
|
}
|
|
SvFLAGS(sv) &= ~SVTYPEMASK;
|
|
SvFLAGS(sv) |= mt;
|
|
return TRUE;
|
|
}
|
|
|
|
int
|
|
Perl_sv_backoff(pTHX_ register SV *sv)
|
|
{
|
|
assert(SvOOK(sv));
|
|
if (SvIVX(sv)) {
|
|
char *s = SvPVX(sv);
|
|
SvLEN(sv) += SvIVX(sv);
|
|
SvPVX(sv) -= SvIVX(sv);
|
|
SvIV_set(sv, 0);
|
|
Move(s, SvPVX(sv), SvCUR(sv)+1, char);
|
|
}
|
|
SvFLAGS(sv) &= ~SVf_OOK;
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
=for apidoc sv_grow
|
|
|
|
Expands the character buffer in the SV. This will use C<sv_unref> and will
|
|
upgrade the SV to C<SVt_PV>. Returns a pointer to the character buffer.
|
|
Use C<SvGROW>.
|
|
|
|
=cut
|
|
*/
|
|
|
|
char *
|
|
Perl_sv_grow(pTHX_ register SV *sv, register STRLEN newlen)
|
|
{
|
|
register char *s;
|
|
|
|
#ifdef HAS_64K_LIMIT
|
|
if (newlen >= 0x10000) {
|
|
PerlIO_printf(Perl_debug_log,
|
|
"Allocation too large: %"UVxf"\n", (UV)newlen);
|
|
my_exit(1);
|
|
}
|
|
#endif /* HAS_64K_LIMIT */
|
|
if (SvROK(sv))
|
|
sv_unref(sv);
|
|
if (SvTYPE(sv) < SVt_PV) {
|
|
sv_upgrade(sv, SVt_PV);
|
|
s = SvPVX(sv);
|
|
}
|
|
else if (SvOOK(sv)) { /* pv is offset? */
|
|
sv_backoff(sv);
|
|
s = SvPVX(sv);
|
|
if (newlen > SvLEN(sv))
|
|
newlen += 10 * (newlen - SvCUR(sv)); /* avoid copy each time */
|
|
#ifdef HAS_64K_LIMIT
|
|
if (newlen >= 0x10000)
|
|
newlen = 0xFFFF;
|
|
#endif
|
|
}
|
|
else
|
|
s = SvPVX(sv);
|
|
if (newlen > SvLEN(sv)) { /* need more room? */
|
|
if (SvLEN(sv) && s) {
|
|
#if defined(MYMALLOC) && !defined(LEAKTEST)
|
|
STRLEN l = malloced_size((void*)SvPVX(sv));
|
|
if (newlen <= l) {
|
|
SvLEN_set(sv, l);
|
|
return s;
|
|
} else
|
|
#endif
|
|
Renew(s,newlen,char);
|
|
}
|
|
else
|
|
New(703,s,newlen,char);
|
|
SvPV_set(sv, s);
|
|
SvLEN_set(sv, newlen);
|
|
}
|
|
return s;
|
|
}
|
|
|
|
/*
|
|
=for apidoc sv_setiv
|
|
|
|
Copies an integer into the given SV. Does not handle 'set' magic. See
|
|
C<sv_setiv_mg>.
|
|
|
|
=cut
|
|
*/
|
|
|
|
void
|
|
Perl_sv_setiv(pTHX_ register SV *sv, IV i)
|
|
{
|
|
SV_CHECK_THINKFIRST(sv);
|
|
switch (SvTYPE(sv)) {
|
|
case SVt_NULL:
|
|
sv_upgrade(sv, SVt_IV);
|
|
break;
|
|
case SVt_NV:
|
|
sv_upgrade(sv, SVt_PVNV);
|
|
break;
|
|
case SVt_RV:
|
|
case SVt_PV:
|
|
sv_upgrade(sv, SVt_PVIV);
|
|
break;
|
|
|
|
case SVt_PVGV:
|
|
case SVt_PVAV:
|
|
case SVt_PVHV:
|
|
case SVt_PVCV:
|
|
case SVt_PVFM:
|
|
case SVt_PVIO:
|
|
Perl_croak(aTHX_ "Can't coerce %s to integer in %s", sv_reftype(sv,0),
|
|
PL_op_desc[PL_op->op_type]);
|
|
}
|
|
(void)SvIOK_only(sv); /* validate number */
|
|
SvIVX(sv) = i;
|
|
SvTAINT(sv);
|
|
}
|
|
|
|
/*
|
|
=for apidoc sv_setiv_mg
|
|
|
|
Like C<sv_setiv>, but also handles 'set' magic.
|
|
|
|
=cut
|
|
*/
|
|
|
|
void
|
|
Perl_sv_setiv_mg(pTHX_ register SV *sv, IV i)
|
|
{
|
|
sv_setiv(sv,i);
|
|
SvSETMAGIC(sv);
|
|
}
|
|
|
|
/*
|
|
=for apidoc sv_setuv
|
|
|
|
Copies an unsigned integer into the given SV. Does not handle 'set' magic.
|
|
See C<sv_setuv_mg>.
|
|
|
|
=cut
|
|
*/
|
|
|
|
void
|
|
Perl_sv_setuv(pTHX_ register SV *sv, UV u)
|
|
{
|
|
sv_setiv(sv, 0);
|
|
SvIsUV_on(sv);
|
|
SvUVX(sv) = u;
|
|
}
|
|
|
|
/*
|
|
=for apidoc sv_setuv_mg
|
|
|
|
Like C<sv_setuv>, but also handles 'set' magic.
|
|
|
|
=cut
|
|
*/
|
|
|
|
void
|
|
Perl_sv_setuv_mg(pTHX_ register SV *sv, UV u)
|
|
{
|
|
sv_setuv(sv,u);
|
|
SvSETMAGIC(sv);
|
|
}
|
|
|
|
/*
|
|
=for apidoc sv_setnv
|
|
|
|
Copies a double into the given SV. Does not handle 'set' magic. See
|
|
C<sv_setnv_mg>.
|
|
|
|
=cut
|
|
*/
|
|
|
|
void
|
|
Perl_sv_setnv(pTHX_ register SV *sv, NV num)
|
|
{
|
|
SV_CHECK_THINKFIRST(sv);
|
|
switch (SvTYPE(sv)) {
|
|
case SVt_NULL:
|
|
case SVt_IV:
|
|
sv_upgrade(sv, SVt_NV);
|
|
break;
|
|
case SVt_RV:
|
|
case SVt_PV:
|
|
case SVt_PVIV:
|
|
sv_upgrade(sv, SVt_PVNV);
|
|
break;
|
|
|
|
case SVt_PVGV:
|
|
case SVt_PVAV:
|
|
case SVt_PVHV:
|
|
case SVt_PVCV:
|
|
case SVt_PVFM:
|
|
case SVt_PVIO:
|
|
Perl_croak(aTHX_ "Can't coerce %s to number in %s", sv_reftype(sv,0),
|
|
PL_op_name[PL_op->op_type]);
|
|
}
|
|
SvNVX(sv) = num;
|
|
(void)SvNOK_only(sv); /* validate number */
|
|
SvTAINT(sv);
|
|
}
|
|
|
|
/*
|
|
=for apidoc sv_setnv_mg
|
|
|
|
Like C<sv_setnv>, but also handles 'set' magic.
|
|
|
|
=cut
|
|
*/
|
|
|
|
void
|
|
Perl_sv_setnv_mg(pTHX_ register SV *sv, NV num)
|
|
{
|
|
sv_setnv(sv,num);
|
|
SvSETMAGIC(sv);
|
|
}
|
|
|
|
STATIC void
|
|
S_not_a_number(pTHX_ SV *sv)
|
|
{
|
|
char tmpbuf[64];
|
|
char *d = tmpbuf;
|
|
char *s;
|
|
char *limit = tmpbuf + sizeof(tmpbuf) - 8;
|
|
/* each *s can expand to 4 chars + "...\0",
|
|
i.e. need room for 8 chars */
|
|
|
|
for (s = SvPVX(sv); *s && d < limit; s++) {
|
|
int ch = *s & 0xFF;
|
|
if (ch & 128 && !isPRINT_LC(ch)) {
|
|
*d++ = 'M';
|
|
*d++ = '-';
|
|
ch &= 127;
|
|
}
|
|
if (ch == '\n') {
|
|
*d++ = '\\';
|
|
*d++ = 'n';
|
|
}
|
|
else if (ch == '\r') {
|
|
*d++ = '\\';
|
|
*d++ = 'r';
|
|
}
|
|
else if (ch == '\f') {
|
|
*d++ = '\\';
|
|
*d++ = 'f';
|
|
}
|
|
else if (ch == '\\') {
|
|
*d++ = '\\';
|
|
*d++ = '\\';
|
|
}
|
|
else if (isPRINT_LC(ch))
|
|
*d++ = ch;
|
|
else {
|
|
*d++ = '^';
|
|
*d++ = toCTRL(ch);
|
|
}
|
|
}
|
|
if (*s) {
|
|
*d++ = '.';
|
|
*d++ = '.';
|
|
*d++ = '.';
|
|
}
|
|
*d = '\0';
|
|
|
|
if (PL_op)
|
|
Perl_warner(aTHX_ WARN_NUMERIC,
|
|
"Argument \"%s\" isn't numeric in %s", tmpbuf,
|
|
PL_op_desc[PL_op->op_type]);
|
|
else
|
|
Perl_warner(aTHX_ WARN_NUMERIC,
|
|
"Argument \"%s\" isn't numeric", tmpbuf);
|
|
}
|
|
|
|
/* the number can be converted to integer with atol() or atoll() */
|
|
#define IS_NUMBER_TO_INT_BY_ATOL 0x01
|
|
#define IS_NUMBER_TO_INT_BY_ATOF 0x02 /* atol() may be != atof() */
|
|
#define IS_NUMBER_NOT_IV 0x04 /* (IV)atof() may be != atof() */
|
|
#define IS_NUMBER_NEG 0x08 /* not good to cache UV */
|
|
#define IS_NUMBER_INFINITY 0x10 /* this is big */
|
|
|
|
/* Actually, ISO C leaves conversion of UV to IV undefined, but
|
|
until proven guilty, assume that things are not that bad... */
|
|
|
|
IV
|
|
Perl_sv_2iv(pTHX_ register SV *sv)
|
|
{
|
|
if (!sv)
|
|
return 0;
|
|
if (SvGMAGICAL(sv)) {
|
|
mg_get(sv);
|
|
if (SvIOKp(sv))
|
|
return SvIVX(sv);
|
|
if (SvNOKp(sv)) {
|
|
return I_V(SvNVX(sv));
|
|
}
|
|
if (SvPOKp(sv) && SvLEN(sv))
|
|
return asIV(sv);
|
|
if (!SvROK(sv)) {
|
|
if (!(SvFLAGS(sv) & SVs_PADTMP)) {
|
|
if (ckWARN(WARN_UNINITIALIZED) && !PL_localizing)
|
|
report_uninit();
|
|
}
|
|
return 0;
|
|
}
|
|
}
|
|
if (SvTHINKFIRST(sv)) {
|
|
if (SvROK(sv)) {
|
|
SV* tmpstr;
|
|
if (SvAMAGIC(sv) && (tmpstr=AMG_CALLun(sv,numer)) &&
|
|
(SvRV(tmpstr) != SvRV(sv)))
|
|
return SvIV(tmpstr);
|
|
return PTR2IV(SvRV(sv));
|
|
}
|
|
if (SvREADONLY(sv) && !SvOK(sv)) {
|
|
if (ckWARN(WARN_UNINITIALIZED))
|
|
report_uninit();
|
|
return 0;
|
|
}
|
|
}
|
|
if (SvIOKp(sv)) {
|
|
if (SvIsUV(sv)) {
|
|
return (IV)(SvUVX(sv));
|
|
}
|
|
else {
|
|
return SvIVX(sv);
|
|
}
|
|
}
|
|
if (SvNOKp(sv)) {
|
|
/* We can cache the IV/UV value even if it not good enough
|
|
* to reconstruct NV, since the conversion to PV will prefer
|
|
* NV over IV/UV.
|
|
*/
|
|
|
|
if (SvTYPE(sv) == SVt_NV)
|
|
sv_upgrade(sv, SVt_PVNV);
|
|
|
|
(void)SvIOK_on(sv);
|
|
if (SvNVX(sv) < (NV)IV_MAX + 0.5)
|
|
SvIVX(sv) = I_V(SvNVX(sv));
|
|
else {
|
|
SvUVX(sv) = U_V(SvNVX(sv));
|
|
SvIsUV_on(sv);
|
|
ret_iv_max:
|
|
DEBUG_c(PerlIO_printf(Perl_debug_log,
|
|
"0x%"UVxf" 2iv(%"UVuf" => %"IVdf") (as unsigned)\n",
|
|
PTR2UV(sv),
|
|
SvUVX(sv),
|
|
SvUVX(sv)));
|
|
return (IV)SvUVX(sv);
|
|
}
|
|
}
|
|
else if (SvPOKp(sv) && SvLEN(sv)) {
|
|
I32 numtype = looks_like_number(sv);
|
|
|
|
/* We want to avoid a possible problem when we cache an IV which
|
|
may be later translated to an NV, and the resulting NV is not
|
|
the translation of the initial data.
|
|
|
|
This means that if we cache such an IV, we need to cache the
|
|
NV as well. Moreover, we trade speed for space, and do not
|
|
cache the NV if not needed.
|
|
*/
|
|
if (numtype & IS_NUMBER_NOT_IV) {
|
|
/* May be not an integer. Need to cache NV if we cache IV
|
|
* - otherwise future conversion to NV will be wrong. */
|
|
NV d;
|
|
|
|
d = Atof(SvPVX(sv));
|
|
|
|
if (SvTYPE(sv) < SVt_PVNV)
|
|
sv_upgrade(sv, SVt_PVNV);
|
|
SvNVX(sv) = d;
|
|
(void)SvNOK_on(sv);
|
|
(void)SvIOK_on(sv);
|
|
#if defined(USE_LONG_DOUBLE)
|
|
DEBUG_c(PerlIO_printf(Perl_debug_log, "0x%"UVxf" 2nv(%" PERL_PRIgldbl ")\n",
|
|
PTR2UV(sv), SvNVX(sv)));
|
|
#else
|
|
DEBUG_c(PerlIO_printf(Perl_debug_log, "0x%"UVxf" 2nv(%g)\n",
|
|
PTR2UV(sv), SvNVX(sv)));
|
|
#endif
|
|
if (SvNVX(sv) < (NV)IV_MAX + 0.5)
|
|
SvIVX(sv) = I_V(SvNVX(sv));
|
|
else {
|
|
SvUVX(sv) = U_V(SvNVX(sv));
|
|
SvIsUV_on(sv);
|
|
goto ret_iv_max;
|
|
}
|
|
}
|
|
else { /* The NV may be reconstructed from IV - safe to cache IV,
|
|
which may be calculated by atol(). */
|
|
if (SvTYPE(sv) < SVt_PVIV)
|
|
sv_upgrade(sv, SVt_PVIV);
|
|
(void)SvIOK_on(sv);
|
|
SvIVX(sv) = Atol(SvPVX(sv));
|
|
if (! numtype && ckWARN(WARN_NUMERIC))
|
|
not_a_number(sv);
|
|
}
|
|
}
|
|
else {
|
|
if (ckWARN(WARN_UNINITIALIZED) && !PL_localizing && !(SvFLAGS(sv) & SVs_PADTMP))
|
|
report_uninit();
|
|
if (SvTYPE(sv) < SVt_IV)
|
|
/* Typically the caller expects that sv_any is not NULL now. */
|
|
sv_upgrade(sv, SVt_IV);
|
|
return 0;
|
|
}
|
|
DEBUG_c(PerlIO_printf(Perl_debug_log, "0x%"UVxf" 2iv(%"IVdf")\n",
|
|
PTR2UV(sv),SvIVX(sv)));
|
|
return SvIsUV(sv) ? (IV)SvUVX(sv) : SvIVX(sv);
|
|
}
|
|
|
|
UV
|
|
Perl_sv_2uv(pTHX_ register SV *sv)
|
|
{
|
|
if (!sv)
|
|
return 0;
|
|
if (SvGMAGICAL(sv)) {
|
|
mg_get(sv);
|
|
if (SvIOKp(sv))
|
|
return SvUVX(sv);
|
|
if (SvNOKp(sv))
|
|
return U_V(SvNVX(sv));
|
|
if (SvPOKp(sv) && SvLEN(sv))
|
|
return asUV(sv);
|
|
if (!SvROK(sv)) {
|
|
if (!(SvFLAGS(sv) & SVs_PADTMP)) {
|
|
if (ckWARN(WARN_UNINITIALIZED) && !PL_localizing)
|
|
report_uninit();
|
|
}
|
|
return 0;
|
|
}
|
|
}
|
|
if (SvTHINKFIRST(sv)) {
|
|
if (SvROK(sv)) {
|
|
SV* tmpstr;
|
|
if (SvAMAGIC(sv) && (tmpstr=AMG_CALLun(sv,numer)) &&
|
|
(SvRV(tmpstr) != SvRV(sv)))
|
|
return SvUV(tmpstr);
|
|
return PTR2UV(SvRV(sv));
|
|
}
|
|
if (SvREADONLY(sv) && !SvOK(sv)) {
|
|
if (ckWARN(WARN_UNINITIALIZED))
|
|
report_uninit();
|
|
return 0;
|
|
}
|
|
}
|
|
if (SvIOKp(sv)) {
|
|
if (SvIsUV(sv)) {
|
|
return SvUVX(sv);
|
|
}
|
|
else {
|
|
return (UV)SvIVX(sv);
|
|
}
|
|
}
|
|
if (SvNOKp(sv)) {
|
|
/* We can cache the IV/UV value even if it not good enough
|
|
* to reconstruct NV, since the conversion to PV will prefer
|
|
* NV over IV/UV.
|
|
*/
|
|
if (SvTYPE(sv) == SVt_NV)
|
|
sv_upgrade(sv, SVt_PVNV);
|
|
(void)SvIOK_on(sv);
|
|
if (SvNVX(sv) >= -0.5) {
|
|
SvIsUV_on(sv);
|
|
SvUVX(sv) = U_V(SvNVX(sv));
|
|
}
|
|
else {
|
|
SvIVX(sv) = I_V(SvNVX(sv));
|
|
ret_zero:
|
|
DEBUG_c(PerlIO_printf(Perl_debug_log,
|
|
"0x%"UVxf" 2uv(%"IVdf" => %"IVdf") (as signed)\n",
|
|
PTR2UV(sv),
|
|
SvIVX(sv),
|
|
(IV)(UV)SvIVX(sv)));
|
|
return (UV)SvIVX(sv);
|
|
}
|
|
}
|
|
else if (SvPOKp(sv) && SvLEN(sv)) {
|
|
I32 numtype = looks_like_number(sv);
|
|
|
|
/* We want to avoid a possible problem when we cache a UV which
|
|
may be later translated to an NV, and the resulting NV is not
|
|
the translation of the initial data.
|
|
|
|
This means that if we cache such a UV, we need to cache the
|
|
NV as well. Moreover, we trade speed for space, and do not
|
|
cache the NV if not needed.
|
|
*/
|
|
if (numtype & IS_NUMBER_NOT_IV) {
|
|
/* May be not an integer. Need to cache NV if we cache IV
|
|
* - otherwise future conversion to NV will be wrong. */
|
|
NV d;
|
|
|
|
d = Atof(SvPVX(sv));
|
|
|
|
if (SvTYPE(sv) < SVt_PVNV)
|
|
sv_upgrade(sv, SVt_PVNV);
|
|
SvNVX(sv) = d;
|
|
(void)SvNOK_on(sv);
|
|
(void)SvIOK_on(sv);
|
|
#if defined(USE_LONG_DOUBLE)
|
|
DEBUG_c(PerlIO_printf(Perl_debug_log,
|
|
"0x%"UVxf" 2nv(%" PERL_PRIgldbl ")\n",
|
|
PTR2UV(sv), SvNVX(sv)));
|
|
#else
|
|
DEBUG_c(PerlIO_printf(Perl_debug_log,
|
|
"0x%"UVxf" 2nv(%g)\n",
|
|
PTR2UV(sv), SvNVX(sv)));
|
|
#endif
|
|
if (SvNVX(sv) < -0.5) {
|
|
SvIVX(sv) = I_V(SvNVX(sv));
|
|
goto ret_zero;
|
|
} else {
|
|
SvUVX(sv) = U_V(SvNVX(sv));
|
|
SvIsUV_on(sv);
|
|
}
|
|
}
|
|
else if (numtype & IS_NUMBER_NEG) {
|
|
/* The NV may be reconstructed from IV - safe to cache IV,
|
|
which may be calculated by atol(). */
|
|
if (SvTYPE(sv) == SVt_PV)
|
|
sv_upgrade(sv, SVt_PVIV);
|
|
(void)SvIOK_on(sv);
|
|
SvIVX(sv) = (IV)Atol(SvPVX(sv));
|
|
}
|
|
else if (numtype) { /* Non-negative */
|
|
/* The NV may be reconstructed from UV - safe to cache UV,
|
|
which may be calculated by strtoul()/atol. */
|
|
if (SvTYPE(sv) == SVt_PV)
|
|
sv_upgrade(sv, SVt_PVIV);
|
|
(void)SvIOK_on(sv);
|
|
(void)SvIsUV_on(sv);
|
|
#ifdef HAS_STRTOUL
|
|
SvUVX(sv) = Strtoul(SvPVX(sv), Null(char**), 10);
|
|
#else /* no atou(), but we know the number fits into IV... */
|
|
/* The only problem may be if it is negative... */
|
|
SvUVX(sv) = (UV)Atol(SvPVX(sv));
|
|
#endif
|
|
}
|
|
else { /* Not a number. Cache 0. */
|
|
if (SvTYPE(sv) < SVt_PVIV)
|
|
sv_upgrade(sv, SVt_PVIV);
|
|
(void)SvIOK_on(sv);
|
|
(void)SvIsUV_on(sv);
|
|
SvUVX(sv) = 0; /* We assume that 0s have the
|
|
same bitmap in IV and UV. */
|
|
if (ckWARN(WARN_NUMERIC))
|
|
not_a_number(sv);
|
|
}
|
|
}
|
|
else {
|
|
if (!(SvFLAGS(sv) & SVs_PADTMP)) {
|
|
if (ckWARN(WARN_UNINITIALIZED) && !PL_localizing)
|
|
report_uninit();
|
|
}
|
|
if (SvTYPE(sv) < SVt_IV)
|
|
/* Typically the caller expects that sv_any is not NULL now. */
|
|
sv_upgrade(sv, SVt_IV);
|
|
return 0;
|
|
}
|
|
|
|
DEBUG_c(PerlIO_printf(Perl_debug_log, "0x%"UVxf" 2uv(%"UVuf")\n",
|
|
PTR2UV(sv),SvUVX(sv)));
|
|
return SvIsUV(sv) ? SvUVX(sv) : (UV)SvIVX(sv);
|
|
}
|
|
|
|
NV
|
|
Perl_sv_2nv(pTHX_ register SV *sv)
|
|
{
|
|
if (!sv)
|
|
return 0.0;
|
|
if (SvGMAGICAL(sv)) {
|
|
mg_get(sv);
|
|
if (SvNOKp(sv))
|
|
return SvNVX(sv);
|
|
if (SvPOKp(sv) && SvLEN(sv)) {
|
|
if (ckWARN(WARN_NUMERIC) && !SvIOKp(sv) && !looks_like_number(sv))
|
|
not_a_number(sv);
|
|
return Atof(SvPVX(sv));
|
|
}
|
|
if (SvIOKp(sv)) {
|
|
if (SvIsUV(sv))
|
|
return (NV)SvUVX(sv);
|
|
else
|
|
return (NV)SvIVX(sv);
|
|
}
|
|
if (!SvROK(sv)) {
|
|
if (!(SvFLAGS(sv) & SVs_PADTMP)) {
|
|
if (ckWARN(WARN_UNINITIALIZED) && !PL_localizing)
|
|
report_uninit();
|
|
}
|
|
return 0;
|
|
}
|
|
}
|
|
if (SvTHINKFIRST(sv)) {
|
|
if (SvROK(sv)) {
|
|
SV* tmpstr;
|
|
if (SvAMAGIC(sv) && (tmpstr=AMG_CALLun(sv,numer)) &&
|
|
(SvRV(tmpstr) != SvRV(sv)))
|
|
return SvNV(tmpstr);
|
|
return PTR2NV(SvRV(sv));
|
|
}
|
|
if (SvREADONLY(sv) && !SvOK(sv)) {
|
|
if (ckWARN(WARN_UNINITIALIZED))
|
|
report_uninit();
|
|
return 0.0;
|
|
}
|
|
}
|
|
if (SvTYPE(sv) < SVt_NV) {
|
|
if (SvTYPE(sv) == SVt_IV)
|
|
sv_upgrade(sv, SVt_PVNV);
|
|
else
|
|
sv_upgrade(sv, SVt_NV);
|
|
#if defined(USE_LONG_DOUBLE)
|
|
DEBUG_c({
|
|
STORE_NUMERIC_LOCAL_SET_STANDARD();
|
|
PerlIO_printf(Perl_debug_log,
|
|
"0x%"UVxf" num(%" PERL_PRIgldbl ")\n",
|
|
PTR2UV(sv), SvNVX(sv));
|
|
RESTORE_NUMERIC_LOCAL();
|
|
});
|
|
#else
|
|
DEBUG_c({
|
|
STORE_NUMERIC_LOCAL_SET_STANDARD();
|
|
PerlIO_printf(Perl_debug_log, "0x%"UVxf" num(%g)\n",
|
|
PTR2UV(sv), SvNVX(sv));
|
|
RESTORE_NUMERIC_LOCAL();
|
|
});
|
|
#endif
|
|
}
|
|
else if (SvTYPE(sv) < SVt_PVNV)
|
|
sv_upgrade(sv, SVt_PVNV);
|
|
if (SvIOKp(sv) &&
|
|
(!SvPOKp(sv) || !strchr(SvPVX(sv),'.') || !looks_like_number(sv)))
|
|
{
|
|
SvNVX(sv) = SvIsUV(sv) ? (NV)SvUVX(sv) : (NV)SvIVX(sv);
|
|
}
|
|
else if (SvPOKp(sv) && SvLEN(sv)) {
|
|
if (ckWARN(WARN_NUMERIC) && !SvIOKp(sv) && !looks_like_number(sv))
|
|
not_a_number(sv);
|
|
SvNVX(sv) = Atof(SvPVX(sv));
|
|
}
|
|
else {
|
|
if (ckWARN(WARN_UNINITIALIZED) && !PL_localizing && !(SvFLAGS(sv) & SVs_PADTMP))
|
|
report_uninit();
|
|
if (SvTYPE(sv) < SVt_NV)
|
|
/* Typically the caller expects that sv_any is not NULL now. */
|
|
sv_upgrade(sv, SVt_NV);
|
|
return 0.0;
|
|
}
|
|
SvNOK_on(sv);
|
|
#if defined(USE_LONG_DOUBLE)
|
|
DEBUG_c({
|
|
STORE_NUMERIC_LOCAL_SET_STANDARD();
|
|
PerlIO_printf(Perl_debug_log, "0x%"UVxf" 2nv(%" PERL_PRIgldbl ")\n",
|
|
PTR2UV(sv), SvNVX(sv));
|
|
RESTORE_NUMERIC_LOCAL();
|
|
});
|
|
#else
|
|
DEBUG_c({
|
|
STORE_NUMERIC_LOCAL_SET_STANDARD();
|
|
PerlIO_printf(Perl_debug_log, "0x%"UVxf" 1nv(%g)\n",
|
|
PTR2UV(sv), SvNVX(sv));
|
|
RESTORE_NUMERIC_LOCAL();
|
|
});
|
|
#endif
|
|
return SvNVX(sv);
|
|
}
|
|
|
|
STATIC IV
|
|
S_asIV(pTHX_ SV *sv)
|
|
{
|
|
I32 numtype = looks_like_number(sv);
|
|
NV d;
|
|
|
|
if (numtype & IS_NUMBER_TO_INT_BY_ATOL)
|
|
return Atol(SvPVX(sv));
|
|
if (!numtype) {
|
|
if (ckWARN(WARN_NUMERIC))
|
|
not_a_number(sv);
|
|
}
|
|
d = Atof(SvPVX(sv));
|
|
return I_V(d);
|
|
}
|
|
|
|
STATIC UV
|
|
S_asUV(pTHX_ SV *sv)
|
|
{
|
|
I32 numtype = looks_like_number(sv);
|
|
|
|
#ifdef HAS_STRTOUL
|
|
if (numtype & IS_NUMBER_TO_INT_BY_ATOL)
|
|
return Strtoul(SvPVX(sv), Null(char**), 10);
|
|
#endif
|
|
if (!numtype) {
|
|
if (ckWARN(WARN_NUMERIC))
|
|
not_a_number(sv);
|
|
}
|
|
return U_V(Atof(SvPVX(sv)));
|
|
}
|
|
|
|
/*
|
|
* Returns a combination of (advisory only - can get false negatives)
|
|
* IS_NUMBER_TO_INT_BY_ATOL, IS_NUMBER_TO_INT_BY_ATOF, IS_NUMBER_NOT_IV,
|
|
* IS_NUMBER_NEG
|
|
* 0 if does not look like number.
|
|
*
|
|
* In fact possible values are 0 and
|
|
* IS_NUMBER_TO_INT_BY_ATOL 123
|
|
* IS_NUMBER_TO_INT_BY_ATOL | IS_NUMBER_NOT_IV 123.1
|
|
* IS_NUMBER_TO_INT_BY_ATOF | IS_NUMBER_NOT_IV 123e0
|
|
* IS_NUMBER_INFINITY
|
|
* with a possible addition of IS_NUMBER_NEG.
|
|
*/
|
|
|
|
/*
|
|
=for apidoc looks_like_number
|
|
|
|
Test if an the content of an SV looks like a number (or is a
|
|
number).
|
|
|
|
=cut
|
|
*/
|
|
|
|
I32
|
|
Perl_looks_like_number(pTHX_ SV *sv)
|
|
{
|
|
register char *s;
|
|
register char *send;
|
|
register char *sbegin;
|
|
register char *nbegin;
|
|
I32 numtype = 0;
|
|
I32 sawinf = 0;
|
|
STRLEN len;
|
|
#ifdef USE_LOCALE_NUMERIC
|
|
bool specialradix = FALSE;
|
|
#endif
|
|
|
|
if (SvPOK(sv)) {
|
|
sbegin = SvPVX(sv);
|
|
len = SvCUR(sv);
|
|
}
|
|
else if (SvPOKp(sv))
|
|
sbegin = SvPV(sv, len);
|
|
else
|
|
return 1;
|
|
send = sbegin + len;
|
|
|
|
s = sbegin;
|
|
while (isSPACE(*s))
|
|
s++;
|
|
if (*s == '-') {
|
|
s++;
|
|
numtype = IS_NUMBER_NEG;
|
|
}
|
|
else if (*s == '+')
|
|
s++;
|
|
|
|
nbegin = s;
|
|
/*
|
|
* we return IS_NUMBER_TO_INT_BY_ATOL if the number can be converted
|
|
* to _integer_ with atol() and IS_NUMBER_TO_INT_BY_ATOF if you need
|
|
* (int)atof().
|
|
*/
|
|
|
|
/* next must be digit or the radix separator or beginning of infinity */
|
|
if (isDIGIT(*s)) {
|
|
do {
|
|
s++;
|
|
} while (isDIGIT(*s));
|
|
|
|
if (s - nbegin >= TYPE_DIGITS(IV)) /* Cannot cache ato[ul]() */
|
|
numtype |= IS_NUMBER_TO_INT_BY_ATOF | IS_NUMBER_NOT_IV;
|
|
else
|
|
numtype |= IS_NUMBER_TO_INT_BY_ATOL;
|
|
|
|
if (*s == '.'
|
|
#ifdef USE_LOCALE_NUMERIC
|
|
|| (specialradix = IS_NUMERIC_RADIX(s))
|
|
#endif
|
|
) {
|
|
#ifdef USE_LOCALE_NUMERIC
|
|
if (specialradix)
|
|
s += SvCUR(PL_numeric_radix_sv);
|
|
else
|
|
#endif
|
|
s++;
|
|
numtype |= IS_NUMBER_NOT_IV;
|
|
while (isDIGIT(*s)) /* optional digits after the radix */
|
|
s++;
|
|
}
|
|
}
|
|
else if (*s == '.'
|
|
#ifdef USE_LOCALE_NUMERIC
|
|
|| (specialradix = IS_NUMERIC_RADIX(s))
|
|
#endif
|
|
) {
|
|
#ifdef USE_LOCALE_NUMERIC
|
|
if (specialradix)
|
|
s += SvCUR(PL_numeric_radix_sv);
|
|
else
|
|
#endif
|
|
s++;
|
|
numtype |= IS_NUMBER_TO_INT_BY_ATOL | IS_NUMBER_NOT_IV;
|
|
/* no digits before the radix means we need digits after it */
|
|
if (isDIGIT(*s)) {
|
|
do {
|
|
s++;
|
|
} while (isDIGIT(*s));
|
|
}
|
|
else
|
|
return 0;
|
|
}
|
|
else if (*s == 'I' || *s == 'i') {
|
|
s++; if (*s != 'N' && *s != 'n') return 0;
|
|
s++; if (*s != 'F' && *s != 'f') return 0;
|
|
s++; if (*s == 'I' || *s == 'i') {
|
|
s++; if (*s != 'N' && *s != 'n') return 0;
|
|
s++; if (*s != 'I' && *s != 'i') return 0;
|
|
s++; if (*s != 'T' && *s != 't') return 0;
|
|
s++; if (*s != 'Y' && *s != 'y') return 0;
|
|
}
|
|
sawinf = 1;
|
|
}
|
|
else
|
|
return 0;
|
|
|
|
if (sawinf)
|
|
numtype = IS_NUMBER_INFINITY;
|
|
else {
|
|
/* we can have an optional exponent part */
|
|
if (*s == 'e' || *s == 'E') {
|
|
numtype &= ~IS_NUMBER_NEG;
|
|
numtype |= IS_NUMBER_TO_INT_BY_ATOF | IS_NUMBER_NOT_IV;
|
|
s++;
|
|
if (*s == '+' || *s == '-')
|
|
s++;
|
|
if (isDIGIT(*s)) {
|
|
do {
|
|
s++;
|
|
} while (isDIGIT(*s));
|
|
}
|
|
else
|
|
return 0;
|
|
}
|
|
}
|
|
while (isSPACE(*s))
|
|
s++;
|
|
if (s >= send)
|
|
return numtype;
|
|
if (len == 10 && memEQ(sbegin, "0 but true", 10))
|
|
return IS_NUMBER_TO_INT_BY_ATOL;
|
|
return 0;
|
|
}
|
|
|
|
char *
|
|
Perl_sv_2pv_nolen(pTHX_ register SV *sv)
|
|
{
|
|
STRLEN n_a;
|
|
return sv_2pv(sv, &n_a);
|
|
}
|
|
|
|
/* We assume that buf is at least TYPE_CHARS(UV) long. */
|
|
static char *
|
|
uiv_2buf(char *buf, IV iv, UV uv, int is_uv, char **peob)
|
|
{
|
|
char *ptr = buf + TYPE_CHARS(UV);
|
|
char *ebuf = ptr;
|
|
int sign;
|
|
|
|
if (is_uv)
|
|
sign = 0;
|
|
else if (iv >= 0) {
|
|
uv = iv;
|
|
sign = 0;
|
|
} else {
|
|
uv = -iv;
|
|
sign = 1;
|
|
}
|
|
do {
|
|
*--ptr = '0' + (uv % 10);
|
|
} while (uv /= 10);
|
|
if (sign)
|
|
*--ptr = '-';
|
|
*peob = ebuf;
|
|
return ptr;
|
|
}
|
|
|
|
char *
|
|
Perl_sv_2pv(pTHX_ register SV *sv, STRLEN *lp)
|
|
{
|
|
register char *s;
|
|
int olderrno;
|
|
SV *tsv;
|
|
char tbuf[64]; /* Must fit sprintf/Gconvert of longest IV/NV */
|
|
char *tmpbuf = tbuf;
|
|
|
|
if (!sv) {
|
|
*lp = 0;
|
|
return "";
|
|
}
|
|
if (SvGMAGICAL(sv)) {
|
|
mg_get(sv);
|
|
if (SvPOKp(sv)) {
|
|
*lp = SvCUR(sv);
|
|
return SvPVX(sv);
|
|
}
|
|
if (SvIOKp(sv)) {
|
|
if (SvIsUV(sv))
|
|
(void)sprintf(tmpbuf,"%"UVuf, (UV)SvUVX(sv));
|
|
else
|
|
(void)sprintf(tmpbuf,"%"IVdf, (IV)SvIVX(sv));
|
|
tsv = Nullsv;
|
|
goto tokensave;
|
|
}
|
|
if (SvNOKp(sv)) {
|
|
Gconvert(SvNVX(sv), NV_DIG, 0, tmpbuf);
|
|
tsv = Nullsv;
|
|
goto tokensave;
|
|
}
|
|
if (!SvROK(sv)) {
|
|
if (!(SvFLAGS(sv) & SVs_PADTMP)) {
|
|
if (ckWARN(WARN_UNINITIALIZED) && !PL_localizing)
|
|
report_uninit();
|
|
}
|
|
*lp = 0;
|
|
return "";
|
|
}
|
|
}
|
|
if (SvTHINKFIRST(sv)) {
|
|
if (SvROK(sv)) {
|
|
SV* tmpstr;
|
|
if (SvAMAGIC(sv) && (tmpstr=AMG_CALLun(sv,string)) &&
|
|
(SvRV(tmpstr) != SvRV(sv)))
|
|
return SvPV(tmpstr,*lp);
|
|
sv = (SV*)SvRV(sv);
|
|
if (!sv)
|
|
s = "NULLREF";
|
|
else {
|
|
MAGIC *mg;
|
|
|
|
switch (SvTYPE(sv)) {
|
|
case SVt_PVMG:
|
|
if ( ((SvFLAGS(sv) &
|
|
(SVs_OBJECT|SVf_OK|SVs_GMG|SVs_SMG|SVs_RMG))
|
|
== (SVs_OBJECT|SVs_RMG))
|
|
&& strEQ(s=HvNAME(SvSTASH(sv)), "Regexp")
|
|
&& (mg = mg_find(sv, 'r'))) {
|
|
regexp *re = (regexp *)mg->mg_obj;
|
|
|
|
if (!mg->mg_ptr) {
|
|
char *fptr = "msix";
|
|
char reflags[6];
|
|
char ch;
|
|
int left = 0;
|
|
int right = 4;
|
|
U16 reganch = (re->reganch & PMf_COMPILETIME) >> 12;
|
|
|
|
while((ch = *fptr++)) {
|
|
if(reganch & 1) {
|
|
reflags[left++] = ch;
|
|
}
|
|
else {
|
|
reflags[right--] = ch;
|
|
}
|
|
reganch >>= 1;
|
|
}
|
|
if(left != 4) {
|
|
reflags[left] = '-';
|
|
left = 5;
|
|
}
|
|
|
|
mg->mg_len = re->prelen + 4 + left;
|
|
New(616, mg->mg_ptr, mg->mg_len + 1 + left, char);
|
|
Copy("(?", mg->mg_ptr, 2, char);
|
|
Copy(reflags, mg->mg_ptr+2, left, char);
|
|
Copy(":", mg->mg_ptr+left+2, 1, char);
|
|
Copy(re->precomp, mg->mg_ptr+3+left, re->prelen, char);
|
|
mg->mg_ptr[mg->mg_len - 1] = ')';
|
|
mg->mg_ptr[mg->mg_len] = 0;
|
|
}
|
|
PL_reginterp_cnt += re->program[0].next_off;
|
|
*lp = mg->mg_len;
|
|
return mg->mg_ptr;
|
|
}
|
|
/* Fall through */
|
|
case SVt_NULL:
|
|
case SVt_IV:
|
|
case SVt_NV:
|
|
case SVt_RV:
|
|
case SVt_PV:
|
|
case SVt_PVIV:
|
|
case SVt_PVNV:
|
|
case SVt_PVBM: s = "SCALAR"; break;
|
|
case SVt_PVLV: s = "LVALUE"; break;
|
|
case SVt_PVAV: s = "ARRAY"; break;
|
|
case SVt_PVHV: s = "HASH"; break;
|
|
case SVt_PVCV: s = "CODE"; break;
|
|
case SVt_PVGV: s = "GLOB"; break;
|
|
case SVt_PVFM: s = "FORMAT"; break;
|
|
case SVt_PVIO: s = "IO"; break;
|
|
default: s = "UNKNOWN"; break;
|
|
}
|
|
tsv = NEWSV(0,0);
|
|
if (SvOBJECT(sv))
|
|
Perl_sv_setpvf(aTHX_ tsv, "%s=%s", HvNAME(SvSTASH(sv)), s);
|
|
else
|
|
sv_setpv(tsv, s);
|
|
Perl_sv_catpvf(aTHX_ tsv, "(0x%"UVxf")", PTR2UV(sv));
|
|
goto tokensaveref;
|
|
}
|
|
*lp = strlen(s);
|
|
return s;
|
|
}
|
|
if (SvREADONLY(sv) && !SvOK(sv)) {
|
|
if (ckWARN(WARN_UNINITIALIZED))
|
|
report_uninit();
|
|
*lp = 0;
|
|
return "";
|
|
}
|
|
}
|
|
if (SvNOKp(sv)) { /* See note in sv_2uv() */
|
|
/* XXXX 64-bit? IV may have better precision... */
|
|
/* I tried changing this to be 64-bit-aware and
|
|
* the t/op/numconvert.t became very, very, angry.
|
|
* --jhi Sep 1999 */
|
|
if (SvTYPE(sv) < SVt_PVNV)
|
|
sv_upgrade(sv, SVt_PVNV);
|
|
/* The +20 is pure guesswork. Configure test needed. --jhi */
|
|
SvGROW(sv, NV_DIG + 20);
|
|
s = SvPVX(sv);
|
|
olderrno = errno; /* some Xenix systems wipe out errno here */
|
|
#ifdef apollo
|
|
if (SvNVX(sv) == 0.0)
|
|
(void)strcpy(s,"0");
|
|
else
|
|
#endif /*apollo*/
|
|
{
|
|
Gconvert(SvNVX(sv), NV_DIG, 0, s);
|
|
}
|
|
errno = olderrno;
|
|
#ifdef FIXNEGATIVEZERO
|
|
if (*s == '-' && s[1] == '0' && !s[2])
|
|
strcpy(s,"0");
|
|
#endif
|
|
while (*s) s++;
|
|
#ifdef hcx
|
|
if (s[-1] == '.')
|
|
*--s = '\0';
|
|
#endif
|
|
}
|
|
else if (SvIOKp(sv)) {
|
|
U32 isIOK = SvIOK(sv);
|
|
U32 isUIOK = SvIsUV(sv);
|
|
char buf[TYPE_CHARS(UV)];
|
|
char *ebuf, *ptr;
|
|
|
|
if (SvTYPE(sv) < SVt_PVIV)
|
|
sv_upgrade(sv, SVt_PVIV);
|
|
if (isUIOK)
|
|
ptr = uiv_2buf(buf, 0, SvUVX(sv), 1, &ebuf);
|
|
else
|
|
ptr = uiv_2buf(buf, SvIVX(sv), 0, 0, &ebuf);
|
|
SvGROW(sv, ebuf - ptr + 1); /* inlined from sv_setpvn */
|
|
Move(ptr,SvPVX(sv),ebuf - ptr,char);
|
|
SvCUR_set(sv, ebuf - ptr);
|
|
s = SvEND(sv);
|
|
*s = '\0';
|
|
if (isIOK)
|
|
SvIOK_on(sv);
|
|
else
|
|
SvIOKp_on(sv);
|
|
if (isUIOK)
|
|
SvIsUV_on(sv);
|
|
SvPOK_on(sv);
|
|
}
|
|
else {
|
|
if (ckWARN(WARN_UNINITIALIZED)
|
|
&& !PL_localizing && !(SvFLAGS(sv) & SVs_PADTMP))
|
|
report_uninit();
|
|
*lp = 0;
|
|
if (SvTYPE(sv) < SVt_PV)
|
|
/* Typically the caller expects that sv_any is not NULL now. */
|
|
sv_upgrade(sv, SVt_PV);
|
|
return "";
|
|
}
|
|
*lp = s - SvPVX(sv);
|
|
SvCUR_set(sv, *lp);
|
|
SvPOK_on(sv);
|
|
DEBUG_c(PerlIO_printf(Perl_debug_log, "0x%"UVxf" 2pv(%s)\n",
|
|
PTR2UV(sv),SvPVX(sv)));
|
|
return SvPVX(sv);
|
|
|
|
tokensave:
|
|
if (SvROK(sv)) { /* XXX Skip this when sv_pvn_force calls */
|
|
/* Sneaky stuff here */
|
|
|
|
tokensaveref:
|
|
if (!tsv)
|
|
tsv = newSVpv(tmpbuf, 0);
|
|
sv_2mortal(tsv);
|
|
*lp = SvCUR(tsv);
|
|
return SvPVX(tsv);
|
|
}
|
|
else {
|
|
STRLEN len;
|
|
char *t;
|
|
|
|
if (tsv) {
|
|
sv_2mortal(tsv);
|
|
t = SvPVX(tsv);
|
|
len = SvCUR(tsv);
|
|
}
|
|
else {
|
|
t = tmpbuf;
|
|
len = strlen(tmpbuf);
|
|
}
|
|
#ifdef FIXNEGATIVEZERO
|
|
if (len == 2 && t[0] == '-' && t[1] == '0') {
|
|
t = "0";
|
|
len = 1;
|
|
}
|
|
#endif
|
|
(void)SvUPGRADE(sv, SVt_PV);
|
|
*lp = len;
|
|
s = SvGROW(sv, len + 1);
|
|
SvCUR_set(sv, len);
|
|
(void)strcpy(s, t);
|
|
SvPOKp_on(sv);
|
|
return s;
|
|
}
|
|
}
|
|
|
|
char *
|
|
Perl_sv_2pvbyte_nolen(pTHX_ register SV *sv)
|
|
{
|
|
STRLEN n_a;
|
|
return sv_2pvbyte(sv, &n_a);
|
|
}
|
|
|
|
char *
|
|
Perl_sv_2pvbyte(pTHX_ register SV *sv, STRLEN *lp)
|
|
{
|
|
return sv_2pv(sv,lp);
|
|
}
|
|
|
|
char *
|
|
Perl_sv_2pvutf8_nolen(pTHX_ register SV *sv)
|
|
{
|
|
STRLEN n_a;
|
|
return sv_2pvutf8(sv, &n_a);
|
|
}
|
|
|
|
char *
|
|
Perl_sv_2pvutf8(pTHX_ register SV *sv, STRLEN *lp)
|
|
{
|
|
sv_utf8_upgrade(sv);
|
|
return SvPV(sv,*lp);
|
|
}
|
|
|
|
/* This function is only called on magical items */
|
|
bool
|
|
Perl_sv_2bool(pTHX_ register SV *sv)
|
|
{
|
|
if (SvGMAGICAL(sv))
|
|
mg_get(sv);
|
|
|
|
if (!SvOK(sv))
|
|
return 0;
|
|
if (SvROK(sv)) {
|
|
SV* tmpsv;
|
|
if (SvAMAGIC(sv) && (tmpsv=AMG_CALLun(sv,bool_)) &&
|
|
(SvRV(tmpsv) != SvRV(sv)))
|
|
return SvTRUE(tmpsv);
|
|
return SvRV(sv) != 0;
|
|
}
|
|
if (SvPOKp(sv)) {
|
|
register XPV* Xpvtmp;
|
|
if ((Xpvtmp = (XPV*)SvANY(sv)) &&
|
|
(*Xpvtmp->xpv_pv > '0' ||
|
|
Xpvtmp->xpv_cur > 1 ||
|
|
(Xpvtmp->xpv_cur && *Xpvtmp->xpv_pv != '0')))
|
|
return 1;
|
|
else
|
|
return 0;
|
|
}
|
|
else {
|
|
if (SvIOKp(sv))
|
|
return SvIVX(sv) != 0;
|
|
else {
|
|
if (SvNOKp(sv))
|
|
return SvNVX(sv) != 0.0;
|
|
else
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
=for apidoc sv_utf8_upgrade
|
|
|
|
Convert the PV of an SV to its UTF8-encoded form.
|
|
|
|
=cut
|
|
*/
|
|
|
|
void
|
|
Perl_sv_utf8_upgrade(pTHX_ register SV *sv)
|
|
{
|
|
char *s, *t, *e;
|
|
int hibit = 0;
|
|
|
|
if (!sv || !SvPOK(sv) || SvUTF8(sv))
|
|
return;
|
|
|
|
/* This function could be much more efficient if we had a FLAG in SVs
|
|
* to signal if there are any hibit chars in the PV.
|
|
* Given that there isn't make loop fast as possible
|
|
*/
|
|
s = SvPVX(sv);
|
|
e = SvEND(sv);
|
|
t = s;
|
|
while (t < e) {
|
|
if ((hibit = UTF8_IS_CONTINUED(*t++)))
|
|
break;
|
|
}
|
|
|
|
if (hibit) {
|
|
STRLEN len;
|
|
|
|
if (SvREADONLY(sv) && SvFAKE(sv)) {
|
|
sv_force_normal(sv);
|
|
s = SvPVX(sv);
|
|
}
|
|
len = SvCUR(sv) + 1; /* Plus the \0 */
|
|
SvPVX(sv) = (char*)bytes_to_utf8((U8*)s, &len);
|
|
SvCUR(sv) = len - 1;
|
|
if (SvLEN(sv) != 0)
|
|
Safefree(s); /* No longer using what was there before. */
|
|
SvLEN(sv) = len; /* No longer know the real size. */
|
|
SvUTF8_on(sv);
|
|
}
|
|
}
|
|
|
|
/*
|
|
=for apidoc sv_utf8_downgrade
|
|
|
|
Attempt to convert the PV of an SV from UTF8-encoded to byte encoding.
|
|
This may not be possible if the PV contains non-byte encoding characters;
|
|
if this is the case, either returns false or, if C<fail_ok> is not
|
|
true, croaks.
|
|
|
|
=cut
|
|
*/
|
|
|
|
bool
|
|
Perl_sv_utf8_downgrade(pTHX_ register SV* sv, bool fail_ok)
|
|
{
|
|
if (SvPOK(sv) && SvUTF8(sv)) {
|
|
if (SvCUR(sv)) {
|
|
char *s;
|
|
STRLEN len;
|
|
|
|
if (SvREADONLY(sv) && SvFAKE(sv))
|
|
sv_force_normal(sv);
|
|
s = SvPV(sv, len);
|
|
if (!utf8_to_bytes((U8*)s, &len)) {
|
|
if (fail_ok)
|
|
return FALSE;
|
|
else {
|
|
if (PL_op)
|
|
Perl_croak(aTHX_ "Wide character in %s",
|
|
PL_op_desc[PL_op->op_type]);
|
|
else
|
|
Perl_croak(aTHX_ "Wide character");
|
|
}
|
|
}
|
|
SvCUR(sv) = len;
|
|
}
|
|
SvUTF8_off(sv);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
=for apidoc sv_utf8_encode
|
|
|
|
Convert the PV of an SV to UTF8-encoded, but then turn off the C<SvUTF8>
|
|
flag so that it looks like bytes again. Nothing calls this.
|
|
|
|
=cut
|
|
*/
|
|
|
|
void
|
|
Perl_sv_utf8_encode(pTHX_ register SV *sv)
|
|
{
|
|
sv_utf8_upgrade(sv);
|
|
SvUTF8_off(sv);
|
|
}
|
|
|
|
bool
|
|
Perl_sv_utf8_decode(pTHX_ register SV *sv)
|
|
{
|
|
if (SvPOK(sv)) {
|
|
char *c;
|
|
char *e;
|
|
bool has_utf = FALSE;
|
|
if (!sv_utf8_downgrade(sv, TRUE))
|
|
return FALSE;
|
|
|
|
/* it is actually just a matter of turning the utf8 flag on, but
|
|
* we want to make sure everything inside is valid utf8 first.
|
|
*/
|
|
c = SvPVX(sv);
|
|
if (!is_utf8_string((U8*)c, SvCUR(sv)+1))
|
|
return FALSE;
|
|
e = SvEND(sv);
|
|
while (c < e) {
|
|
if (UTF8_IS_CONTINUED(*c++)) {
|
|
SvUTF8_on(sv);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/* Note: sv_setsv() should not be called with a source string that needs
|
|
* to be reused, since it may destroy the source string if it is marked
|
|
* as temporary.
|
|
*/
|
|
|
|
/*
|
|
=for apidoc sv_setsv
|
|
|
|
Copies the contents of the source SV C<ssv> into the destination SV C<dsv>.
|
|
The source SV may be destroyed if it is mortal. Does not handle 'set'
|
|
magic. See the macro forms C<SvSetSV>, C<SvSetSV_nosteal> and
|
|
C<sv_setsv_mg>.
|
|
|
|
=cut
|
|
*/
|
|
|
|
void
|
|
Perl_sv_setsv(pTHX_ SV *dstr, register SV *sstr)
|
|
{
|
|
register U32 sflags;
|
|
register int dtype;
|
|
register int stype;
|
|
|
|
if (sstr == dstr)
|
|
return;
|
|
SV_CHECK_THINKFIRST(dstr);
|
|
if (!sstr)
|
|
sstr = &PL_sv_undef;
|
|
stype = SvTYPE(sstr);
|
|
dtype = SvTYPE(dstr);
|
|
|
|
SvAMAGIC_off(dstr);
|
|
|
|
/* There's a lot of redundancy below but we're going for speed here */
|
|
|
|
switch (stype) {
|
|
case SVt_NULL:
|
|
undef_sstr:
|
|
if (dtype != SVt_PVGV) {
|
|
(void)SvOK_off(dstr);
|
|
return;
|
|
}
|
|
break;
|
|
case SVt_IV:
|
|
if (SvIOK(sstr)) {
|
|
switch (dtype) {
|
|
case SVt_NULL:
|
|
sv_upgrade(dstr, SVt_IV);
|
|
break;
|
|
case SVt_NV:
|
|
sv_upgrade(dstr, SVt_PVNV);
|
|
break;
|
|
case SVt_RV:
|
|
case SVt_PV:
|
|
sv_upgrade(dstr, SVt_PVIV);
|
|
break;
|
|
}
|
|
(void)SvIOK_only(dstr);
|
|
SvIVX(dstr) = SvIVX(sstr);
|
|
if (SvIsUV(sstr))
|
|
SvIsUV_on(dstr);
|
|
if (SvTAINTED(sstr))
|
|
SvTAINT(dstr);
|
|
return;
|
|
}
|
|
goto undef_sstr;
|
|
|
|
case SVt_NV:
|
|
if (SvNOK(sstr)) {
|
|
switch (dtype) {
|
|
case SVt_NULL:
|
|
case SVt_IV:
|
|
sv_upgrade(dstr, SVt_NV);
|
|
break;
|
|
case SVt_RV:
|
|
case SVt_PV:
|
|
case SVt_PVIV:
|
|
sv_upgrade(dstr, SVt_PVNV);
|
|
break;
|
|
}
|
|
SvNVX(dstr) = SvNVX(sstr);
|
|
(void)SvNOK_only(dstr);
|
|
if (SvTAINTED(sstr))
|
|
SvTAINT(dstr);
|
|
return;
|
|
}
|
|
goto undef_sstr;
|
|
|
|
case SVt_RV:
|
|
if (dtype < SVt_RV)
|
|
sv_upgrade(dstr, SVt_RV);
|
|
else if (dtype == SVt_PVGV &&
|
|
SvTYPE(SvRV(sstr)) == SVt_PVGV) {
|
|
sstr = SvRV(sstr);
|
|
if (sstr == dstr) {
|
|
if (GvIMPORTED(dstr) != GVf_IMPORTED
|
|
&& CopSTASH_ne(PL_curcop, GvSTASH(dstr)))
|
|
{
|
|
GvIMPORTED_on(dstr);
|
|
}
|
|
GvMULTI_on(dstr);
|
|
return;
|
|
}
|
|
goto glob_assign;
|
|
}
|
|
break;
|
|
case SVt_PV:
|
|
case SVt_PVFM:
|
|
if (dtype < SVt_PV)
|
|
sv_upgrade(dstr, SVt_PV);
|
|
break;
|
|
case SVt_PVIV:
|
|
if (dtype < SVt_PVIV)
|
|
sv_upgrade(dstr, SVt_PVIV);
|
|
break;
|
|
case SVt_PVNV:
|
|
if (dtype < SVt_PVNV)
|
|
sv_upgrade(dstr, SVt_PVNV);
|
|
break;
|
|
case SVt_PVAV:
|
|
case SVt_PVHV:
|
|
case SVt_PVCV:
|
|
case SVt_PVIO:
|
|
if (PL_op)
|
|
Perl_croak(aTHX_ "Bizarre copy of %s in %s", sv_reftype(sstr, 0),
|
|
PL_op_name[PL_op->op_type]);
|
|
else
|
|
Perl_croak(aTHX_ "Bizarre copy of %s", sv_reftype(sstr, 0));
|
|
break;
|
|
|
|
case SVt_PVGV:
|
|
if (dtype <= SVt_PVGV) {
|
|
glob_assign:
|
|
if (dtype != SVt_PVGV) {
|
|
char *name = GvNAME(sstr);
|
|
STRLEN len = GvNAMELEN(sstr);
|
|
sv_upgrade(dstr, SVt_PVGV);
|
|
sv_magic(dstr, dstr, '*', Nullch, 0);
|
|
GvSTASH(dstr) = (HV*)SvREFCNT_inc(GvSTASH(sstr));
|
|
GvNAME(dstr) = savepvn(name, len);
|
|
GvNAMELEN(dstr) = len;
|
|
SvFAKE_on(dstr); /* can coerce to non-glob */
|
|
}
|
|
/* ahem, death to those who redefine active sort subs */
|
|
else if (PL_curstackinfo->si_type == PERLSI_SORT
|
|
&& GvCV(dstr) && PL_sortcop == CvSTART(GvCV(dstr)))
|
|
Perl_croak(aTHX_ "Can't redefine active sort subroutine %s",
|
|
GvNAME(dstr));
|
|
(void)SvOK_off(dstr);
|
|
GvINTRO_off(dstr); /* one-shot flag */
|
|
gp_free((GV*)dstr);
|
|
GvGP(dstr) = gp_ref(GvGP(sstr));
|
|
if (SvTAINTED(sstr))
|
|
SvTAINT(dstr);
|
|
if (GvIMPORTED(dstr) != GVf_IMPORTED
|
|
&& CopSTASH_ne(PL_curcop, GvSTASH(dstr)))
|
|
{
|
|
GvIMPORTED_on(dstr);
|
|
}
|
|
GvMULTI_on(dstr);
|
|
return;
|
|
}
|
|
/* FALL THROUGH */
|
|
|
|
default:
|
|
if (SvGMAGICAL(sstr)) {
|
|
mg_get(sstr);
|
|
if (SvTYPE(sstr) != stype) {
|
|
stype = SvTYPE(sstr);
|
|
if (stype == SVt_PVGV && dtype <= SVt_PVGV)
|
|
goto glob_assign;
|
|
}
|
|
}
|
|
if (stype == SVt_PVLV)
|
|
(void)SvUPGRADE(dstr, SVt_PVNV);
|
|
else
|
|
(void)SvUPGRADE(dstr, stype);
|
|
}
|
|
|
|
sflags = SvFLAGS(sstr);
|
|
|
|
if (sflags & SVf_ROK) {
|
|
if (dtype >= SVt_PV) {
|
|
if (dtype == SVt_PVGV) {
|
|
SV *sref = SvREFCNT_inc(SvRV(sstr));
|
|
SV *dref = 0;
|
|
int intro = GvINTRO(dstr);
|
|
|
|
if (intro) {
|
|
GP *gp;
|
|
gp_free((GV*)dstr);
|
|
GvINTRO_off(dstr); /* one-shot flag */
|
|
Newz(602,gp, 1, GP);
|
|
GvGP(dstr) = gp_ref(gp);
|
|
GvSV(dstr) = NEWSV(72,0);
|
|
GvLINE(dstr) = CopLINE(PL_curcop);
|
|
GvEGV(dstr) = (GV*)dstr;
|
|
}
|
|
GvMULTI_on(dstr);
|
|
switch (SvTYPE(sref)) {
|
|
case SVt_PVAV:
|
|
if (intro)
|
|
SAVESPTR(GvAV(dstr));
|
|
else
|
|
dref = (SV*)GvAV(dstr);
|
|
GvAV(dstr) = (AV*)sref;
|
|
if (!GvIMPORTED_AV(dstr)
|
|
&& CopSTASH_ne(PL_curcop, GvSTASH(dstr)))
|
|
{
|
|
GvIMPORTED_AV_on(dstr);
|
|
}
|
|
break;
|
|
case SVt_PVHV:
|
|
if (intro)
|
|
SAVESPTR(GvHV(dstr));
|
|
else
|
|
dref = (SV*)GvHV(dstr);
|
|
GvHV(dstr) = (HV*)sref;
|
|
if (!GvIMPORTED_HV(dstr)
|
|
&& CopSTASH_ne(PL_curcop, GvSTASH(dstr)))
|
|
{
|
|
GvIMPORTED_HV_on(dstr);
|
|
}
|
|
break;
|
|
case SVt_PVCV:
|
|
if (intro) {
|
|
if (GvCVGEN(dstr) && GvCV(dstr) != (CV*)sref) {
|
|
SvREFCNT_dec(GvCV(dstr));
|
|
GvCV(dstr) = Nullcv;
|
|
GvCVGEN(dstr) = 0; /* Switch off cacheness. */
|
|
PL_sub_generation++;
|
|
}
|
|
SAVESPTR(GvCV(dstr));
|
|
}
|
|
else
|
|
dref = (SV*)GvCV(dstr);
|
|
if (GvCV(dstr) != (CV*)sref) {
|
|
CV* cv = GvCV(dstr);
|
|
if (cv) {
|
|
if (!GvCVGEN((GV*)dstr) &&
|
|
(CvROOT(cv) || CvXSUB(cv)))
|
|
{
|
|
SV *const_sv = cv_const_sv(cv);
|
|
bool const_changed = TRUE;
|
|
if(const_sv)
|
|
const_changed = sv_cmp(const_sv,
|
|
op_const_sv(CvSTART((CV*)sref),
|
|
Nullcv));
|
|
/* ahem, death to those who redefine
|
|
* active sort subs */
|
|
if (PL_curstackinfo->si_type == PERLSI_SORT &&
|
|
PL_sortcop == CvSTART(cv))
|
|
Perl_croak(aTHX_
|
|
"Can't redefine active sort subroutine %s",
|
|
GvENAME((GV*)dstr));
|
|
if ((const_changed || const_sv) && ckWARN(WARN_REDEFINE))
|
|
Perl_warner(aTHX_ WARN_REDEFINE, const_sv ?
|
|
"Constant subroutine %s redefined"
|
|
: "Subroutine %s redefined",
|
|
GvENAME((GV*)dstr));
|
|
}
|
|
cv_ckproto(cv, (GV*)dstr,
|
|
SvPOK(sref) ? SvPVX(sref) : Nullch);
|
|
}
|
|
GvCV(dstr) = (CV*)sref;
|
|
GvCVGEN(dstr) = 0; /* Switch off cacheness. */
|
|
GvASSUMECV_on(dstr);
|
|
PL_sub_generation++;
|
|
}
|
|
if (!GvIMPORTED_CV(dstr)
|
|
&& CopSTASH_ne(PL_curcop, GvSTASH(dstr)))
|
|
{
|
|
GvIMPORTED_CV_on(dstr);
|
|
}
|
|
break;
|
|
case SVt_PVIO:
|
|
if (intro)
|
|
SAVESPTR(GvIOp(dstr));
|
|
else
|
|
dref = (SV*)GvIOp(dstr);
|
|
GvIOp(dstr) = (IO*)sref;
|
|
break;
|
|
default:
|
|
if (intro)
|
|
SAVESPTR(GvSV(dstr));
|
|
else
|
|
dref = (SV*)GvSV(dstr);
|
|
GvSV(dstr) = sref;
|
|
if (!GvIMPORTED_SV(dstr)
|
|
&& CopSTASH_ne(PL_curcop, GvSTASH(dstr)))
|
|
{
|
|
GvIMPORTED_SV_on(dstr);
|
|
}
|
|
break;
|
|
}
|
|
if (dref)
|
|
SvREFCNT_dec(dref);
|
|
if (intro)
|
|
SAVEFREESV(sref);
|
|
if (SvTAINTED(sstr))
|
|
SvTAINT(dstr);
|
|
return;
|
|
}
|
|
if (SvPVX(dstr)) {
|
|
(void)SvOOK_off(dstr); /* backoff */
|
|
if (SvLEN(dstr))
|
|
Safefree(SvPVX(dstr));
|
|
SvLEN(dstr)=SvCUR(dstr)=0;
|
|
}
|
|
}
|
|
(void)SvOK_off(dstr);
|
|
SvRV(dstr) = SvREFCNT_inc(SvRV(sstr));
|
|
SvROK_on(dstr);
|
|
if (sflags & SVp_NOK) {
|
|
SvNOK_on(dstr);
|
|
SvNVX(dstr) = SvNVX(sstr);
|
|
}
|
|
if (sflags & SVp_IOK) {
|
|
(void)SvIOK_on(dstr);
|
|
SvIVX(dstr) = SvIVX(sstr);
|
|
if (sflags & SVf_IVisUV)
|
|
SvIsUV_on(dstr);
|
|
}
|
|
if (SvAMAGIC(sstr)) {
|
|
SvAMAGIC_on(dstr);
|
|
}
|
|
}
|
|
else if (sflags & SVp_POK) {
|
|
|
|
/*
|
|
* Check to see if we can just swipe the string. If so, it's a
|
|
* possible small lose on short strings, but a big win on long ones.
|
|
* It might even be a win on short strings if SvPVX(dstr)
|
|
* has to be allocated and SvPVX(sstr) has to be freed.
|
|
*/
|
|
|
|
if (SvTEMP(sstr) && /* slated for free anyway? */
|
|
SvREFCNT(sstr) == 1 && /* and no other references to it? */
|
|
!(sflags & SVf_OOK)) /* and not involved in OOK hack? */
|
|
{
|
|
if (SvPVX(dstr)) { /* we know that dtype >= SVt_PV */
|
|
if (SvOOK(dstr)) {
|
|
SvFLAGS(dstr) &= ~SVf_OOK;
|
|
Safefree(SvPVX(dstr) - SvIVX(dstr));
|
|
}
|
|
else if (SvLEN(dstr))
|
|
Safefree(SvPVX(dstr));
|
|
}
|
|
(void)SvPOK_only(dstr);
|
|
SvPV_set(dstr, SvPVX(sstr));
|
|
SvLEN_set(dstr, SvLEN(sstr));
|
|
SvCUR_set(dstr, SvCUR(sstr));
|
|
|
|
SvTEMP_off(dstr);
|
|
(void)SvOK_off(sstr); /* NOTE: nukes most SvFLAGS on sstr */
|
|
SvPV_set(sstr, Nullch);
|
|
SvLEN_set(sstr, 0);
|
|
SvCUR_set(sstr, 0);
|
|
SvTEMP_off(sstr);
|
|
}
|
|
else { /* have to copy actual string */
|
|
STRLEN len = SvCUR(sstr);
|
|
|
|
SvGROW(dstr, len + 1); /* inlined from sv_setpvn */
|
|
Move(SvPVX(sstr),SvPVX(dstr),len,char);
|
|
SvCUR_set(dstr, len);
|
|
*SvEND(dstr) = '\0';
|
|
(void)SvPOK_only(dstr);
|
|
}
|
|
if (sflags & SVf_UTF8)
|
|
SvUTF8_on(dstr);
|
|
/*SUPPRESS 560*/
|
|
if (sflags & SVp_NOK) {
|
|
SvNOK_on(dstr);
|
|
SvNVX(dstr) = SvNVX(sstr);
|
|
}
|
|
if (sflags & SVp_IOK) {
|
|
(void)SvIOK_on(dstr);
|
|
SvIVX(dstr) = SvIVX(sstr);
|
|
if (sflags & SVf_IVisUV)
|
|
SvIsUV_on(dstr);
|
|
}
|
|
}
|
|
else if (sflags & SVp_NOK) {
|
|
SvNVX(dstr) = SvNVX(sstr);
|
|
(void)SvNOK_only(dstr);
|
|
if (sflags & SVf_IOK) {
|
|
(void)SvIOK_on(dstr);
|
|
SvIVX(dstr) = SvIVX(sstr);
|
|
/* XXXX Do we want to set IsUV for IV(ROK)? Be extra safe... */
|
|
if (sflags & SVf_IVisUV)
|
|
SvIsUV_on(dstr);
|
|
}
|
|
}
|
|
else if (sflags & SVp_IOK) {
|
|
(void)SvIOK_only(dstr);
|
|
SvIVX(dstr) = SvIVX(sstr);
|
|
if (sflags & SVf_IVisUV)
|
|
SvIsUV_on(dstr);
|
|
}
|
|
else {
|
|
if (dtype == SVt_PVGV) {
|
|
if (ckWARN(WARN_MISC))
|
|
Perl_warner(aTHX_ WARN_MISC, "Undefined value assigned to typeglob");
|
|
}
|
|
else
|
|
(void)SvOK_off(dstr);
|
|
}
|
|
if (SvTAINTED(sstr))
|
|
SvTAINT(dstr);
|
|
}
|
|
|
|
/*
|
|
=for apidoc sv_setsv_mg
|
|
|
|
Like C<sv_setsv>, but also handles 'set' magic.
|
|
|
|
=cut
|
|
*/
|
|
|
|
void
|
|
Perl_sv_setsv_mg(pTHX_ SV *dstr, register SV *sstr)
|
|
{
|
|
sv_setsv(dstr,sstr);
|
|
SvSETMAGIC(dstr);
|
|
}
|
|
|
|
/*
|
|
=for apidoc sv_setpvn
|
|
|
|
Copies a string into an SV. The C<len> parameter indicates the number of
|
|
bytes to be copied. Does not handle 'set' magic. See C<sv_setpvn_mg>.
|
|
|
|
=cut
|
|
*/
|
|
|
|
void
|
|
Perl_sv_setpvn(pTHX_ register SV *sv, register const char *ptr, register STRLEN len)
|
|
{
|
|
register char *dptr;
|
|
|
|
SV_CHECK_THINKFIRST(sv);
|
|
if (!ptr) {
|
|
(void)SvOK_off(sv);
|
|
return;
|
|
}
|
|
else {
|
|
/* len is STRLEN which is unsigned, need to copy to signed */
|
|
IV iv = len;
|
|
assert(iv >= 0);
|
|
}
|
|
(void)SvUPGRADE(sv, SVt_PV);
|
|
|
|
SvGROW(sv, len + 1);
|
|
dptr = SvPVX(sv);
|
|
Move(ptr,dptr,len,char);
|
|
dptr[len] = '\0';
|
|
SvCUR_set(sv, len);
|
|
(void)SvPOK_only(sv); /* validate pointer */
|
|
SvTAINT(sv);
|
|
}
|
|
|
|
/*
|
|
=for apidoc sv_setpvn_mg
|
|
|
|
Like C<sv_setpvn>, but also handles 'set' magic.
|
|
|
|
=cut
|
|
*/
|
|
|
|
void
|
|
Perl_sv_setpvn_mg(pTHX_ register SV *sv, register const char *ptr, register STRLEN len)
|
|
{
|
|
sv_setpvn(sv,ptr,len);
|
|
SvSETMAGIC(sv);
|
|
}
|
|
|
|
/*
|
|
=for apidoc sv_setpv
|
|
|
|
Copies a string into an SV. The string must be null-terminated. Does not
|
|
handle 'set' magic. See C<sv_setpv_mg>.
|
|
|
|
=cut
|
|
*/
|
|
|
|
void
|
|
Perl_sv_setpv(pTHX_ register SV *sv, register const char *ptr)
|
|
{
|
|
register STRLEN len;
|
|
|
|
SV_CHECK_THINKFIRST(sv);
|
|
if (!ptr) {
|
|
(void)SvOK_off(sv);
|
|
return;
|
|
}
|
|
len = strlen(ptr);
|
|
(void)SvUPGRADE(sv, SVt_PV);
|
|
|
|
SvGROW(sv, len + 1);
|
|
Move(ptr,SvPVX(sv),len+1,char);
|
|
SvCUR_set(sv, len);
|
|
(void)SvPOK_only(sv); /* validate pointer */
|
|
SvTAINT(sv);
|
|
}
|
|
|
|
/*
|
|
=for apidoc sv_setpv_mg
|
|
|
|
Like C<sv_setpv>, but also handles 'set' magic.
|
|
|
|
=cut
|
|
*/
|
|
|
|
void
|
|
Perl_sv_setpv_mg(pTHX_ register SV *sv, register const char *ptr)
|
|
{
|
|
sv_setpv(sv,ptr);
|
|
SvSETMAGIC(sv);
|
|
}
|
|
|
|
/*
|
|
=for apidoc sv_usepvn
|
|
|
|
Tells an SV to use C<ptr> to find its string value. Normally the string is
|
|
stored inside the SV but sv_usepvn allows the SV to use an outside string.
|
|
The C<ptr> should point to memory that was allocated by C<malloc>. The
|
|
string length, C<len>, must be supplied. This function will realloc the
|
|
memory pointed to by C<ptr>, so that pointer should not be freed or used by
|
|
the programmer after giving it to sv_usepvn. Does not handle 'set' magic.
|
|
See C<sv_usepvn_mg>.
|
|
|
|
=cut
|
|
*/
|
|
|
|
void
|
|
Perl_sv_usepvn(pTHX_ register SV *sv, register char *ptr, register STRLEN len)
|
|
{
|
|
SV_CHECK_THINKFIRST(sv);
|
|
(void)SvUPGRADE(sv, SVt_PV);
|
|
if (!ptr) {
|
|
(void)SvOK_off(sv);
|
|
return;
|
|
}
|
|
(void)SvOOK_off(sv);
|
|
if (SvPVX(sv) && SvLEN(sv))
|
|
Safefree(SvPVX(sv));
|
|
Renew(ptr, len+1, char);
|
|
SvPVX(sv) = ptr;
|
|
SvCUR_set(sv, len);
|
|
SvLEN_set(sv, len+1);
|
|
*SvEND(sv) = '\0';
|
|
(void)SvPOK_only(sv); /* validate pointer */
|
|
SvTAINT(sv);
|
|
}
|
|
|
|
/*
|
|
=for apidoc sv_usepvn_mg
|
|
|
|
Like C<sv_usepvn>, but also handles 'set' magic.
|
|
|
|
=cut
|
|
*/
|
|
|
|
void
|
|
Perl_sv_usepvn_mg(pTHX_ register SV *sv, register char *ptr, register STRLEN len)
|
|
{
|
|
sv_usepvn(sv,ptr,len);
|
|
SvSETMAGIC(sv);
|
|
}
|
|
|
|
void
|
|
Perl_sv_force_normal(pTHX_ register SV *sv)
|
|
{
|
|
if (SvREADONLY(sv)) {
|
|
if (PL_curcop != &PL_compiling)
|
|
Perl_croak(aTHX_ PL_no_modify);
|
|
}
|
|
if (SvROK(sv))
|
|
sv_unref(sv);
|
|
else if (SvFAKE(sv) && SvTYPE(sv) == SVt_PVGV)
|
|
sv_unglob(sv);
|
|
}
|
|
|
|
/*
|
|
=for apidoc sv_chop
|
|
|
|
Efficient removal of characters from the beginning of the string buffer.
|
|
SvPOK(sv) must be true and the C<ptr> must be a pointer to somewhere inside
|
|
the string buffer. The C<ptr> becomes the first character of the adjusted
|
|
string.
|
|
|
|
=cut
|
|
*/
|
|
|
|
void
|
|
Perl_sv_chop(pTHX_ register SV *sv, register char *ptr) /* like set but assuming ptr is in sv */
|
|
|
|
|
|
{
|
|
register STRLEN delta;
|
|
|
|
if (!ptr || !SvPOKp(sv))
|
|
return;
|
|
SV_CHECK_THINKFIRST(sv);
|
|
if (SvTYPE(sv) < SVt_PVIV)
|
|
sv_upgrade(sv,SVt_PVIV);
|
|
|
|
if (!SvOOK(sv)) {
|
|
if (!SvLEN(sv)) { /* make copy of shared string */
|
|
char *pvx = SvPVX(sv);
|
|
STRLEN len = SvCUR(sv);
|
|
SvGROW(sv, len + 1);
|
|
Move(pvx,SvPVX(sv),len,char);
|
|
*SvEND(sv) = '\0';
|
|
}
|
|
SvIVX(sv) = 0;
|
|
SvFLAGS(sv) |= SVf_OOK;
|
|
}
|
|
SvFLAGS(sv) &= ~(SVf_IOK|SVf_NOK|SVp_IOK|SVp_NOK|SVf_IVisUV);
|
|
delta = ptr - SvPVX(sv);
|
|
SvLEN(sv) -= delta;
|
|
SvCUR(sv) -= delta;
|
|
SvPVX(sv) += delta;
|
|
SvIVX(sv) += delta;
|
|
}
|
|
|
|
/*
|
|
=for apidoc sv_catpvn
|
|
|
|
Concatenates the string onto the end of the string which is in the SV. The
|
|
C<len> indicates number of bytes to copy. Handles 'get' magic, but not
|
|
'set' magic. See C<sv_catpvn_mg>.
|
|
|
|
=cut
|
|
*/
|
|
|
|
void
|
|
Perl_sv_catpvn(pTHX_ register SV *sv, register const char *ptr, register STRLEN len)
|
|
{
|
|
STRLEN tlen;
|
|
char *junk;
|
|
|
|
junk = SvPV_force(sv, tlen);
|
|
SvGROW(sv, tlen + len + 1);
|
|
if (ptr == junk)
|
|
ptr = SvPVX(sv);
|
|
Move(ptr,SvPVX(sv)+tlen,len,char);
|
|
SvCUR(sv) += len;
|
|
*SvEND(sv) = '\0';
|
|
(void)SvPOK_only_UTF8(sv); /* validate pointer */
|
|
SvTAINT(sv);
|
|
}
|
|
|
|
/*
|
|
=for apidoc sv_catpvn_mg
|
|
|
|
Like C<sv_catpvn>, but also handles 'set' magic.
|
|
|
|
=cut
|
|
*/
|
|
|
|
void
|
|
Perl_sv_catpvn_mg(pTHX_ register SV *sv, register const char *ptr, register STRLEN len)
|
|
{
|
|
sv_catpvn(sv,ptr,len);
|
|
SvSETMAGIC(sv);
|
|
}
|
|
|
|
/*
|
|
=for apidoc sv_catsv
|
|
|
|
Concatenates the string from SV C<ssv> onto the end of the string in
|
|
SV C<dsv>. Modifies C<dsv> but not C<ssv>. Handles 'get' magic, but
|
|
not 'set' magic. See C<sv_catsv_mg>.
|
|
|
|
=cut */
|
|
|
|
void
|
|
Perl_sv_catsv(pTHX_ SV *dstr, register SV *sstr)
|
|
{
|
|
char *spv;
|
|
STRLEN slen;
|
|
if (!sstr)
|
|
return;
|
|
if ((spv = SvPV(sstr, slen))) {
|
|
bool dutf8 = DO_UTF8(dstr);
|
|
bool sutf8 = DO_UTF8(sstr);
|
|
|
|
if (dutf8 == sutf8)
|
|
sv_catpvn(dstr,spv,slen);
|
|
else {
|
|
if (dutf8) {
|
|
SV* cstr = newSVsv(sstr);
|
|
char *cpv;
|
|
STRLEN clen;
|
|
|
|
sv_utf8_upgrade(cstr);
|
|
cpv = SvPV(cstr,clen);
|
|
sv_catpvn(dstr,cpv,clen);
|
|
sv_2mortal(cstr);
|
|
}
|
|
else {
|
|
sv_utf8_upgrade(dstr);
|
|
sv_catpvn(dstr,spv,slen);
|
|
SvUTF8_on(dstr);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
=for apidoc sv_catsv_mg
|
|
|
|
Like C<sv_catsv>, but also handles 'set' magic.
|
|
|
|
=cut
|
|
*/
|
|
|
|
void
|
|
Perl_sv_catsv_mg(pTHX_ SV *dstr, register SV *sstr)
|
|
{
|
|
sv_catsv(dstr,sstr);
|
|
SvSETMAGIC(dstr);
|
|
}
|
|
|
|
/*
|
|
=for apidoc sv_catpv
|
|
|
|
Concatenates the string onto the end of the string which is in the SV.
|
|
Handles 'get' magic, but not 'set' magic. See C<sv_catpv_mg>.
|
|
|
|
=cut
|
|
*/
|
|
|
|
void
|
|
Perl_sv_catpv(pTHX_ register SV *sv, register const char *ptr)
|
|
{
|
|
register STRLEN len;
|
|
STRLEN tlen;
|
|
char *junk;
|
|
|
|
if (!ptr)
|
|
return;
|
|
junk = SvPV_force(sv, tlen);
|
|
len = strlen(ptr);
|
|
SvGROW(sv, tlen + len + 1);
|
|
if (ptr == junk)
|
|
ptr = SvPVX(sv);
|
|
Move(ptr,SvPVX(sv)+tlen,len+1,char);
|
|
SvCUR(sv) += len;
|
|
(void)SvPOK_only_UTF8(sv); /* validate pointer */
|
|
SvTAINT(sv);
|
|
}
|
|
|
|
/*
|
|
=for apidoc sv_catpv_mg
|
|
|
|
Like C<sv_catpv>, but also handles 'set' magic.
|
|
|
|
=cut
|
|
*/
|
|
|
|
void
|
|
Perl_sv_catpv_mg(pTHX_ register SV *sv, register const char *ptr)
|
|
{
|
|
sv_catpv(sv,ptr);
|
|
SvSETMAGIC(sv);
|
|
}
|
|
|
|
SV *
|
|
Perl_newSV(pTHX_ STRLEN len)
|
|
{
|
|
register SV *sv;
|
|
|
|
new_SV(sv);
|
|
if (len) {
|
|
sv_upgrade(sv, SVt_PV);
|
|
SvGROW(sv, len + 1);
|
|
}
|
|
return sv;
|
|
}
|
|
|
|
/* name is assumed to contain an SV* if (name && namelen == HEf_SVKEY) */
|
|
|
|
/*
|
|
=for apidoc sv_magic
|
|
|
|
Adds magic to an SV.
|
|
|
|
=cut
|
|
*/
|
|
|
|
void
|
|
Perl_sv_magic(pTHX_ register SV *sv, SV *obj, int how, const char *name, I32 namlen)
|
|
{
|
|
MAGIC* mg;
|
|
|
|
if (SvREADONLY(sv)) {
|
|
if (PL_curcop != &PL_compiling && !strchr("gBf", how))
|
|
Perl_croak(aTHX_ PL_no_modify);
|
|
}
|
|
if (SvMAGICAL(sv) || (how == 't' && SvTYPE(sv) >= SVt_PVMG)) {
|
|
if (SvMAGIC(sv) && (mg = mg_find(sv, how))) {
|
|
if (how == 't')
|
|
mg->mg_len |= 1;
|
|
return;
|
|
}
|
|
}
|
|
else {
|
|
(void)SvUPGRADE(sv, SVt_PVMG);
|
|
}
|
|
Newz(702,mg, 1, MAGIC);
|
|
mg->mg_moremagic = SvMAGIC(sv);
|
|
SvMAGIC(sv) = mg;
|
|
|
|
/* Some magic sontains a reference loop, where the sv and object refer to
|
|
each other. To prevent a avoid a reference loop that would prevent such
|
|
objects being freed, we look for such loops and if we find one we avoid
|
|
incrementing the object refcount. */
|
|
if (!obj || obj == sv || how == '#' || how == 'r' ||
|
|
(SvTYPE(obj) == SVt_PVGV &&
|
|
(GvSV(obj) == sv || GvHV(obj) == (HV*)sv || GvAV(obj) == (AV*)sv ||
|
|
GvCV(obj) == (CV*)sv || GvIOp(obj) == (IO*)sv ||
|
|
GvFORM(obj) == (CV*)sv)))
|
|
{
|
|
mg->mg_obj = obj;
|
|
}
|
|
else {
|
|
mg->mg_obj = SvREFCNT_inc(obj);
|
|
mg->mg_flags |= MGf_REFCOUNTED;
|
|
}
|
|
mg->mg_type = how;
|
|
mg->mg_len = namlen;
|
|
if (name)
|
|
if (namlen >= 0)
|
|
mg->mg_ptr = savepvn(name, namlen);
|
|
else if (namlen == HEf_SVKEY)
|
|
mg->mg_ptr = (char*)SvREFCNT_inc((SV*)name);
|
|
|
|
switch (how) {
|
|
case 0:
|
|
mg->mg_virtual = &PL_vtbl_sv;
|
|
break;
|
|
case 'A':
|
|
mg->mg_virtual = &PL_vtbl_amagic;
|
|
break;
|
|
case 'a':
|
|
mg->mg_virtual = &PL_vtbl_amagicelem;
|
|
break;
|
|
case 'c':
|
|
mg->mg_virtual = 0;
|
|
break;
|
|
case 'B':
|
|
mg->mg_virtual = &PL_vtbl_bm;
|
|
break;
|
|
case 'D':
|
|
mg->mg_virtual = &PL_vtbl_regdata;
|
|
break;
|
|
case 'd':
|
|
mg->mg_virtual = &PL_vtbl_regdatum;
|
|
break;
|
|
case 'E':
|
|
mg->mg_virtual = &PL_vtbl_env;
|
|
break;
|
|
case 'f':
|
|
mg->mg_virtual = &PL_vtbl_fm;
|
|
break;
|
|
case 'e':
|
|
mg->mg_virtual = &PL_vtbl_envelem;
|
|
break;
|
|
case 'g':
|
|
mg->mg_virtual = &PL_vtbl_mglob;
|
|
break;
|
|
case 'I':
|
|
mg->mg_virtual = &PL_vtbl_isa;
|
|
break;
|
|
case 'i':
|
|
mg->mg_virtual = &PL_vtbl_isaelem;
|
|
break;
|
|
case 'k':
|
|
mg->mg_virtual = &PL_vtbl_nkeys;
|
|
break;
|
|
case 'L':
|
|
SvRMAGICAL_on(sv);
|
|
mg->mg_virtual = 0;
|
|
break;
|
|
case 'l':
|
|
mg->mg_virtual = &PL_vtbl_dbline;
|
|
break;
|
|
#ifdef USE_THREADS
|
|
case 'm':
|
|
mg->mg_virtual = &PL_vtbl_mutex;
|
|
break;
|
|
#endif /* USE_THREADS */
|
|
#ifdef USE_LOCALE_COLLATE
|
|
case 'o':
|
|
mg->mg_virtual = &PL_vtbl_collxfrm;
|
|
break;
|
|
#endif /* USE_LOCALE_COLLATE */
|
|
case 'P':
|
|
mg->mg_virtual = &PL_vtbl_pack;
|
|
break;
|
|
case 'p':
|
|
case 'q':
|
|
mg->mg_virtual = &PL_vtbl_packelem;
|
|
break;
|
|
case 'r':
|
|
mg->mg_virtual = &PL_vtbl_regexp;
|
|
break;
|
|
case 'S':
|
|
mg->mg_virtual = &PL_vtbl_sig;
|
|
break;
|
|
case 's':
|
|
mg->mg_virtual = &PL_vtbl_sigelem;
|
|
break;
|
|
case 't':
|
|
mg->mg_virtual = &PL_vtbl_taint;
|
|
mg->mg_len = 1;
|
|
break;
|
|
case 'U':
|
|
mg->mg_virtual = &PL_vtbl_uvar;
|
|
break;
|
|
case 'v':
|
|
mg->mg_virtual = &PL_vtbl_vec;
|
|
break;
|
|
case 'x':
|
|
mg->mg_virtual = &PL_vtbl_substr;
|
|
break;
|
|
case 'y':
|
|
mg->mg_virtual = &PL_vtbl_defelem;
|
|
break;
|
|
case '*':
|
|
mg->mg_virtual = &PL_vtbl_glob;
|
|
break;
|
|
case '#':
|
|
mg->mg_virtual = &PL_vtbl_arylen;
|
|
break;
|
|
case '.':
|
|
mg->mg_virtual = &PL_vtbl_pos;
|
|
break;
|
|
case '<':
|
|
mg->mg_virtual = &PL_vtbl_backref;
|
|
break;
|
|
case '~': /* Reserved for use by extensions not perl internals. */
|
|
/* Useful for attaching extension internal data to perl vars. */
|
|
/* Note that multiple extensions may clash if magical scalars */
|
|
/* etc holding private data from one are passed to another. */
|
|
SvRMAGICAL_on(sv);
|
|
break;
|
|
default:
|
|
Perl_croak(aTHX_ "Don't know how to handle magic of type '%c'", how);
|
|
}
|
|
mg_magical(sv);
|
|
if (SvGMAGICAL(sv))
|
|
SvFLAGS(sv) &= ~(SVf_IOK|SVf_NOK|SVf_POK);
|
|
}
|
|
|
|
/*
|
|
=for apidoc sv_unmagic
|
|
|
|
Removes magic from an SV.
|
|
|
|
=cut
|
|
*/
|
|
|
|
int
|
|
Perl_sv_unmagic(pTHX_ SV *sv, int type)
|
|
{
|
|
MAGIC* mg;
|
|
MAGIC** mgp;
|
|
if (SvTYPE(sv) < SVt_PVMG || !SvMAGIC(sv))
|
|
return 0;
|
|
mgp = &SvMAGIC(sv);
|
|
for (mg = *mgp; mg; mg = *mgp) {
|
|
if (mg->mg_type == type) {
|
|
MGVTBL* vtbl = mg->mg_virtual;
|
|
*mgp = mg->mg_moremagic;
|
|
if (vtbl && vtbl->svt_free)
|
|
CALL_FPTR(vtbl->svt_free)(aTHX_ sv, mg);
|
|
if (mg->mg_ptr && mg->mg_type != 'g')
|
|
if (mg->mg_len >= 0)
|
|
Safefree(mg->mg_ptr);
|
|
else if (mg->mg_len == HEf_SVKEY)
|
|
SvREFCNT_dec((SV*)mg->mg_ptr);
|
|
if (mg->mg_flags & MGf_REFCOUNTED)
|
|
SvREFCNT_dec(mg->mg_obj);
|
|
Safefree(mg);
|
|
}
|
|
else
|
|
mgp = &mg->mg_moremagic;
|
|
}
|
|
if (!SvMAGIC(sv)) {
|
|
SvMAGICAL_off(sv);
|
|
SvFLAGS(sv) |= (SvFLAGS(sv) & (SVp_IOK|SVp_NOK|SVp_POK)) >> PRIVSHIFT;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
=for apidoc sv_rvweaken
|
|
|
|
Weaken a reference.
|
|
|
|
=cut
|
|
*/
|
|
|
|
SV *
|
|
Perl_sv_rvweaken(pTHX_ SV *sv)
|
|
{
|
|
SV *tsv;
|
|
if (!SvOK(sv)) /* let undefs pass */
|
|
return sv;
|
|
if (!SvROK(sv))
|
|
Perl_croak(aTHX_ "Can't weaken a nonreference");
|
|
else if (SvWEAKREF(sv)) {
|
|
if (ckWARN(WARN_MISC))
|
|
Perl_warner(aTHX_ WARN_MISC, "Reference is already weak");
|
|
return sv;
|
|
}
|
|
tsv = SvRV(sv);
|
|
sv_add_backref(tsv, sv);
|
|
SvWEAKREF_on(sv);
|
|
SvREFCNT_dec(tsv);
|
|
return sv;
|
|
}
|
|
|
|
void
|
|
Perl_sv_add_backref(pTHX_ SV *tsv, SV *sv)
|
|
{
|
|
AV *av;
|
|
MAGIC *mg;
|
|
if (SvMAGICAL(tsv) && (mg = mg_find(tsv, '<')))
|
|
av = (AV*)mg->mg_obj;
|
|
else {
|
|
av = newAV();
|
|
sv_magic(tsv, (SV*)av, '<', NULL, 0);
|
|
SvREFCNT_dec(av); /* for sv_magic */
|
|
}
|
|
av_push(av,sv);
|
|
}
|
|
|
|
void
|
|
Perl_sv_del_backref(pTHX_ SV *sv)
|
|
{
|
|
AV *av;
|
|
SV **svp;
|
|
I32 i;
|
|
SV *tsv = SvRV(sv);
|
|
MAGIC *mg;
|
|
if (!SvMAGICAL(tsv) || !(mg = mg_find(tsv, '<')))
|
|
Perl_croak(aTHX_ "panic: del_backref");
|
|
av = (AV *)mg->mg_obj;
|
|
svp = AvARRAY(av);
|
|
i = AvFILLp(av);
|
|
while (i >= 0) {
|
|
if (svp[i] == sv) {
|
|
svp[i] = &PL_sv_undef; /* XXX */
|
|
}
|
|
i--;
|
|
}
|
|
}
|
|
|
|
/*
|
|
=for apidoc sv_insert
|
|
|
|
Inserts a string at the specified offset/length within the SV. Similar to
|
|
the Perl substr() function.
|
|
|
|
=cut
|
|
*/
|
|
|
|
void
|
|
Perl_sv_insert(pTHX_ SV *bigstr, STRLEN offset, STRLEN len, char *little, STRLEN littlelen)
|
|
{
|
|
register char *big;
|
|
register char *mid;
|
|
register char *midend;
|
|
register char *bigend;
|
|
register I32 i;
|
|
STRLEN curlen;
|
|
|
|
|
|
if (!bigstr)
|
|
Perl_croak(aTHX_ "Can't modify non-existent substring");
|
|
SvPV_force(bigstr, curlen);
|
|
(void)SvPOK_only_UTF8(bigstr);
|
|
if (offset + len > curlen) {
|
|
SvGROW(bigstr, offset+len+1);
|
|
Zero(SvPVX(bigstr)+curlen, offset+len-curlen, char);
|
|
SvCUR_set(bigstr, offset+len);
|
|
}
|
|
|
|
SvTAINT(bigstr);
|
|
i = littlelen - len;
|
|
if (i > 0) { /* string might grow */
|
|
big = SvGROW(bigstr, SvCUR(bigstr) + i + 1);
|
|
mid = big + offset + len;
|
|
midend = bigend = big + SvCUR(bigstr);
|
|
bigend += i;
|
|
*bigend = '\0';
|
|
while (midend > mid) /* shove everything down */
|
|
*--bigend = *--midend;
|
|
Move(little,big+offset,littlelen,char);
|
|
SvCUR(bigstr) += i;
|
|
SvSETMAGIC(bigstr);
|
|
return;
|
|
}
|
|
else if (i == 0) {
|
|
Move(little,SvPVX(bigstr)+offset,len,char);
|
|
SvSETMAGIC(bigstr);
|
|
return;
|
|
}
|
|
|
|
big = SvPVX(bigstr);
|
|
mid = big + offset;
|
|
midend = mid + len;
|
|
bigend = big + SvCUR(bigstr);
|
|
|
|
if (midend > bigend)
|
|
Perl_croak(aTHX_ "panic: sv_insert");
|
|
|
|
if (mid - big > bigend - midend) { /* faster to shorten from end */
|
|
if (littlelen) {
|
|
Move(little, mid, littlelen,char);
|
|
mid += littlelen;
|
|
}
|
|
i = bigend - midend;
|
|
if (i > 0) {
|
|
Move(midend, mid, i,char);
|
|
mid += i;
|
|
}
|
|
*mid = '\0';
|
|
SvCUR_set(bigstr, mid - big);
|
|
}
|
|
/*SUPPRESS 560*/
|
|
else if ((i = mid - big)) { /* faster from front */
|
|
midend -= littlelen;
|
|
mid = midend;
|
|
sv_chop(bigstr,midend-i);
|
|
big += i;
|
|
while (i--)
|
|
*--midend = *--big;
|
|
if (littlelen)
|
|
Move(little, mid, littlelen,char);
|
|
}
|
|
else if (littlelen) {
|
|
midend -= littlelen;
|
|
sv_chop(bigstr,midend);
|
|
Move(little,midend,littlelen,char);
|
|
}
|
|
else {
|
|
sv_chop(bigstr,midend);
|
|
}
|
|
SvSETMAGIC(bigstr);
|
|
}
|
|
|
|
/*
|
|
=for apidoc sv_replace
|
|
|
|
Make the first argument a copy of the second, then delete the original.
|
|
|
|
=cut
|
|
*/
|
|
|
|
void
|
|
Perl_sv_replace(pTHX_ register SV *sv, register SV *nsv)
|
|
{
|
|
U32 refcnt = SvREFCNT(sv);
|
|
SV_CHECK_THINKFIRST(sv);
|
|
if (SvREFCNT(nsv) != 1 && ckWARN_d(WARN_INTERNAL))
|
|
Perl_warner(aTHX_ WARN_INTERNAL, "Reference miscount in sv_replace()");
|
|
if (SvMAGICAL(sv)) {
|
|
if (SvMAGICAL(nsv))
|
|
mg_free(nsv);
|
|
else
|
|
sv_upgrade(nsv, SVt_PVMG);
|
|
SvMAGIC(nsv) = SvMAGIC(sv);
|
|
SvFLAGS(nsv) |= SvMAGICAL(sv);
|
|
SvMAGICAL_off(sv);
|
|
SvMAGIC(sv) = 0;
|
|
}
|
|
SvREFCNT(sv) = 0;
|
|
sv_clear(sv);
|
|
assert(!SvREFCNT(sv));
|
|
StructCopy(nsv,sv,SV);
|
|
SvREFCNT(sv) = refcnt;
|
|
SvFLAGS(nsv) |= SVTYPEMASK; /* Mark as freed */
|
|
del_SV(nsv);
|
|
}
|
|
|
|
/*
|
|
=for apidoc sv_clear
|
|
|
|
Clear an SV, making it empty. Does not free the memory used by the SV
|
|
itself.
|
|
|
|
=cut
|
|
*/
|
|
|
|
void
|
|
Perl_sv_clear(pTHX_ register SV *sv)
|
|
{
|
|
HV* stash;
|
|
assert(sv);
|
|
assert(SvREFCNT(sv) == 0);
|
|
|
|
if (SvOBJECT(sv)) {
|
|
if (PL_defstash) { /* Still have a symbol table? */
|
|
dSP;
|
|
GV* destructor;
|
|
SV tmpref;
|
|
|
|
Zero(&tmpref, 1, SV);
|
|
sv_upgrade(&tmpref, SVt_RV);
|
|
SvROK_on(&tmpref);
|
|
SvREADONLY_on(&tmpref); /* DESTROY() could be naughty */
|
|
SvREFCNT(&tmpref) = 1;
|
|
|
|
do {
|
|
stash = SvSTASH(sv);
|
|
destructor = gv_fetchmethod(SvSTASH(sv), "DESTROY");
|
|
if (destructor) {
|
|
ENTER;
|
|
PUSHSTACKi(PERLSI_DESTROY);
|
|
SvRV(&tmpref) = SvREFCNT_inc(sv);
|
|
EXTEND(SP, 2);
|
|
PUSHMARK(SP);
|
|
PUSHs(&tmpref);
|
|
PUTBACK;
|
|
call_sv((SV*)GvCV(destructor),
|
|
G_DISCARD|G_EVAL|G_KEEPERR);
|
|
SvREFCNT(sv)--;
|
|
POPSTACK;
|
|
SPAGAIN;
|
|
LEAVE;
|
|
}
|
|
} while (SvOBJECT(sv) && SvSTASH(sv) != stash);
|
|
|
|
del_XRV(SvANY(&tmpref));
|
|
|
|
if (SvREFCNT(sv)) {
|
|
if (PL_in_clean_objs)
|
|
Perl_croak(aTHX_ "DESTROY created new reference to dead object '%s'",
|
|
HvNAME(stash));
|
|
/* DESTROY gave object new lease on life */
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (SvOBJECT(sv)) {
|
|
SvREFCNT_dec(SvSTASH(sv)); /* possibly of changed persuasion */
|
|
SvOBJECT_off(sv); /* Curse the object. */
|
|
if (SvTYPE(sv) != SVt_PVIO)
|
|
--PL_sv_objcount; /* XXX Might want something more general */
|
|
}
|
|
}
|
|
if (SvTYPE(sv) >= SVt_PVMG && SvMAGIC(sv))
|
|
mg_free(sv);
|
|
stash = NULL;
|
|
switch (SvTYPE(sv)) {
|
|
case SVt_PVIO:
|
|
if (IoIFP(sv) &&
|
|
IoIFP(sv) != PerlIO_stdin() &&
|
|
IoIFP(sv) != PerlIO_stdout() &&
|
|
IoIFP(sv) != PerlIO_stderr())
|
|
{
|
|
io_close((IO*)sv, FALSE);
|
|
}
|
|
if (IoDIRP(sv) && !(IoFLAGS(sv) & IOf_FAKE_DIRP))
|
|
PerlDir_close(IoDIRP(sv));
|
|
IoDIRP(sv) = (DIR*)NULL;
|
|
Safefree(IoTOP_NAME(sv));
|
|
Safefree(IoFMT_NAME(sv));
|
|
Safefree(IoBOTTOM_NAME(sv));
|
|
/* FALL THROUGH */
|
|
case SVt_PVBM:
|
|
goto freescalar;
|
|
case SVt_PVCV:
|
|
case SVt_PVFM:
|
|
cv_undef((CV*)sv);
|
|
goto freescalar;
|
|
case SVt_PVHV:
|
|
hv_undef((HV*)sv);
|
|
break;
|
|
case SVt_PVAV:
|
|
av_undef((AV*)sv);
|
|
break;
|
|
case SVt_PVLV:
|
|
SvREFCNT_dec(LvTARG(sv));
|
|
goto freescalar;
|
|
case SVt_PVGV:
|
|
gp_free((GV*)sv);
|
|
Safefree(GvNAME(sv));
|
|
/* cannot decrease stash refcount yet, as we might recursively delete
|
|
ourselves when the refcnt drops to zero. Delay SvREFCNT_dec
|
|
of stash until current sv is completely gone.
|
|
-- JohnPC, 27 Mar 1998 */
|
|
stash = GvSTASH(sv);
|
|
/* FALL THROUGH */
|
|
case SVt_PVMG:
|
|
case SVt_PVNV:
|
|
case SVt_PVIV:
|
|
freescalar:
|
|
(void)SvOOK_off(sv);
|
|
/* FALL THROUGH */
|
|
case SVt_PV:
|
|
case SVt_RV:
|
|
if (SvROK(sv)) {
|
|
if (SvWEAKREF(sv))
|
|
sv_del_backref(sv);
|
|
else
|
|
SvREFCNT_dec(SvRV(sv));
|
|
}
|
|
else if (SvPVX(sv) && SvLEN(sv))
|
|
Safefree(SvPVX(sv));
|
|
break;
|
|
/*
|
|
case SVt_NV:
|
|
case SVt_IV:
|
|
case SVt_NULL:
|
|
break;
|
|
*/
|
|
}
|
|
|
|
switch (SvTYPE(sv)) {
|
|
case SVt_NULL:
|
|
break;
|
|
case SVt_IV:
|
|
del_XIV(SvANY(sv));
|
|
break;
|
|
case SVt_NV:
|
|
del_XNV(SvANY(sv));
|
|
break;
|
|
case SVt_RV:
|
|
del_XRV(SvANY(sv));
|
|
break;
|
|
case SVt_PV:
|
|
del_XPV(SvANY(sv));
|
|
break;
|
|
case SVt_PVIV:
|
|
del_XPVIV(SvANY(sv));
|
|
break;
|
|
case SVt_PVNV:
|
|
del_XPVNV(SvANY(sv));
|
|
break;
|
|
case SVt_PVMG:
|
|
del_XPVMG(SvANY(sv));
|
|
break;
|
|
case SVt_PVLV:
|
|
del_XPVLV(SvANY(sv));
|
|
break;
|
|
case SVt_PVAV:
|
|
del_XPVAV(SvANY(sv));
|
|
break;
|
|
case SVt_PVHV:
|
|
del_XPVHV(SvANY(sv));
|
|
break;
|
|
case SVt_PVCV:
|
|
del_XPVCV(SvANY(sv));
|
|
break;
|
|
case SVt_PVGV:
|
|
del_XPVGV(SvANY(sv));
|
|
/* code duplication for increased performance. */
|
|
SvFLAGS(sv) &= SVf_BREAK;
|
|
SvFLAGS(sv) |= SVTYPEMASK;
|
|
/* decrease refcount of the stash that owns this GV, if any */
|
|
if (stash)
|
|
SvREFCNT_dec(stash);
|
|
return; /* not break, SvFLAGS reset already happened */
|
|
case SVt_PVBM:
|
|
del_XPVBM(SvANY(sv));
|
|
break;
|
|
case SVt_PVFM:
|
|
del_XPVFM(SvANY(sv));
|
|
break;
|
|
case SVt_PVIO:
|
|
del_XPVIO(SvANY(sv));
|
|
break;
|
|
}
|
|
SvFLAGS(sv) &= SVf_BREAK;
|
|
SvFLAGS(sv) |= SVTYPEMASK;
|
|
}
|
|
|
|
SV *
|
|
Perl_sv_newref(pTHX_ SV *sv)
|
|
{
|
|
if (sv)
|
|
ATOMIC_INC(SvREFCNT(sv));
|
|
return sv;
|
|
}
|
|
|
|
/*
|
|
=for apidoc sv_free
|
|
|
|
Free the memory used by an SV.
|
|
|
|
=cut
|
|
*/
|
|
|
|
void
|
|
Perl_sv_free(pTHX_ SV *sv)
|
|
{
|
|
int refcount_is_zero;
|
|
|
|
if (!sv)
|
|
return;
|
|
if (SvREFCNT(sv) == 0) {
|
|
if (SvFLAGS(sv) & SVf_BREAK)
|
|
return;
|
|
if (PL_in_clean_all) /* All is fair */
|
|
return;
|
|
if (SvREADONLY(sv) && SvIMMORTAL(sv)) {
|
|
/* make sure SvREFCNT(sv)==0 happens very seldom */
|
|
SvREFCNT(sv) = (~(U32)0)/2;
|
|
return;
|
|
}
|
|
if (ckWARN_d(WARN_INTERNAL))
|
|
Perl_warner(aTHX_ WARN_INTERNAL, "Attempt to free unreferenced scalar");
|
|
return;
|
|
}
|
|
ATOMIC_DEC_AND_TEST(refcount_is_zero, SvREFCNT(sv));
|
|
if (!refcount_is_zero)
|
|
return;
|
|
#ifdef DEBUGGING
|
|
if (SvTEMP(sv)) {
|
|
if (ckWARN_d(WARN_DEBUGGING))
|
|
Perl_warner(aTHX_ WARN_DEBUGGING,
|
|
"Attempt to free temp prematurely: SV 0x%"UVxf,
|
|
PTR2UV(sv));
|
|
return;
|
|
}
|
|
#endif
|
|
if (SvREADONLY(sv) && SvIMMORTAL(sv)) {
|
|
/* make sure SvREFCNT(sv)==0 happens very seldom */
|
|
SvREFCNT(sv) = (~(U32)0)/2;
|
|
return;
|
|
}
|
|
sv_clear(sv);
|
|
if (! SvREFCNT(sv))
|
|
del_SV(sv);
|
|
}
|
|
|
|
/*
|
|
=for apidoc sv_len
|
|
|
|
Returns the length of the string in the SV. See also C<SvCUR>.
|
|
|
|
=cut
|
|
*/
|
|
|
|
STRLEN
|
|
Perl_sv_len(pTHX_ register SV *sv)
|
|
{
|
|
char *junk;
|
|
STRLEN len;
|
|
|
|
if (!sv)
|
|
return 0;
|
|
|
|
if (SvGMAGICAL(sv))
|
|
len = mg_length(sv);
|
|
else
|
|
junk = SvPV(sv, len);
|
|
return len;
|
|
}
|
|
|
|
/*
|
|
=for apidoc sv_len_utf8
|
|
|
|
Returns the number of characters in the string in an SV, counting wide
|
|
UTF8 bytes as a single character.
|
|
|
|
=cut
|
|
*/
|
|
|
|
STRLEN
|
|
Perl_sv_len_utf8(pTHX_ register SV *sv)
|
|
{
|
|
if (!sv)
|
|
return 0;
|
|
|
|
#ifdef NOTYET
|
|
if (SvGMAGICAL(sv))
|
|
return mg_length(sv);
|
|
else
|
|
#endif
|
|
{
|
|
STRLEN len;
|
|
U8 *s = (U8*)SvPV(sv, len);
|
|
|
|
return Perl_utf8_length(aTHX_ s, s + len);
|
|
}
|
|
}
|
|
|
|
void
|
|
Perl_sv_pos_u2b(pTHX_ register SV *sv, I32* offsetp, I32* lenp)
|
|
{
|
|
U8 *start;
|
|
U8 *s;
|
|
U8 *send;
|
|
I32 uoffset = *offsetp;
|
|
STRLEN len;
|
|
|
|
if (!sv)
|
|
return;
|
|
|
|
start = s = (U8*)SvPV(sv, len);
|
|
send = s + len;
|
|
while (s < send && uoffset--)
|
|
s += UTF8SKIP(s);
|
|
if (s >= send)
|
|
s = send;
|
|
*offsetp = s - start;
|
|
if (lenp) {
|
|
I32 ulen = *lenp;
|
|
start = s;
|
|
while (s < send && ulen--)
|
|
s += UTF8SKIP(s);
|
|
if (s >= send)
|
|
s = send;
|
|
*lenp = s - start;
|
|
}
|
|
return;
|
|
}
|
|
|
|
void
|
|
Perl_sv_pos_b2u(pTHX_ register SV *sv, I32* offsetp)
|
|
{
|
|
U8 *s;
|
|
U8 *send;
|
|
STRLEN len;
|
|
|
|
if (!sv)
|
|
return;
|
|
|
|
s = (U8*)SvPV(sv, len);
|
|
if (len < *offsetp)
|
|
Perl_croak(aTHX_ "panic: sv_pos_b2u: bad byte offset");
|
|
send = s + *offsetp;
|
|
len = 0;
|
|
while (s < send) {
|
|
STRLEN n;
|
|
|
|
if (utf8_to_uv(s, UTF8SKIP(s), &n, 0)) {
|
|
s += n;
|
|
len++;
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
*offsetp = len;
|
|
return;
|
|
}
|
|
|
|
/*
|
|
=for apidoc sv_eq
|
|
|
|
Returns a boolean indicating whether the strings in the two SVs are
|
|
identical.
|
|
|
|
=cut
|
|
*/
|
|
|
|
I32
|
|
Perl_sv_eq(pTHX_ register SV *sv1, register SV *sv2)
|
|
{
|
|
char *pv1;
|
|
STRLEN cur1;
|
|
char *pv2;
|
|
STRLEN cur2;
|
|
I32 eq = 0;
|
|
bool pv1tmp = FALSE;
|
|
bool pv2tmp = FALSE;
|
|
|
|
if (!sv1) {
|
|
pv1 = "";
|
|
cur1 = 0;
|
|
}
|
|
else
|
|
pv1 = SvPV(sv1, cur1);
|
|
|
|
if (!sv2){
|
|
pv2 = "";
|
|
cur2 = 0;
|
|
}
|
|
else
|
|
pv2 = SvPV(sv2, cur2);
|
|
|
|
/* do not utf8ize the comparands as a side-effect */
|
|
if (cur1 && cur2 && SvUTF8(sv1) != SvUTF8(sv2) && !IN_BYTE) {
|
|
bool is_utf8 = TRUE;
|
|
|
|
if (SvUTF8(sv1)) {
|
|
char *pv = (char*)bytes_from_utf8((U8*)pv1, &cur1, &is_utf8);
|
|
|
|
if ((pv1tmp = (pv != pv1)))
|
|
pv1 = pv;
|
|
}
|
|
else {
|
|
char *pv = (char *)bytes_from_utf8((U8*)pv2, &cur2, &is_utf8);
|
|
|
|
if ((pv2tmp = (pv != pv2)))
|
|
pv2 = pv;
|
|
}
|
|
}
|
|
|
|
if (cur1 == cur2)
|
|
eq = memEQ(pv1, pv2, cur1);
|
|
|
|
if (pv1tmp)
|
|
Safefree(pv1);
|
|
if (pv2tmp)
|
|
Safefree(pv2);
|
|
|
|
return eq;
|
|
}
|
|
|
|
/*
|
|
=for apidoc sv_cmp
|
|
|
|
Compares the strings in two SVs. Returns -1, 0, or 1 indicating whether the
|
|
string in C<sv1> is less than, equal to, or greater than the string in
|
|
C<sv2>.
|
|
|
|
=cut
|
|
*/
|
|
|
|
I32
|
|
Perl_sv_cmp(pTHX_ register SV *sv1, register SV *sv2)
|
|
{
|
|
STRLEN cur1, cur2;
|
|
char *pv1, *pv2;
|
|
I32 cmp;
|
|
bool pv1tmp = FALSE;
|
|
bool pv2tmp = FALSE;
|
|
|
|
if (!sv1) {
|
|
pv1 = "";
|
|
cur1 = 0;
|
|
}
|
|
else
|
|
pv1 = SvPV(sv1, cur1);
|
|
|
|
if (!sv2){
|
|
pv2 = "";
|
|
cur2 = 0;
|
|
}
|
|
else
|
|
pv2 = SvPV(sv2, cur2);
|
|
|
|
/* do not utf8ize the comparands as a side-effect */
|
|
if (cur1 && cur2 && SvUTF8(sv1) != SvUTF8(sv2) && !IN_BYTE) {
|
|
if (SvUTF8(sv1)) {
|
|
pv2 = (char*)bytes_to_utf8((U8*)pv2, &cur2);
|
|
pv2tmp = TRUE;
|
|
}
|
|
else {
|
|
pv1 = (char*)bytes_to_utf8((U8*)pv1, &cur1);
|
|
pv1tmp = TRUE;
|
|
}
|
|
}
|
|
|
|
if (!cur1) {
|
|
cmp = cur2 ? -1 : 0;
|
|
} else if (!cur2) {
|
|
cmp = 1;
|
|
} else {
|
|
I32 retval = memcmp((void*)pv1, (void*)pv2, cur1 < cur2 ? cur1 : cur2);
|
|
|
|
if (retval) {
|
|
cmp = retval < 0 ? -1 : 1;
|
|
} else if (cur1 == cur2) {
|
|
cmp = 0;
|
|
} else {
|
|
cmp = cur1 < cur2 ? -1 : 1;
|
|
}
|
|
}
|
|
|
|
if (pv1tmp)
|
|
Safefree(pv1);
|
|
if (pv2tmp)
|
|
Safefree(pv2);
|
|
|
|
return cmp;
|
|
}
|
|
|
|
/*
|
|
=for apidoc sv_cmp_locale
|
|
|
|
Compares the strings in two SVs in a locale-aware manner. See
|
|
L</sv_cmp_locale>
|
|
|
|
=cut
|
|
*/
|
|
|
|
I32
|
|
Perl_sv_cmp_locale(pTHX_ register SV *sv1, register SV *sv2)
|
|
{
|
|
#ifdef USE_LOCALE_COLLATE
|
|
|
|
char *pv1, *pv2;
|
|
STRLEN len1, len2;
|
|
I32 retval;
|
|
|
|
if (PL_collation_standard)
|
|
goto raw_compare;
|
|
|
|
len1 = 0;
|
|
pv1 = sv1 ? sv_collxfrm(sv1, &len1) : (char *) NULL;
|
|
len2 = 0;
|
|
pv2 = sv2 ? sv_collxfrm(sv2, &len2) : (char *) NULL;
|
|
|
|
if (!pv1 || !len1) {
|
|
if (pv2 && len2)
|
|
return -1;
|
|
else
|
|
goto raw_compare;
|
|
}
|
|
else {
|
|
if (!pv2 || !len2)
|
|
return 1;
|
|
}
|
|
|
|
retval = memcmp((void*)pv1, (void*)pv2, len1 < len2 ? len1 : len2);
|
|
|
|
if (retval)
|
|
return retval < 0 ? -1 : 1;
|
|
|
|
/*
|
|
* When the result of collation is equality, that doesn't mean
|
|
* that there are no differences -- some locales exclude some
|
|
* characters from consideration. So to avoid false equalities,
|
|
* we use the raw string as a tiebreaker.
|
|
*/
|
|
|
|
raw_compare:
|
|
/* FALL THROUGH */
|
|
|
|
#endif /* USE_LOCALE_COLLATE */
|
|
|
|
return sv_cmp(sv1, sv2);
|
|
}
|
|
|
|
#ifdef USE_LOCALE_COLLATE
|
|
/*
|
|
* Any scalar variable may carry an 'o' magic that contains the
|
|
* scalar data of the variable transformed to such a format that
|
|
* a normal memory comparison can be used to compare the data
|
|
* according to the locale settings.
|
|
*/
|
|
char *
|
|
Perl_sv_collxfrm(pTHX_ SV *sv, STRLEN *nxp)
|
|
{
|
|
MAGIC *mg;
|
|
|
|
mg = SvMAGICAL(sv) ? mg_find(sv, 'o') : (MAGIC *) NULL;
|
|
if (!mg || !mg->mg_ptr || *(U32*)mg->mg_ptr != PL_collation_ix) {
|
|
char *s, *xf;
|
|
STRLEN len, xlen;
|
|
|
|
if (mg)
|
|
Safefree(mg->mg_ptr);
|
|
s = SvPV(sv, len);
|
|
if ((xf = mem_collxfrm(s, len, &xlen))) {
|
|
if (SvREADONLY(sv)) {
|
|
SAVEFREEPV(xf);
|
|
*nxp = xlen;
|
|
return xf + sizeof(PL_collation_ix);
|
|
}
|
|
if (! mg) {
|
|
sv_magic(sv, 0, 'o', 0, 0);
|
|
mg = mg_find(sv, 'o');
|
|
assert(mg);
|
|
}
|
|
mg->mg_ptr = xf;
|
|
mg->mg_len = xlen;
|
|
}
|
|
else {
|
|
if (mg) {
|
|
mg->mg_ptr = NULL;
|
|
mg->mg_len = -1;
|
|
}
|
|
}
|
|
}
|
|
if (mg && mg->mg_ptr) {
|
|
*nxp = mg->mg_len;
|
|
return mg->mg_ptr + sizeof(PL_collation_ix);
|
|
}
|
|
else {
|
|
*nxp = 0;
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
#endif /* USE_LOCALE_COLLATE */
|
|
|
|
/*
|
|
=for apidoc sv_gets
|
|
|
|
Get a line from the filehandle and store it into the SV, optionally
|
|
appending to the currently-stored string.
|
|
|
|
=cut
|
|
*/
|
|
|
|
char *
|
|
Perl_sv_gets(pTHX_ register SV *sv, register PerlIO *fp, I32 append)
|
|
{
|
|
char *rsptr;
|
|
STRLEN rslen;
|
|
register STDCHAR rslast;
|
|
register STDCHAR *bp;
|
|
register I32 cnt;
|
|
I32 i;
|
|
|
|
SV_CHECK_THINKFIRST(sv);
|
|
(void)SvUPGRADE(sv, SVt_PV);
|
|
|
|
SvSCREAM_off(sv);
|
|
|
|
if (RsSNARF(PL_rs)) {
|
|
rsptr = NULL;
|
|
rslen = 0;
|
|
}
|
|
else if (RsRECORD(PL_rs)) {
|
|
I32 recsize, bytesread;
|
|
char *buffer;
|
|
|
|
/* Grab the size of the record we're getting */
|
|
recsize = SvIV(SvRV(PL_rs));
|
|
(void)SvPOK_only(sv); /* Validate pointer */
|
|
buffer = SvGROW(sv, recsize + 1);
|
|
/* Go yank in */
|
|
#ifdef VMS
|
|
/* VMS wants read instead of fread, because fread doesn't respect */
|
|
/* RMS record boundaries. This is not necessarily a good thing to be */
|
|
/* doing, but we've got no other real choice */
|
|
bytesread = PerlLIO_read(PerlIO_fileno(fp), buffer, recsize);
|
|
#else
|
|
bytesread = PerlIO_read(fp, buffer, recsize);
|
|
#endif
|
|
SvCUR_set(sv, bytesread);
|
|
buffer[bytesread] = '\0';
|
|
SvUTF8_off(sv);
|
|
return(SvCUR(sv) ? SvPVX(sv) : Nullch);
|
|
}
|
|
else if (RsPARA(PL_rs)) {
|
|
rsptr = "\n\n";
|
|
rslen = 2;
|
|
}
|
|
else {
|
|
/* Get $/ i.e. PL_rs into same encoding as stream wants */
|
|
if (SvUTF8(PL_rs)) {
|
|
if (!sv_utf8_downgrade(PL_rs, TRUE)) {
|
|
Perl_croak(aTHX_ "Wide character in $/");
|
|
}
|
|
}
|
|
rsptr = SvPV(PL_rs, rslen);
|
|
}
|
|
|
|
rslast = rslen ? rsptr[rslen - 1] : '\0';
|
|
|
|
if (RsPARA(PL_rs)) { /* have to do this both before and after */
|
|
do { /* to make sure file boundaries work right */
|
|
if (PerlIO_eof(fp))
|
|
return 0;
|
|
i = PerlIO_getc(fp);
|
|
if (i != '\n') {
|
|
if (i == -1)
|
|
return 0;
|
|
PerlIO_ungetc(fp,i);
|
|
break;
|
|
}
|
|
} while (i != EOF);
|
|
}
|
|
|
|
/* See if we know enough about I/O mechanism to cheat it ! */
|
|
|
|
/* This used to be #ifdef test - it is made run-time test for ease
|
|
of abstracting out stdio interface. One call should be cheap
|
|
enough here - and may even be a macro allowing compile
|
|
time optimization.
|
|
*/
|
|
|
|
if (PerlIO_fast_gets(fp)) {
|
|
|
|
/*
|
|
* We're going to steal some values from the stdio struct
|
|
* and put EVERYTHING in the innermost loop into registers.
|
|
*/
|
|
register STDCHAR *ptr;
|
|
STRLEN bpx;
|
|
I32 shortbuffered;
|
|
|
|
#if defined(VMS) && defined(PERLIO_IS_STDIO)
|
|
/* An ungetc()d char is handled separately from the regular
|
|
* buffer, so we getc() it back out and stuff it in the buffer.
|
|
*/
|
|
i = PerlIO_getc(fp);
|
|
if (i == EOF) return 0;
|
|
*(--((*fp)->_ptr)) = (unsigned char) i;
|
|
(*fp)->_cnt++;
|
|
#endif
|
|
|
|
/* Here is some breathtakingly efficient cheating */
|
|
|
|
cnt = PerlIO_get_cnt(fp); /* get count into register */
|
|
(void)SvPOK_only(sv); /* validate pointer */
|
|
if (SvLEN(sv) - append <= cnt + 1) { /* make sure we have the room */
|
|
if (cnt > 80 && SvLEN(sv) > append) {
|
|
shortbuffered = cnt - SvLEN(sv) + append + 1;
|
|
cnt -= shortbuffered;
|
|
}
|
|
else {
|
|
shortbuffered = 0;
|
|
/* remember that cnt can be negative */
|
|
SvGROW(sv, append + (cnt <= 0 ? 2 : (cnt + 1)));
|
|
}
|
|
}
|
|
else
|
|
shortbuffered = 0;
|
|
bp = (STDCHAR*)SvPVX(sv) + append; /* move these two too to registers */
|
|
ptr = (STDCHAR*)PerlIO_get_ptr(fp);
|
|
DEBUG_P(PerlIO_printf(Perl_debug_log,
|
|
"Screamer: entering, ptr=%"UVuf", cnt=%ld\n",PTR2UV(ptr),(long)cnt));
|
|
DEBUG_P(PerlIO_printf(Perl_debug_log,
|
|
"Screamer: entering: FILE * thinks ptr=%"UVuf", cnt=%ld, base=%"UVuf"\n",
|
|
PTR2UV(PerlIO_get_ptr(fp)), (long)PerlIO_get_cnt(fp),
|
|
PTR2UV(PerlIO_has_base(fp) ? PerlIO_get_base(fp) : 0)));
|
|
for (;;) {
|
|
screamer:
|
|
if (cnt > 0) {
|
|
if (rslen) {
|
|
while (cnt > 0) { /* this | eat */
|
|
cnt--;
|
|
if ((*bp++ = *ptr++) == rslast) /* really | dust */
|
|
goto thats_all_folks; /* screams | sed :-) */
|
|
}
|
|
}
|
|
else {
|
|
Copy(ptr, bp, cnt, char); /* this | eat */
|
|
bp += cnt; /* screams | dust */
|
|
ptr += cnt; /* louder | sed :-) */
|
|
cnt = 0;
|
|
}
|
|
}
|
|
|
|
if (shortbuffered) { /* oh well, must extend */
|
|
cnt = shortbuffered;
|
|
shortbuffered = 0;
|
|
bpx = bp - (STDCHAR*)SvPVX(sv); /* box up before relocation */
|
|
SvCUR_set(sv, bpx);
|
|
SvGROW(sv, SvLEN(sv) + append + cnt + 2);
|
|
bp = (STDCHAR*)SvPVX(sv) + bpx; /* unbox after relocation */
|
|
continue;
|
|
}
|
|
|
|
DEBUG_P(PerlIO_printf(Perl_debug_log,
|
|
"Screamer: going to getc, ptr=%"UVuf", cnt=%ld\n",
|
|
PTR2UV(ptr),(long)cnt));
|
|
PerlIO_set_ptrcnt(fp, ptr, cnt); /* deregisterize cnt and ptr */
|
|
DEBUG_P(PerlIO_printf(Perl_debug_log,
|
|
"Screamer: pre: FILE * thinks ptr=%"UVuf", cnt=%ld, base=%"UVuf"\n",
|
|
PTR2UV(PerlIO_get_ptr(fp)), (long)PerlIO_get_cnt(fp),
|
|
PTR2UV(PerlIO_has_base (fp) ? PerlIO_get_base(fp) : 0)));
|
|
/* This used to call 'filbuf' in stdio form, but as that behaves like
|
|
getc when cnt <= 0 we use PerlIO_getc here to avoid introducing
|
|
another abstraction. */
|
|
i = PerlIO_getc(fp); /* get more characters */
|
|
DEBUG_P(PerlIO_printf(Perl_debug_log,
|
|
"Screamer: post: FILE * thinks ptr=%"UVuf", cnt=%ld, base=%"UVuf"\n",
|
|
PTR2UV(PerlIO_get_ptr(fp)), (long)PerlIO_get_cnt(fp),
|
|
PTR2UV(PerlIO_has_base (fp) ? PerlIO_get_base(fp) : 0)));
|
|
cnt = PerlIO_get_cnt(fp);
|
|
ptr = (STDCHAR*)PerlIO_get_ptr(fp); /* reregisterize cnt and ptr */
|
|
DEBUG_P(PerlIO_printf(Perl_debug_log,
|
|
"Screamer: after getc, ptr=%"UVuf", cnt=%ld\n",PTR2UV(ptr),(long)cnt));
|
|
|
|
if (i == EOF) /* all done for ever? */
|
|
goto thats_really_all_folks;
|
|
|
|
bpx = bp - (STDCHAR*)SvPVX(sv); /* box up before relocation */
|
|
SvCUR_set(sv, bpx);
|
|
SvGROW(sv, bpx + cnt + 2);
|
|
bp = (STDCHAR*)SvPVX(sv) + bpx; /* unbox after relocation */
|
|
|
|
*bp++ = i; /* store character from PerlIO_getc */
|
|
|
|
if (rslen && (STDCHAR)i == rslast) /* all done for now? */
|
|
goto thats_all_folks;
|
|
}
|
|
|
|
thats_all_folks:
|
|
if ((rslen > 1 && (bp - (STDCHAR*)SvPVX(sv) < rslen)) ||
|
|
memNE((char*)bp - rslen, rsptr, rslen))
|
|
goto screamer; /* go back to the fray */
|
|
thats_really_all_folks:
|
|
if (shortbuffered)
|
|
cnt += shortbuffered;
|
|
DEBUG_P(PerlIO_printf(Perl_debug_log,
|
|
"Screamer: quitting, ptr=%"UVuf", cnt=%ld\n",PTR2UV(ptr),(long)cnt));
|
|
PerlIO_set_ptrcnt(fp, ptr, cnt); /* put these back or we're in trouble */
|
|
DEBUG_P(PerlIO_printf(Perl_debug_log,
|
|
"Screamer: end: FILE * thinks ptr=%"UVuf", cnt=%ld, base=%"UVuf"\n",
|
|
PTR2UV(PerlIO_get_ptr(fp)), (long)PerlIO_get_cnt(fp),
|
|
PTR2UV(PerlIO_has_base (fp) ? PerlIO_get_base(fp) : 0)));
|
|
*bp = '\0';
|
|
SvCUR_set(sv, bp - (STDCHAR*)SvPVX(sv)); /* set length */
|
|
DEBUG_P(PerlIO_printf(Perl_debug_log,
|
|
"Screamer: done, len=%ld, string=|%.*s|\n",
|
|
(long)SvCUR(sv),(int)SvCUR(sv),SvPVX(sv)));
|
|
}
|
|
else
|
|
{
|
|
#ifndef EPOC
|
|
/*The big, slow, and stupid way */
|
|
STDCHAR buf[8192];
|
|
#else
|
|
/* Need to work around EPOC SDK features */
|
|
/* On WINS: MS VC5 generates calls to _chkstk, */
|
|
/* if a `large' stack frame is allocated */
|
|
/* gcc on MARM does not generate calls like these */
|
|
STDCHAR buf[1024];
|
|
#endif
|
|
|
|
screamer2:
|
|
if (rslen) {
|
|
register STDCHAR *bpe = buf + sizeof(buf);
|
|
bp = buf;
|
|
while ((i = PerlIO_getc(fp)) != EOF && (*bp++ = i) != rslast && bp < bpe)
|
|
; /* keep reading */
|
|
cnt = bp - buf;
|
|
}
|
|
else {
|
|
cnt = PerlIO_read(fp,(char*)buf, sizeof(buf));
|
|
/* Accomodate broken VAXC compiler, which applies U8 cast to
|
|
* both args of ?: operator, causing EOF to change into 255
|
|
*/
|
|
if (cnt) { i = (U8)buf[cnt - 1]; } else { i = EOF; }
|
|
}
|
|
|
|
if (append)
|
|
sv_catpvn(sv, (char *) buf, cnt);
|
|
else
|
|
sv_setpvn(sv, (char *) buf, cnt);
|
|
|
|
if (i != EOF && /* joy */
|
|
(!rslen ||
|
|
SvCUR(sv) < rslen ||
|
|
memNE(SvPVX(sv) + SvCUR(sv) - rslen, rsptr, rslen)))
|
|
{
|
|
append = -1;
|
|
/*
|
|
* If we're reading from a TTY and we get a short read,
|
|
* indicating that the user hit his EOF character, we need
|
|
* to notice it now, because if we try to read from the TTY
|
|
* again, the EOF condition will disappear.
|
|
*
|
|
* The comparison of cnt to sizeof(buf) is an optimization
|
|
* that prevents unnecessary calls to feof().
|
|
*
|
|
* - jik 9/25/96
|
|
*/
|
|
if (!(cnt < sizeof(buf) && PerlIO_eof(fp)))
|
|
goto screamer2;
|
|
}
|
|
}
|
|
|
|
if (RsPARA(PL_rs)) { /* have to do this both before and after */
|
|
while (i != EOF) { /* to make sure file boundaries work right */
|
|
i = PerlIO_getc(fp);
|
|
if (i != '\n') {
|
|
PerlIO_ungetc(fp,i);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
SvUTF8_off(sv);
|
|
|
|
return (SvCUR(sv) - append) ? SvPVX(sv) : Nullch;
|
|
}
|
|
|
|
|
|
/*
|
|
=for apidoc sv_inc
|
|
|
|
Auto-increment of the value in the SV.
|
|
|
|
=cut
|
|
*/
|
|
|
|
void
|
|
Perl_sv_inc(pTHX_ register SV *sv)
|
|
{
|
|
register char *d;
|
|
int flags;
|
|
|
|
if (!sv)
|
|
return;
|
|
if (SvGMAGICAL(sv))
|
|
mg_get(sv);
|
|
if (SvTHINKFIRST(sv)) {
|
|
if (SvREADONLY(sv)) {
|
|
if (PL_curcop != &PL_compiling)
|
|
Perl_croak(aTHX_ PL_no_modify);
|
|
}
|
|
if (SvROK(sv)) {
|
|
IV i;
|
|
if (SvAMAGIC(sv) && AMG_CALLun(sv,inc))
|
|
return;
|
|
i = PTR2IV(SvRV(sv));
|
|
sv_unref(sv);
|
|
sv_setiv(sv, i);
|
|
}
|
|
}
|
|
flags = SvFLAGS(sv);
|
|
if (flags & SVp_NOK) {
|
|
(void)SvNOK_only(sv);
|
|
SvNVX(sv) += 1.0;
|
|
return;
|
|
}
|
|
if (flags & SVp_IOK) {
|
|
if (SvIsUV(sv)) {
|
|
if (SvUVX(sv) == UV_MAX)
|
|
sv_setnv(sv, (NV)UV_MAX + 1.0);
|
|
else
|
|
(void)SvIOK_only_UV(sv);
|
|
++SvUVX(sv);
|
|
} else {
|
|
if (SvIVX(sv) == IV_MAX)
|
|
sv_setnv(sv, (NV)IV_MAX + 1.0);
|
|
else {
|
|
(void)SvIOK_only(sv);
|
|
++SvIVX(sv);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
if (!(flags & SVp_POK) || !*SvPVX(sv)) {
|
|
if ((flags & SVTYPEMASK) < SVt_PVNV)
|
|
sv_upgrade(sv, SVt_NV);
|
|
SvNVX(sv) = 1.0;
|
|
(void)SvNOK_only(sv);
|
|
return;
|
|
}
|
|
d = SvPVX(sv);
|
|
while (isALPHA(*d)) d++;
|
|
while (isDIGIT(*d)) d++;
|
|
if (*d) {
|
|
sv_setnv(sv,Atof(SvPVX(sv)) + 1.0); /* punt */
|
|
return;
|
|
}
|
|
d--;
|
|
while (d >= SvPVX(sv)) {
|
|
if (isDIGIT(*d)) {
|
|
if (++*d <= '9')
|
|
return;
|
|
*(d--) = '0';
|
|
}
|
|
else {
|
|
#ifdef EBCDIC
|
|
/* MKS: The original code here died if letters weren't consecutive.
|
|
* at least it didn't have to worry about non-C locales. The
|
|
* new code assumes that ('z'-'a')==('Z'-'A'), letters are
|
|
* arranged in order (although not consecutively) and that only
|
|
* [A-Za-z] are accepted by isALPHA in the C locale.
|
|
*/
|
|
if (*d != 'z' && *d != 'Z') {
|
|
do { ++*d; } while (!isALPHA(*d));
|
|
return;
|
|
}
|
|
*(d--) -= 'z' - 'a';
|
|
#else
|
|
++*d;
|
|
if (isALPHA(*d))
|
|
return;
|
|
*(d--) -= 'z' - 'a' + 1;
|
|
#endif
|
|
}
|
|
}
|
|
/* oh,oh, the number grew */
|
|
SvGROW(sv, SvCUR(sv) + 2);
|
|
SvCUR(sv)++;
|
|
for (d = SvPVX(sv) + SvCUR(sv); d > SvPVX(sv); d--)
|
|
*d = d[-1];
|
|
if (isDIGIT(d[1]))
|
|
*d = '1';
|
|
else
|
|
*d = d[1];
|
|
}
|
|
|
|
/*
|
|
=for apidoc sv_dec
|
|
|
|
Auto-decrement of the value in the SV.
|
|
|
|
=cut
|
|
*/
|
|
|
|
void
|
|
Perl_sv_dec(pTHX_ register SV *sv)
|
|
{
|
|
int flags;
|
|
|
|
if (!sv)
|
|
return;
|
|
if (SvGMAGICAL(sv))
|
|
mg_get(sv);
|
|
if (SvTHINKFIRST(sv)) {
|
|
if (SvREADONLY(sv)) {
|
|
if (PL_curcop != &PL_compiling)
|
|
Perl_croak(aTHX_ PL_no_modify);
|
|
}
|
|
if (SvROK(sv)) {
|
|
IV i;
|
|
if (SvAMAGIC(sv) && AMG_CALLun(sv,dec))
|
|
return;
|
|
i = PTR2IV(SvRV(sv));
|
|
sv_unref(sv);
|
|
sv_setiv(sv, i);
|
|
}
|
|
}
|
|
flags = SvFLAGS(sv);
|
|
if (flags & SVp_NOK) {
|
|
SvNVX(sv) -= 1.0;
|
|
(void)SvNOK_only(sv);
|
|
return;
|
|
}
|
|
if (flags & SVp_IOK) {
|
|
if (SvIsUV(sv)) {
|
|
if (SvUVX(sv) == 0) {
|
|
(void)SvIOK_only(sv);
|
|
SvIVX(sv) = -1;
|
|
}
|
|
else {
|
|
(void)SvIOK_only_UV(sv);
|
|
--SvUVX(sv);
|
|
}
|
|
} else {
|
|
if (SvIVX(sv) == IV_MIN)
|
|
sv_setnv(sv, (NV)IV_MIN - 1.0);
|
|
else {
|
|
(void)SvIOK_only(sv);
|
|
--SvIVX(sv);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
if (!(flags & SVp_POK)) {
|
|
if ((flags & SVTYPEMASK) < SVt_PVNV)
|
|
sv_upgrade(sv, SVt_NV);
|
|
SvNVX(sv) = -1.0;
|
|
(void)SvNOK_only(sv);
|
|
return;
|
|
}
|
|
sv_setnv(sv,Atof(SvPVX(sv)) - 1.0); /* punt */
|
|
}
|
|
|
|
/*
|
|
=for apidoc sv_mortalcopy
|
|
|
|
Creates a new SV which is a copy of the original SV. The new SV is marked
|
|
as mortal.
|
|
|
|
=cut
|
|
*/
|
|
|
|
/* Make a string that will exist for the duration of the expression
|
|
* evaluation. Actually, it may have to last longer than that, but
|
|
* hopefully we won't free it until it has been assigned to a
|
|
* permanent location. */
|
|
|
|
SV *
|
|
Perl_sv_mortalcopy(pTHX_ SV *oldstr)
|
|
{
|
|
register SV *sv;
|
|
|
|
new_SV(sv);
|
|
sv_setsv(sv,oldstr);
|
|
EXTEND_MORTAL(1);
|
|
PL_tmps_stack[++PL_tmps_ix] = sv;
|
|
SvTEMP_on(sv);
|
|
return sv;
|
|
}
|
|
|
|
/*
|
|
=for apidoc sv_newmortal
|
|
|
|
Creates a new SV which is mortal. The reference count of the SV is set to 1.
|
|
|
|
=cut
|
|
*/
|
|
|
|
SV *
|
|
Perl_sv_newmortal(pTHX)
|
|
{
|
|
register SV *sv;
|
|
|
|
new_SV(sv);
|
|
SvFLAGS(sv) = SVs_TEMP;
|
|
EXTEND_MORTAL(1);
|
|
PL_tmps_stack[++PL_tmps_ix] = sv;
|
|
return sv;
|
|
}
|
|
|
|
/*
|
|
=for apidoc sv_2mortal
|
|
|
|
Marks an SV as mortal. The SV will be destroyed when the current context
|
|
ends.
|
|
|
|
=cut
|
|
*/
|
|
|
|
/* same thing without the copying */
|
|
|
|
SV *
|
|
Perl_sv_2mortal(pTHX_ register SV *sv)
|
|
{
|
|
if (!sv)
|
|
return sv;
|
|
if (SvREADONLY(sv) && SvIMMORTAL(sv))
|
|
return sv;
|
|
EXTEND_MORTAL(1);
|
|
PL_tmps_stack[++PL_tmps_ix] = sv;
|
|
SvTEMP_on(sv);
|
|
return sv;
|
|
}
|
|
|
|
/*
|
|
=for apidoc newSVpv
|
|
|
|
Creates a new SV and copies a string into it. The reference count for the
|
|
SV is set to 1. If C<len> is zero, Perl will compute the length using
|
|
strlen(). For efficiency, consider using C<newSVpvn> instead.
|
|
|
|
=cut
|
|
*/
|
|
|
|
SV *
|
|
Perl_newSVpv(pTHX_ const char *s, STRLEN len)
|
|
{
|
|
register SV *sv;
|
|
|
|
new_SV(sv);
|
|
if (!len)
|
|
len = strlen(s);
|
|
sv_setpvn(sv,s,len);
|
|
return sv;
|
|
}
|
|
|
|
/*
|
|
=for apidoc newSVpvn
|
|
|
|
Creates a new SV and copies a string into it. The reference count for the
|
|
SV is set to 1. Note that if C<len> is zero, Perl will create a zero length
|
|
string. You are responsible for ensuring that the source string is at least
|
|
C<len> bytes long.
|
|
|
|
=cut
|
|
*/
|
|
|
|
SV *
|
|
Perl_newSVpvn(pTHX_ const char *s, STRLEN len)
|
|
{
|
|
register SV *sv;
|
|
|
|
new_SV(sv);
|
|
sv_setpvn(sv,s,len);
|
|
return sv;
|
|
}
|
|
|
|
#if defined(PERL_IMPLICIT_CONTEXT)
|
|
SV *
|
|
Perl_newSVpvf_nocontext(const char* pat, ...)
|
|
{
|
|
dTHX;
|
|
register SV *sv;
|
|
va_list args;
|
|
va_start(args, pat);
|
|
sv = vnewSVpvf(pat, &args);
|
|
va_end(args);
|
|
return sv;
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
=for apidoc newSVpvf
|
|
|
|
Creates a new SV an initialize it with the string formatted like
|
|
C<sprintf>.
|
|
|
|
=cut
|
|
*/
|
|
|
|
SV *
|
|
Perl_newSVpvf(pTHX_ const char* pat, ...)
|
|
{
|
|
register SV *sv;
|
|
va_list args;
|
|
va_start(args, pat);
|
|
sv = vnewSVpvf(pat, &args);
|
|
va_end(args);
|
|
return sv;
|
|
}
|
|
|
|
SV *
|
|
Perl_vnewSVpvf(pTHX_ const char* pat, va_list* args)
|
|
{
|
|
register SV *sv;
|
|
new_SV(sv);
|
|
sv_vsetpvfn(sv, pat, strlen(pat), args, Null(SV**), 0, Null(bool*));
|
|
return sv;
|
|
}
|
|
|
|
/*
|
|
=for apidoc newSVnv
|
|
|
|
Creates a new SV and copies a floating point value into it.
|
|
The reference count for the SV is set to 1.
|
|
|
|
=cut
|
|
*/
|
|
|
|
SV *
|
|
Perl_newSVnv(pTHX_ NV n)
|
|
{
|
|
register SV *sv;
|
|
|
|
new_SV(sv);
|
|
sv_setnv(sv,n);
|
|
return sv;
|
|
}
|
|
|
|
/*
|
|
=for apidoc newSViv
|
|
|
|
Creates a new SV and copies an integer into it. The reference count for the
|
|
SV is set to 1.
|
|
|
|
=cut
|
|
*/
|
|
|
|
SV *
|
|
Perl_newSViv(pTHX_ IV i)
|
|
{
|
|
register SV *sv;
|
|
|
|
new_SV(sv);
|
|
sv_setiv(sv,i);
|
|
return sv;
|
|
}
|
|
|
|
/*
|
|
=for apidoc newSVuv
|
|
|
|
Creates a new SV and copies an unsigned integer into it.
|
|
The reference count for the SV is set to 1.
|
|
|
|
=cut
|
|
*/
|
|
|
|
SV *
|
|
Perl_newSVuv(pTHX_ UV u)
|
|
{
|
|
register SV *sv;
|
|
|
|
new_SV(sv);
|
|
sv_setuv(sv,u);
|
|
return sv;
|
|
}
|
|
|
|
/*
|
|
=for apidoc newRV_noinc
|
|
|
|
Creates an RV wrapper for an SV. The reference count for the original
|
|
SV is B<not> incremented.
|
|
|
|
=cut
|
|
*/
|
|
|
|
SV *
|
|
Perl_newRV_noinc(pTHX_ SV *tmpRef)
|
|
{
|
|
register SV *sv;
|
|
|
|
new_SV(sv);
|
|
sv_upgrade(sv, SVt_RV);
|
|
SvTEMP_off(tmpRef);
|
|
SvRV(sv) = tmpRef;
|
|
SvROK_on(sv);
|
|
return sv;
|
|
}
|
|
|
|
/* newRV_inc is #defined to newRV in sv.h */
|
|
SV *
|
|
Perl_newRV(pTHX_ SV *tmpRef)
|
|
{
|
|
return newRV_noinc(SvREFCNT_inc(tmpRef));
|
|
}
|
|
|
|
/*
|
|
=for apidoc newSVsv
|
|
|
|
Creates a new SV which is an exact duplicate of the original SV.
|
|
|
|
=cut
|
|
*/
|
|
|
|
/* make an exact duplicate of old */
|
|
|
|
SV *
|
|
Perl_newSVsv(pTHX_ register SV *old)
|
|
{
|
|
register SV *sv;
|
|
|
|
if (!old)
|
|
return Nullsv;
|
|
if (SvTYPE(old) == SVTYPEMASK) {
|
|
if (ckWARN_d(WARN_INTERNAL))
|
|
Perl_warner(aTHX_ WARN_INTERNAL, "semi-panic: attempt to dup freed string");
|
|
return Nullsv;
|
|
}
|
|
new_SV(sv);
|
|
if (SvTEMP(old)) {
|
|
SvTEMP_off(old);
|
|
sv_setsv(sv,old);
|
|
SvTEMP_on(old);
|
|
}
|
|
else
|
|
sv_setsv(sv,old);
|
|
return sv;
|
|
}
|
|
|
|
void
|
|
Perl_sv_reset(pTHX_ register char *s, HV *stash)
|
|
{
|
|
register HE *entry;
|
|
register GV *gv;
|
|
register SV *sv;
|
|
register I32 i;
|
|
register PMOP *pm;
|
|
register I32 max;
|
|
char todo[PERL_UCHAR_MAX+1];
|
|
|
|
if (!stash)
|
|
return;
|
|
|
|
if (!*s) { /* reset ?? searches */
|
|
for (pm = HvPMROOT(stash); pm; pm = pm->op_pmnext) {
|
|
pm->op_pmdynflags &= ~PMdf_USED;
|
|
}
|
|
return;
|
|
}
|
|
|
|
/* reset variables */
|
|
|
|
if (!HvARRAY(stash))
|
|
return;
|
|
|
|
Zero(todo, 256, char);
|
|
while (*s) {
|
|
i = (unsigned char)*s;
|
|
if (s[1] == '-') {
|
|
s += 2;
|
|
}
|
|
max = (unsigned char)*s++;
|
|
for ( ; i <= max; i++) {
|
|
todo[i] = 1;
|
|
}
|
|
for (i = 0; i <= (I32) HvMAX(stash); i++) {
|
|
for (entry = HvARRAY(stash)[i];
|
|
entry;
|
|
entry = HeNEXT(entry))
|
|
{
|
|
if (!todo[(U8)*HeKEY(entry)])
|
|
continue;
|
|
gv = (GV*)HeVAL(entry);
|
|
sv = GvSV(gv);
|
|
if (SvTHINKFIRST(sv)) {
|
|
if (!SvREADONLY(sv) && SvROK(sv))
|
|
sv_unref(sv);
|
|
continue;
|
|
}
|
|
(void)SvOK_off(sv);
|
|
if (SvTYPE(sv) >= SVt_PV) {
|
|
SvCUR_set(sv, 0);
|
|
if (SvPVX(sv) != Nullch)
|
|
*SvPVX(sv) = '\0';
|
|
SvTAINT(sv);
|
|
}
|
|
if (GvAV(gv)) {
|
|
av_clear(GvAV(gv));
|
|
}
|
|
if (GvHV(gv) && !HvNAME(GvHV(gv))) {
|
|
hv_clear(GvHV(gv));
|
|
#ifdef USE_ENVIRON_ARRAY
|
|
if (gv == PL_envgv)
|
|
environ[0] = Nullch;
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
IO*
|
|
Perl_sv_2io(pTHX_ SV *sv)
|
|
{
|
|
IO* io;
|
|
GV* gv;
|
|
STRLEN n_a;
|
|
|
|
switch (SvTYPE(sv)) {
|
|
case SVt_PVIO:
|
|
io = (IO*)sv;
|
|
break;
|
|
case SVt_PVGV:
|
|
gv = (GV*)sv;
|
|
io = GvIO(gv);
|
|
if (!io)
|
|
Perl_croak(aTHX_ "Bad filehandle: %s", GvNAME(gv));
|
|
break;
|
|
default:
|
|
if (!SvOK(sv))
|
|
Perl_croak(aTHX_ PL_no_usym, "filehandle");
|
|
if (SvROK(sv))
|
|
return sv_2io(SvRV(sv));
|
|
gv = gv_fetchpv(SvPV(sv,n_a), FALSE, SVt_PVIO);
|
|
if (gv)
|
|
io = GvIO(gv);
|
|
else
|
|
io = 0;
|
|
if (!io)
|
|
Perl_croak(aTHX_ "Bad filehandle: %s", SvPV(sv,n_a));
|
|
break;
|
|
}
|
|
return io;
|
|
}
|
|
|
|
CV *
|
|
Perl_sv_2cv(pTHX_ SV *sv, HV **st, GV **gvp, I32 lref)
|
|
{
|
|
GV *gv;
|
|
CV *cv;
|
|
STRLEN n_a;
|
|
|
|
if (!sv)
|
|
return *gvp = Nullgv, Nullcv;
|
|
switch (SvTYPE(sv)) {
|
|
case SVt_PVCV:
|
|
*st = CvSTASH(sv);
|
|
*gvp = Nullgv;
|
|
return (CV*)sv;
|
|
case SVt_PVHV:
|
|
case SVt_PVAV:
|
|
*gvp = Nullgv;
|
|
return Nullcv;
|
|
case SVt_PVGV:
|
|
gv = (GV*)sv;
|
|
*gvp = gv;
|
|
*st = GvESTASH(gv);
|
|
goto fix_gv;
|
|
|
|
default:
|
|
if (SvGMAGICAL(sv))
|
|
mg_get(sv);
|
|
if (SvROK(sv)) {
|
|
SV **sp = &sv; /* Used in tryAMAGICunDEREF macro. */
|
|
tryAMAGICunDEREF(to_cv);
|
|
|
|
sv = SvRV(sv);
|
|
if (SvTYPE(sv) == SVt_PVCV) {
|
|
cv = (CV*)sv;
|
|
*gvp = Nullgv;
|
|
*st = CvSTASH(cv);
|
|
return cv;
|
|
}
|
|
else if(isGV(sv))
|
|
gv = (GV*)sv;
|
|
else
|
|
Perl_croak(aTHX_ "Not a subroutine reference");
|
|
}
|
|
else if (isGV(sv))
|
|
gv = (GV*)sv;
|
|
else
|
|
gv = gv_fetchpv(SvPV(sv, n_a), lref, SVt_PVCV);
|
|
*gvp = gv;
|
|
if (!gv)
|
|
return Nullcv;
|
|
*st = GvESTASH(gv);
|
|
fix_gv:
|
|
if (lref && !GvCVu(gv)) {
|
|
SV *tmpsv;
|
|
ENTER;
|
|
tmpsv = NEWSV(704,0);
|
|
gv_efullname3(tmpsv, gv, Nullch);
|
|
/* XXX this is probably not what they think they're getting.
|
|
* It has the same effect as "sub name;", i.e. just a forward
|
|
* declaration! */
|
|
newSUB(start_subparse(FALSE, 0),
|
|
newSVOP(OP_CONST, 0, tmpsv),
|
|
Nullop,
|
|
Nullop);
|
|
LEAVE;
|
|
if (!GvCVu(gv))
|
|
Perl_croak(aTHX_ "Unable to create sub named \"%s\"", SvPV(sv,n_a));
|
|
}
|
|
return GvCVu(gv);
|
|
}
|
|
}
|
|
|
|
/*
|
|
=for apidoc sv_true
|
|
|
|
Returns true if the SV has a true value by Perl's rules.
|
|
|
|
=cut
|
|
*/
|
|
|
|
I32
|
|
Perl_sv_true(pTHX_ register SV *sv)
|
|
{
|
|
if (!sv)
|
|
return 0;
|
|
if (SvPOK(sv)) {
|
|
register XPV* tXpv;
|
|
if ((tXpv = (XPV*)SvANY(sv)) &&
|
|
(tXpv->xpv_cur > 1 ||
|
|
(tXpv->xpv_cur && *tXpv->xpv_pv != '0')))
|
|
return 1;
|
|
else
|
|
return 0;
|
|
}
|
|
else {
|
|
if (SvIOK(sv))
|
|
return SvIVX(sv) != 0;
|
|
else {
|
|
if (SvNOK(sv))
|
|
return SvNVX(sv) != 0.0;
|
|
else
|
|
return sv_2bool(sv);
|
|
}
|
|
}
|
|
}
|
|
|
|
IV
|
|
Perl_sv_iv(pTHX_ register SV *sv)
|
|
{
|
|
if (SvIOK(sv)) {
|
|
if (SvIsUV(sv))
|
|
return (IV)SvUVX(sv);
|
|
return SvIVX(sv);
|
|
}
|
|
return sv_2iv(sv);
|
|
}
|
|
|
|
UV
|
|
Perl_sv_uv(pTHX_ register SV *sv)
|
|
{
|
|
if (SvIOK(sv)) {
|
|
if (SvIsUV(sv))
|
|
return SvUVX(sv);
|
|
return (UV)SvIVX(sv);
|
|
}
|
|
return sv_2uv(sv);
|
|
}
|
|
|
|
NV
|
|
Perl_sv_nv(pTHX_ register SV *sv)
|
|
{
|
|
if (SvNOK(sv))
|
|
return SvNVX(sv);
|
|
return sv_2nv(sv);
|
|
}
|
|
|
|
char *
|
|
Perl_sv_pv(pTHX_ SV *sv)
|
|
{
|
|
STRLEN n_a;
|
|
|
|
if (SvPOK(sv))
|
|
return SvPVX(sv);
|
|
|
|
return sv_2pv(sv, &n_a);
|
|
}
|
|
|
|
char *
|
|
Perl_sv_pvn(pTHX_ SV *sv, STRLEN *lp)
|
|
{
|
|
if (SvPOK(sv)) {
|
|
*lp = SvCUR(sv);
|
|
return SvPVX(sv);
|
|
}
|
|
return sv_2pv(sv, lp);
|
|
}
|
|
|
|
/*
|
|
=for apidoc sv_pvn_force
|
|
|
|
Get a sensible string out of the SV somehow.
|
|
|
|
=cut
|
|
*/
|
|
|
|
char *
|
|
Perl_sv_pvn_force(pTHX_ SV *sv, STRLEN *lp)
|
|
{
|
|
char *s;
|
|
|
|
if (SvTHINKFIRST(sv) && !SvROK(sv))
|
|
sv_force_normal(sv);
|
|
|
|
if (SvPOK(sv)) {
|
|
*lp = SvCUR(sv);
|
|
}
|
|
else {
|
|
if (SvTYPE(sv) > SVt_PVLV && SvTYPE(sv) != SVt_PVFM) {
|
|
Perl_croak(aTHX_ "Can't coerce %s to string in %s", sv_reftype(sv,0),
|
|
PL_op_name[PL_op->op_type]);
|
|
}
|
|
else
|
|
s = sv_2pv(sv, lp);
|
|
if (s != SvPVX(sv)) { /* Almost, but not quite, sv_setpvn() */
|
|
STRLEN len = *lp;
|
|
|
|
if (SvROK(sv))
|
|
sv_unref(sv);
|
|
(void)SvUPGRADE(sv, SVt_PV); /* Never FALSE */
|
|
SvGROW(sv, len + 1);
|
|
Move(s,SvPVX(sv),len,char);
|
|
SvCUR_set(sv, len);
|
|
*SvEND(sv) = '\0';
|
|
}
|
|
if (!SvPOK(sv)) {
|
|
SvPOK_on(sv); /* validate pointer */
|
|
SvTAINT(sv);
|
|
DEBUG_c(PerlIO_printf(Perl_debug_log, "0x%"UVxf" 2pv(%s)\n",
|
|
PTR2UV(sv),SvPVX(sv)));
|
|
}
|
|
}
|
|
return SvPVX(sv);
|
|
}
|
|
|
|
char *
|
|
Perl_sv_pvbyte(pTHX_ SV *sv)
|
|
{
|
|
return sv_pv(sv);
|
|
}
|
|
|
|
char *
|
|
Perl_sv_pvbyten(pTHX_ SV *sv, STRLEN *lp)
|
|
{
|
|
return sv_pvn(sv,lp);
|
|
}
|
|
|
|
char *
|
|
Perl_sv_pvbyten_force(pTHX_ SV *sv, STRLEN *lp)
|
|
{
|
|
return sv_pvn_force(sv,lp);
|
|
}
|
|
|
|
char *
|
|
Perl_sv_pvutf8(pTHX_ SV *sv)
|
|
{
|
|
sv_utf8_upgrade(sv);
|
|
return sv_pv(sv);
|
|
}
|
|
|
|
char *
|
|
Perl_sv_pvutf8n(pTHX_ SV *sv, STRLEN *lp)
|
|
{
|
|
sv_utf8_upgrade(sv);
|
|
return sv_pvn(sv,lp);
|
|
}
|
|
|
|
/*
|
|
=for apidoc sv_pvutf8n_force
|
|
|
|
Get a sensible UTF8-encoded string out of the SV somehow. See
|
|
L</sv_pvn_force>.
|
|
|
|
=cut
|
|
*/
|
|
|
|
char *
|
|
Perl_sv_pvutf8n_force(pTHX_ SV *sv, STRLEN *lp)
|
|
{
|
|
sv_utf8_upgrade(sv);
|
|
return sv_pvn_force(sv,lp);
|
|
}
|
|
|
|
/*
|
|
=for apidoc sv_reftype
|
|
|
|
Returns a string describing what the SV is a reference to.
|
|
|
|
=cut
|
|
*/
|
|
|
|
char *
|
|
Perl_sv_reftype(pTHX_ SV *sv, int ob)
|
|
{
|
|
if (ob && SvOBJECT(sv))
|
|
return HvNAME(SvSTASH(sv));
|
|
else {
|
|
switch (SvTYPE(sv)) {
|
|
case SVt_NULL:
|
|
case SVt_IV:
|
|
case SVt_NV:
|
|
case SVt_RV:
|
|
case SVt_PV:
|
|
case SVt_PVIV:
|
|
case SVt_PVNV:
|
|
case SVt_PVMG:
|
|
case SVt_PVBM:
|
|
if (SvROK(sv))
|
|
return "REF";
|
|
else
|
|
return "SCALAR";
|
|
case SVt_PVLV: return "LVALUE";
|
|
case SVt_PVAV: return "ARRAY";
|
|
case SVt_PVHV: return "HASH";
|
|
case SVt_PVCV: return "CODE";
|
|
case SVt_PVGV: return "GLOB";
|
|
case SVt_PVFM: return "FORMAT";
|
|
case SVt_PVIO: return "IO";
|
|
default: return "UNKNOWN";
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
=for apidoc sv_isobject
|
|
|
|
Returns a boolean indicating whether the SV is an RV pointing to a blessed
|
|
object. If the SV is not an RV, or if the object is not blessed, then this
|
|
will return false.
|
|
|
|
=cut
|
|
*/
|
|
|
|
int
|
|
Perl_sv_isobject(pTHX_ SV *sv)
|
|
{
|
|
if (!sv)
|
|
return 0;
|
|
if (SvGMAGICAL(sv))
|
|
mg_get(sv);
|
|
if (!SvROK(sv))
|
|
return 0;
|
|
sv = (SV*)SvRV(sv);
|
|
if (!SvOBJECT(sv))
|
|
return 0;
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
=for apidoc sv_isa
|
|
|
|
Returns a boolean indicating whether the SV is blessed into the specified
|
|
class. This does not check for subtypes; use C<sv_derived_from> to verify
|
|
an inheritance relationship.
|
|
|
|
=cut
|
|
*/
|
|
|
|
int
|
|
Perl_sv_isa(pTHX_ SV *sv, const char *name)
|
|
{
|
|
if (!sv)
|
|
return 0;
|
|
if (SvGMAGICAL(sv))
|
|
mg_get(sv);
|
|
if (!SvROK(sv))
|
|
return 0;
|
|
sv = (SV*)SvRV(sv);
|
|
if (!SvOBJECT(sv))
|
|
return 0;
|
|
|
|
return strEQ(HvNAME(SvSTASH(sv)), name);
|
|
}
|
|
|
|
/*
|
|
=for apidoc newSVrv
|
|
|
|
Creates a new SV for the RV, C<rv>, to point to. If C<rv> is not an RV then
|
|
it will be upgraded to one. If C<classname> is non-null then the new SV will
|
|
be blessed in the specified package. The new SV is returned and its
|
|
reference count is 1.
|
|
|
|
=cut
|
|
*/
|
|
|
|
SV*
|
|
Perl_newSVrv(pTHX_ SV *rv, const char *classname)
|
|
{
|
|
SV *sv;
|
|
|
|
new_SV(sv);
|
|
|
|
SV_CHECK_THINKFIRST(rv);
|
|
SvAMAGIC_off(rv);
|
|
|
|
if (SvTYPE(rv) >= SVt_PVMG) {
|
|
U32 refcnt = SvREFCNT(rv);
|
|
SvREFCNT(rv) = 0;
|
|
sv_clear(rv);
|
|
SvFLAGS(rv) = 0;
|
|
SvREFCNT(rv) = refcnt;
|
|
}
|
|
|
|
if (SvTYPE(rv) < SVt_RV)
|
|
sv_upgrade(rv, SVt_RV);
|
|
else if (SvTYPE(rv) > SVt_RV) {
|
|
(void)SvOOK_off(rv);
|
|
if (SvPVX(rv) && SvLEN(rv))
|
|
Safefree(SvPVX(rv));
|
|
SvCUR_set(rv, 0);
|
|
SvLEN_set(rv, 0);
|
|
}
|
|
|
|
(void)SvOK_off(rv);
|
|
SvRV(rv) = sv;
|
|
SvROK_on(rv);
|
|
|
|
if (classname) {
|
|
HV* stash = gv_stashpv(classname, TRUE);
|
|
(void)sv_bless(rv, stash);
|
|
}
|
|
return sv;
|
|
}
|
|
|
|
/*
|
|
=for apidoc sv_setref_pv
|
|
|
|
Copies a pointer into a new SV, optionally blessing the SV. The C<rv>
|
|
argument will be upgraded to an RV. That RV will be modified to point to
|
|
the new SV. If the C<pv> argument is NULL then C<PL_sv_undef> will be placed
|
|
into the SV. The C<classname> argument indicates the package for the
|
|
blessing. Set C<classname> to C<Nullch> to avoid the blessing. The new SV
|
|
will be returned and will have a reference count of 1.
|
|
|
|
Do not use with other Perl types such as HV, AV, SV, CV, because those
|
|
objects will become corrupted by the pointer copy process.
|
|
|
|
Note that C<sv_setref_pvn> copies the string while this copies the pointer.
|
|
|
|
=cut
|
|
*/
|
|
|
|
SV*
|
|
Perl_sv_setref_pv(pTHX_ SV *rv, const char *classname, void *pv)
|
|
{
|
|
if (!pv) {
|
|
sv_setsv(rv, &PL_sv_undef);
|
|
SvSETMAGIC(rv);
|
|
}
|
|
else
|
|
sv_setiv(newSVrv(rv,classname), PTR2IV(pv));
|
|
return rv;
|
|
}
|
|
|
|
/*
|
|
=for apidoc sv_setref_iv
|
|
|
|
Copies an integer into a new SV, optionally blessing the SV. The C<rv>
|
|
argument will be upgraded to an RV. That RV will be modified to point to
|
|
the new SV. The C<classname> argument indicates the package for the
|
|
blessing. Set C<classname> to C<Nullch> to avoid the blessing. The new SV
|
|
will be returned and will have a reference count of 1.
|
|
|
|
=cut
|
|
*/
|
|
|
|
SV*
|
|
Perl_sv_setref_iv(pTHX_ SV *rv, const char *classname, IV iv)
|
|
{
|
|
sv_setiv(newSVrv(rv,classname), iv);
|
|
return rv;
|
|
}
|
|
|
|
/*
|
|
=for apidoc sv_setref_nv
|
|
|
|
Copies a double into a new SV, optionally blessing the SV. The C<rv>
|
|
argument will be upgraded to an RV. That RV will be modified to point to
|
|
the new SV. The C<classname> argument indicates the package for the
|
|
blessing. Set C<classname> to C<Nullch> to avoid the blessing. The new SV
|
|
will be returned and will have a reference count of 1.
|
|
|
|
=cut
|
|
*/
|
|
|
|
SV*
|
|
Perl_sv_setref_nv(pTHX_ SV *rv, const char *classname, NV nv)
|
|
{
|
|
sv_setnv(newSVrv(rv,classname), nv);
|
|
return rv;
|
|
}
|
|
|
|
/*
|
|
=for apidoc sv_setref_pvn
|
|
|
|
Copies a string into a new SV, optionally blessing the SV. The length of the
|
|
string must be specified with C<n>. The C<rv> argument will be upgraded to
|
|
an RV. That RV will be modified to point to the new SV. The C<classname>
|
|
argument indicates the package for the blessing. Set C<classname> to
|
|
C<Nullch> to avoid the blessing. The new SV will be returned and will have
|
|
a reference count of 1.
|
|
|
|
Note that C<sv_setref_pv> copies the pointer while this copies the string.
|
|
|
|
=cut
|
|
*/
|
|
|
|
SV*
|
|
Perl_sv_setref_pvn(pTHX_ SV *rv, const char *classname, char *pv, STRLEN n)
|
|
{
|
|
sv_setpvn(newSVrv(rv,classname), pv, n);
|
|
return rv;
|
|
}
|
|
|
|
/*
|
|
=for apidoc sv_bless
|
|
|
|
Blesses an SV into a specified package. The SV must be an RV. The package
|
|
must be designated by its stash (see C<gv_stashpv()>). The reference count
|
|
of the SV is unaffected.
|
|
|
|
=cut
|
|
*/
|
|
|
|
SV*
|
|
Perl_sv_bless(pTHX_ SV *sv, HV *stash)
|
|
{
|
|
SV *tmpRef;
|
|
if (!SvROK(sv))
|
|
Perl_croak(aTHX_ "Can't bless non-reference value");
|
|
tmpRef = SvRV(sv);
|
|
if (SvFLAGS(tmpRef) & (SVs_OBJECT|SVf_READONLY)) {
|
|
if (SvREADONLY(tmpRef))
|
|
Perl_croak(aTHX_ PL_no_modify);
|
|
if (SvOBJECT(tmpRef)) {
|
|
if (SvTYPE(tmpRef) != SVt_PVIO)
|
|
--PL_sv_objcount;
|
|
SvREFCNT_dec(SvSTASH(tmpRef));
|
|
}
|
|
}
|
|
SvOBJECT_on(tmpRef);
|
|
if (SvTYPE(tmpRef) != SVt_PVIO)
|
|
++PL_sv_objcount;
|
|
(void)SvUPGRADE(tmpRef, SVt_PVMG);
|
|
SvSTASH(tmpRef) = (HV*)SvREFCNT_inc(stash);
|
|
|
|
if (Gv_AMG(stash))
|
|
SvAMAGIC_on(sv);
|
|
else
|
|
SvAMAGIC_off(sv);
|
|
|
|
return sv;
|
|
}
|
|
|
|
STATIC void
|
|
S_sv_unglob(pTHX_ SV *sv)
|
|
{
|
|
void *xpvmg;
|
|
|
|
assert(SvTYPE(sv) == SVt_PVGV);
|
|
SvFAKE_off(sv);
|
|
if (GvGP(sv))
|
|
gp_free((GV*)sv);
|
|
if (GvSTASH(sv)) {
|
|
SvREFCNT_dec(GvSTASH(sv));
|
|
GvSTASH(sv) = Nullhv;
|
|
}
|
|
sv_unmagic(sv, '*');
|
|
Safefree(GvNAME(sv));
|
|
GvMULTI_off(sv);
|
|
|
|
/* need to keep SvANY(sv) in the right arena */
|
|
xpvmg = new_XPVMG();
|
|
StructCopy(SvANY(sv), xpvmg, XPVMG);
|
|
del_XPVGV(SvANY(sv));
|
|
SvANY(sv) = xpvmg;
|
|
|
|
SvFLAGS(sv) &= ~SVTYPEMASK;
|
|
SvFLAGS(sv) |= SVt_PVMG;
|
|
}
|
|
|
|
/*
|
|
=for apidoc sv_unref
|
|
|
|
Unsets the RV status of the SV, and decrements the reference count of
|
|
whatever was being referenced by the RV. This can almost be thought of
|
|
as a reversal of C<newSVrv>. See C<SvROK_off>.
|
|
|
|
=cut
|
|
*/
|
|
|
|
void
|
|
Perl_sv_unref(pTHX_ SV *sv)
|
|
{
|
|
SV* rv = SvRV(sv);
|
|
|
|
if (SvWEAKREF(sv)) {
|
|
sv_del_backref(sv);
|
|
SvWEAKREF_off(sv);
|
|
SvRV(sv) = 0;
|
|
return;
|
|
}
|
|
SvRV(sv) = 0;
|
|
SvROK_off(sv);
|
|
if (SvREFCNT(rv) != 1 || SvREADONLY(rv))
|
|
SvREFCNT_dec(rv);
|
|
else
|
|
sv_2mortal(rv); /* Schedule for freeing later */
|
|
}
|
|
|
|
void
|
|
Perl_sv_taint(pTHX_ SV *sv)
|
|
{
|
|
sv_magic((sv), Nullsv, 't', Nullch, 0);
|
|
}
|
|
|
|
void
|
|
Perl_sv_untaint(pTHX_ SV *sv)
|
|
{
|
|
if (SvTYPE(sv) >= SVt_PVMG && SvMAGIC(sv)) {
|
|
MAGIC *mg = mg_find(sv, 't');
|
|
if (mg)
|
|
mg->mg_len &= ~1;
|
|
}
|
|
}
|
|
|
|
bool
|
|
Perl_sv_tainted(pTHX_ SV *sv)
|
|
{
|
|
if (SvTYPE(sv) >= SVt_PVMG && SvMAGIC(sv)) {
|
|
MAGIC *mg = mg_find(sv, 't');
|
|
if (mg && ((mg->mg_len & 1) || ((mg->mg_len & 2) && mg->mg_obj == sv)))
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
=for apidoc sv_setpviv
|
|
|
|
Copies an integer into the given SV, also updating its string value.
|
|
Does not handle 'set' magic. See C<sv_setpviv_mg>.
|
|
|
|
=cut
|
|
*/
|
|
|
|
void
|
|
Perl_sv_setpviv(pTHX_ SV *sv, IV iv)
|
|
{
|
|
char buf[TYPE_CHARS(UV)];
|
|
char *ebuf;
|
|
char *ptr = uiv_2buf(buf, iv, 0, 0, &ebuf);
|
|
|
|
sv_setpvn(sv, ptr, ebuf - ptr);
|
|
}
|
|
|
|
|
|
/*
|
|
=for apidoc sv_setpviv_mg
|
|
|
|
Like C<sv_setpviv>, but also handles 'set' magic.
|
|
|
|
=cut
|
|
*/
|
|
|
|
void
|
|
Perl_sv_setpviv_mg(pTHX_ SV *sv, IV iv)
|
|
{
|
|
char buf[TYPE_CHARS(UV)];
|
|
char *ebuf;
|
|
char *ptr = uiv_2buf(buf, iv, 0, 0, &ebuf);
|
|
|
|
sv_setpvn(sv, ptr, ebuf - ptr);
|
|
SvSETMAGIC(sv);
|
|
}
|
|
|
|
#if defined(PERL_IMPLICIT_CONTEXT)
|
|
void
|
|
Perl_sv_setpvf_nocontext(SV *sv, const char* pat, ...)
|
|
{
|
|
dTHX;
|
|
va_list args;
|
|
va_start(args, pat);
|
|
sv_vsetpvf(sv, pat, &args);
|
|
va_end(args);
|
|
}
|
|
|
|
|
|
void
|
|
Perl_sv_setpvf_mg_nocontext(SV *sv, const char* pat, ...)
|
|
{
|
|
dTHX;
|
|
va_list args;
|
|
va_start(args, pat);
|
|
sv_vsetpvf_mg(sv, pat, &args);
|
|
va_end(args);
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
=for apidoc sv_setpvf
|
|
|
|
Processes its arguments like C<sprintf> and sets an SV to the formatted
|
|
output. Does not handle 'set' magic. See C<sv_setpvf_mg>.
|
|
|
|
=cut
|
|
*/
|
|
|
|
void
|
|
Perl_sv_setpvf(pTHX_ SV *sv, const char* pat, ...)
|
|
{
|
|
va_list args;
|
|
va_start(args, pat);
|
|
sv_vsetpvf(sv, pat, &args);
|
|
va_end(args);
|
|
}
|
|
|
|
void
|
|
Perl_sv_vsetpvf(pTHX_ SV *sv, const char* pat, va_list* args)
|
|
{
|
|
sv_vsetpvfn(sv, pat, strlen(pat), args, Null(SV**), 0, Null(bool*));
|
|
}
|
|
|
|
/*
|
|
=for apidoc sv_setpvf_mg
|
|
|
|
Like C<sv_setpvf>, but also handles 'set' magic.
|
|
|
|
=cut
|
|
*/
|
|
|
|
void
|
|
Perl_sv_setpvf_mg(pTHX_ SV *sv, const char* pat, ...)
|
|
{
|
|
va_list args;
|
|
va_start(args, pat);
|
|
sv_vsetpvf_mg(sv, pat, &args);
|
|
va_end(args);
|
|
}
|
|
|
|
void
|
|
Perl_sv_vsetpvf_mg(pTHX_ SV *sv, const char* pat, va_list* args)
|
|
{
|
|
sv_vsetpvfn(sv, pat, strlen(pat), args, Null(SV**), 0, Null(bool*));
|
|
SvSETMAGIC(sv);
|
|
}
|
|
|
|
#if defined(PERL_IMPLICIT_CONTEXT)
|
|
void
|
|
Perl_sv_catpvf_nocontext(SV *sv, const char* pat, ...)
|
|
{
|
|
dTHX;
|
|
va_list args;
|
|
va_start(args, pat);
|
|
sv_vcatpvf(sv, pat, &args);
|
|
va_end(args);
|
|
}
|
|
|
|
void
|
|
Perl_sv_catpvf_mg_nocontext(SV *sv, const char* pat, ...)
|
|
{
|
|
dTHX;
|
|
va_list args;
|
|
va_start(args, pat);
|
|
sv_vcatpvf_mg(sv, pat, &args);
|
|
va_end(args);
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
=for apidoc sv_catpvf
|
|
|
|
Processes its arguments like C<sprintf> and appends the formatted output
|
|
to an SV. Handles 'get' magic, but not 'set' magic. C<SvSETMAGIC()> must
|
|
typically be called after calling this function to handle 'set' magic.
|
|
|
|
=cut
|
|
*/
|
|
|
|
void
|
|
Perl_sv_catpvf(pTHX_ SV *sv, const char* pat, ...)
|
|
{
|
|
va_list args;
|
|
va_start(args, pat);
|
|
sv_vcatpvf(sv, pat, &args);
|
|
va_end(args);
|
|
}
|
|
|
|
void
|
|
Perl_sv_vcatpvf(pTHX_ SV *sv, const char* pat, va_list* args)
|
|
{
|
|
sv_vcatpvfn(sv, pat, strlen(pat), args, Null(SV**), 0, Null(bool*));
|
|
}
|
|
|
|
/*
|
|
=for apidoc sv_catpvf_mg
|
|
|
|
Like C<sv_catpvf>, but also handles 'set' magic.
|
|
|
|
=cut
|
|
*/
|
|
|
|
void
|
|
Perl_sv_catpvf_mg(pTHX_ SV *sv, const char* pat, ...)
|
|
{
|
|
va_list args;
|
|
va_start(args, pat);
|
|
sv_vcatpvf_mg(sv, pat, &args);
|
|
va_end(args);
|
|
}
|
|
|
|
void
|
|
Perl_sv_vcatpvf_mg(pTHX_ SV *sv, const char* pat, va_list* args)
|
|
{
|
|
sv_vcatpvfn(sv, pat, strlen(pat), args, Null(SV**), 0, Null(bool*));
|
|
SvSETMAGIC(sv);
|
|
}
|
|
|
|
/*
|
|
=for apidoc sv_vsetpvfn
|
|
|
|
Works like C<vcatpvfn> but copies the text into the SV instead of
|
|
appending it.
|
|
|
|
=cut
|
|
*/
|
|
|
|
void
|
|
Perl_sv_vsetpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV **svargs, I32 svmax, bool *maybe_tainted)
|
|
{
|
|
sv_setpvn(sv, "", 0);
|
|
sv_vcatpvfn(sv, pat, patlen, args, svargs, svmax, maybe_tainted);
|
|
}
|
|
|
|
/*
|
|
=for apidoc sv_vcatpvfn
|
|
|
|
Processes its arguments like C<vsprintf> and appends the formatted output
|
|
to an SV. Uses an array of SVs if the C style variable argument list is
|
|
missing (NULL). When running with taint checks enabled, indicates via
|
|
C<maybe_tainted> if results are untrustworthy (often due to the use of
|
|
locales).
|
|
|
|
=cut
|
|
*/
|
|
|
|
void
|
|
Perl_sv_vcatpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV **svargs, I32 svmax, bool *maybe_tainted)
|
|
{
|
|
char *p;
|
|
char *q;
|
|
char *patend;
|
|
STRLEN origlen;
|
|
I32 svix = 0;
|
|
static char nullstr[] = "(null)";
|
|
SV *argsv;
|
|
|
|
/* no matter what, this is a string now */
|
|
(void)SvPV_force(sv, origlen);
|
|
|
|
/* special-case "", "%s", and "%_" */
|
|
if (patlen == 0)
|
|
return;
|
|
if (patlen == 2 && pat[0] == '%') {
|
|
switch (pat[1]) {
|
|
case 's':
|
|
if (args) {
|
|
char *s = va_arg(*args, char*);
|
|
sv_catpv(sv, s ? s : nullstr);
|
|
}
|
|
else if (svix < svmax) {
|
|
sv_catsv(sv, *svargs);
|
|
if (DO_UTF8(*svargs))
|
|
SvUTF8_on(sv);
|
|
}
|
|
return;
|
|
case '_':
|
|
if (args) {
|
|
argsv = va_arg(*args, SV*);
|
|
sv_catsv(sv, argsv);
|
|
if (DO_UTF8(argsv))
|
|
SvUTF8_on(sv);
|
|
return;
|
|
}
|
|
/* See comment on '_' below */
|
|
break;
|
|
}
|
|
}
|
|
|
|
patend = (char*)pat + patlen;
|
|
for (p = (char*)pat; p < patend; p = q) {
|
|
bool alt = FALSE;
|
|
bool left = FALSE;
|
|
bool vectorize = FALSE;
|
|
bool utf = FALSE;
|
|
char fill = ' ';
|
|
char plus = 0;
|
|
char intsize = 0;
|
|
STRLEN width = 0;
|
|
STRLEN zeros = 0;
|
|
bool has_precis = FALSE;
|
|
STRLEN precis = 0;
|
|
bool is_utf = FALSE;
|
|
|
|
char esignbuf[4];
|
|
U8 utf8buf[UTF8_MAXLEN+1];
|
|
STRLEN esignlen = 0;
|
|
|
|
char *eptr = Nullch;
|
|
STRLEN elen = 0;
|
|
/* Times 4: a decimal digit takes more than 3 binary digits.
|
|
* NV_DIG: mantissa takes than many decimal digits.
|
|
* Plus 32: Playing safe. */
|
|
char ebuf[IV_DIG * 4 + NV_DIG + 32];
|
|
/* large enough for "%#.#f" --chip */
|
|
/* what about long double NVs? --jhi */
|
|
|
|
SV *vecsv;
|
|
U8 *vecstr = Null(U8*);
|
|
STRLEN veclen = 0;
|
|
char c;
|
|
int i;
|
|
unsigned base;
|
|
IV iv;
|
|
UV uv;
|
|
NV nv;
|
|
STRLEN have;
|
|
STRLEN need;
|
|
STRLEN gap;
|
|
char *dotstr = ".";
|
|
STRLEN dotstrlen = 1;
|
|
|
|
for (q = p; q < patend && *q != '%'; ++q) ;
|
|
if (q > p) {
|
|
sv_catpvn(sv, p, q - p);
|
|
p = q;
|
|
}
|
|
if (q++ >= patend)
|
|
break;
|
|
|
|
/* FLAGS */
|
|
|
|
while (*q) {
|
|
switch (*q) {
|
|
case ' ':
|
|
case '+':
|
|
plus = *q++;
|
|
continue;
|
|
|
|
case '-':
|
|
left = TRUE;
|
|
q++;
|
|
continue;
|
|
|
|
case '0':
|
|
fill = *q++;
|
|
continue;
|
|
|
|
case '#':
|
|
alt = TRUE;
|
|
q++;
|
|
continue;
|
|
|
|
case '*': /* printf("%*vX",":",$ipv6addr) */
|
|
if (q[1] != 'v')
|
|
break;
|
|
q++;
|
|
if (args)
|
|
vecsv = va_arg(*args, SV*);
|
|
else if (svix < svmax)
|
|
vecsv = svargs[svix++];
|
|
else
|
|
continue;
|
|
dotstr = SvPVx(vecsv,dotstrlen);
|
|
if (DO_UTF8(vecsv))
|
|
is_utf = TRUE;
|
|
/* FALL THROUGH */
|
|
|
|
case 'v':
|
|
vectorize = TRUE;
|
|
q++;
|
|
continue;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
|
|
/* WIDTH */
|
|
|
|
switch (*q) {
|
|
case '1': case '2': case '3':
|
|
case '4': case '5': case '6':
|
|
case '7': case '8': case '9':
|
|
width = 0;
|
|
while (isDIGIT(*q))
|
|
width = width * 10 + (*q++ - '0');
|
|
break;
|
|
|
|
case '*':
|
|
if (args)
|
|
i = va_arg(*args, int);
|
|
else
|
|
i = (svix < svmax) ? SvIVx(svargs[svix++]) : 0;
|
|
left |= (i < 0);
|
|
width = (i < 0) ? -i : i;
|
|
q++;
|
|
break;
|
|
}
|
|
|
|
/* PRECISION */
|
|
|
|
if (*q == '.') {
|
|
q++;
|
|
if (*q == '*') {
|
|
if (args)
|
|
i = va_arg(*args, int);
|
|
else
|
|
i = (svix < svmax) ? SvIVx(svargs[svix++]) : 0;
|
|
precis = (i < 0) ? 0 : i;
|
|
q++;
|
|
}
|
|
else {
|
|
precis = 0;
|
|
while (isDIGIT(*q))
|
|
precis = precis * 10 + (*q++ - '0');
|
|
}
|
|
has_precis = TRUE;
|
|
}
|
|
|
|
if (vectorize) {
|
|
if (args) {
|
|
vecsv = va_arg(*args, SV*);
|
|
vecstr = (U8*)SvPVx(vecsv,veclen);
|
|
utf = DO_UTF8(vecsv);
|
|
}
|
|
else if (svix < svmax) {
|
|
vecsv = svargs[svix++];
|
|
vecstr = (U8*)SvPVx(vecsv,veclen);
|
|
utf = DO_UTF8(vecsv);
|
|
}
|
|
else {
|
|
vecstr = (U8*)"";
|
|
veclen = 0;
|
|
}
|
|
}
|
|
|
|
/* SIZE */
|
|
|
|
switch (*q) {
|
|
#if defined(HAS_QUAD) || (defined(HAS_LONG_DOUBLE) && defined(USE_LONG_DOUBLE))
|
|
case 'L': /* Ld */
|
|
/* FALL THROUGH */
|
|
#endif
|
|
#ifdef HAS_QUAD
|
|
case 'q': /* qd */
|
|
intsize = 'q';
|
|
q++;
|
|
break;
|
|
#endif
|
|
case 'l':
|
|
#if defined(HAS_QUAD) || (defined(HAS_LONG_DOUBLE) && defined(USE_LONG_DOUBLE))
|
|
if (*(q + 1) == 'l') { /* lld, llf */
|
|
intsize = 'q';
|
|
q += 2;
|
|
break;
|
|
}
|
|
#endif
|
|
/* FALL THROUGH */
|
|
case 'h':
|
|
/* FALL THROUGH */
|
|
case 'V':
|
|
intsize = *q++;
|
|
break;
|
|
}
|
|
|
|
/* CONVERSION */
|
|
|
|
switch (c = *q++) {
|
|
|
|
/* STRINGS */
|
|
|
|
case '%':
|
|
eptr = q - 1;
|
|
elen = 1;
|
|
goto string;
|
|
|
|
case 'c':
|
|
if (args)
|
|
uv = va_arg(*args, int);
|
|
else
|
|
uv = (svix < svmax) ? SvIVx(svargs[svix++]) : 0;
|
|
if ((uv > 255 || (uv > 127 && SvUTF8(sv))) && !IN_BYTE) {
|
|
eptr = (char*)utf8buf;
|
|
elen = uv_to_utf8((U8*)eptr, uv) - utf8buf;
|
|
is_utf = TRUE;
|
|
}
|
|
else {
|
|
c = (char)uv;
|
|
eptr = &c;
|
|
elen = 1;
|
|
}
|
|
goto string;
|
|
|
|
case 's':
|
|
if (args) {
|
|
eptr = va_arg(*args, char*);
|
|
if (eptr)
|
|
#ifdef MACOS_TRADITIONAL
|
|
/* On MacOS, %#s format is used for Pascal strings */
|
|
if (alt)
|
|
elen = *eptr++;
|
|
else
|
|
#endif
|
|
elen = strlen(eptr);
|
|
else {
|
|
eptr = nullstr;
|
|
elen = sizeof nullstr - 1;
|
|
}
|
|
}
|
|
else if (svix < svmax) {
|
|
argsv = svargs[svix++];
|
|
eptr = SvPVx(argsv, elen);
|
|
if (DO_UTF8(argsv)) {
|
|
if (has_precis && precis < elen) {
|
|
I32 p = precis;
|
|
sv_pos_u2b(argsv, &p, 0); /* sticks at end */
|
|
precis = p;
|
|
}
|
|
if (width) { /* fudge width (can't fudge elen) */
|
|
width += elen - sv_len_utf8(argsv);
|
|
}
|
|
is_utf = TRUE;
|
|
}
|
|
}
|
|
goto string;
|
|
|
|
case '_':
|
|
/*
|
|
* The "%_" hack might have to be changed someday,
|
|
* if ISO or ANSI decide to use '_' for something.
|
|
* So we keep it hidden from users' code.
|
|
*/
|
|
if (!args)
|
|
goto unknown;
|
|
argsv = va_arg(*args,SV*);
|
|
eptr = SvPVx(argsv, elen);
|
|
if (DO_UTF8(argsv))
|
|
is_utf = TRUE;
|
|
|
|
string:
|
|
vectorize = FALSE;
|
|
if (has_precis && elen > precis)
|
|
elen = precis;
|
|
break;
|
|
|
|
/* INTEGERS */
|
|
|
|
case 'p':
|
|
if (alt)
|
|
goto unknown;
|
|
if (args)
|
|
uv = PTR2UV(va_arg(*args, void*));
|
|
else
|
|
uv = (svix < svmax) ? PTR2UV(svargs[svix++]) : 0;
|
|
base = 16;
|
|
goto integer;
|
|
|
|
case 'D':
|
|
#ifdef IV_IS_QUAD
|
|
intsize = 'q';
|
|
#else
|
|
intsize = 'l';
|
|
#endif
|
|
/* FALL THROUGH */
|
|
case 'd':
|
|
case 'i':
|
|
if (vectorize) {
|
|
STRLEN ulen;
|
|
if (!veclen) {
|
|
vectorize = FALSE;
|
|
break;
|
|
}
|
|
if (utf)
|
|
iv = (IV)utf8_to_uv(vecstr, veclen, &ulen, 0);
|
|
else {
|
|
iv = *vecstr;
|
|
ulen = 1;
|
|
}
|
|
vecstr += ulen;
|
|
veclen -= ulen;
|
|
}
|
|
else if (args) {
|
|
switch (intsize) {
|
|
case 'h': iv = (short)va_arg(*args, int); break;
|
|
default: iv = va_arg(*args, int); break;
|
|
case 'l': iv = va_arg(*args, long); break;
|
|
case 'V': iv = va_arg(*args, IV); break;
|
|
#ifdef HAS_QUAD
|
|
case 'q': iv = va_arg(*args, Quad_t); break;
|
|
#endif
|
|
}
|
|
}
|
|
else {
|
|
iv = (svix < svmax) ? SvIVx(svargs[svix++]) : 0;
|
|
switch (intsize) {
|
|
case 'h': iv = (short)iv; break;
|
|
default: break;
|
|
case 'l': iv = (long)iv; break;
|
|
case 'V': break;
|
|
#ifdef HAS_QUAD
|
|
case 'q': iv = (Quad_t)iv; break;
|
|
#endif
|
|
}
|
|
}
|
|
if (iv >= 0) {
|
|
uv = iv;
|
|
if (plus)
|
|
esignbuf[esignlen++] = plus;
|
|
}
|
|
else {
|
|
uv = -iv;
|
|
esignbuf[esignlen++] = '-';
|
|
}
|
|
base = 10;
|
|
goto integer;
|
|
|
|
case 'U':
|
|
#ifdef IV_IS_QUAD
|
|
intsize = 'q';
|
|
#else
|
|
intsize = 'l';
|
|
#endif
|
|
/* FALL THROUGH */
|
|
case 'u':
|
|
base = 10;
|
|
goto uns_integer;
|
|
|
|
case 'b':
|
|
base = 2;
|
|
goto uns_integer;
|
|
|
|
case 'O':
|
|
#ifdef IV_IS_QUAD
|
|
intsize = 'q';
|
|
#else
|
|
intsize = 'l';
|
|
#endif
|
|
/* FALL THROUGH */
|
|
case 'o':
|
|
base = 8;
|
|
goto uns_integer;
|
|
|
|
case 'X':
|
|
case 'x':
|
|
base = 16;
|
|
|
|
uns_integer:
|
|
if (vectorize) {
|
|
STRLEN ulen;
|
|
vector:
|
|
if (!veclen) {
|
|
vectorize = FALSE;
|
|
break;
|
|
}
|
|
if (utf)
|
|
uv = utf8_to_uv(vecstr, veclen, &ulen, 0);
|
|
else {
|
|
uv = *vecstr;
|
|
ulen = 1;
|
|
}
|
|
vecstr += ulen;
|
|
veclen -= ulen;
|
|
}
|
|
else if (args) {
|
|
switch (intsize) {
|
|
case 'h': uv = (unsigned short)va_arg(*args, unsigned); break;
|
|
default: uv = va_arg(*args, unsigned); break;
|
|
case 'l': uv = va_arg(*args, unsigned long); break;
|
|
case 'V': uv = va_arg(*args, UV); break;
|
|
#ifdef HAS_QUAD
|
|
case 'q': uv = va_arg(*args, Quad_t); break;
|
|
#endif
|
|
}
|
|
}
|
|
else {
|
|
uv = (svix < svmax) ? SvUVx(svargs[svix++]) : 0;
|
|
switch (intsize) {
|
|
case 'h': uv = (unsigned short)uv; break;
|
|
default: break;
|
|
case 'l': uv = (unsigned long)uv; break;
|
|
case 'V': break;
|
|
#ifdef HAS_QUAD
|
|
case 'q': uv = (Quad_t)uv; break;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
integer:
|
|
eptr = ebuf + sizeof ebuf;
|
|
switch (base) {
|
|
unsigned dig;
|
|
case 16:
|
|
if (!uv)
|
|
alt = FALSE;
|
|
p = (char*)((c == 'X')
|
|
? "0123456789ABCDEF" : "0123456789abcdef");
|
|
do {
|
|
dig = uv & 15;
|
|
*--eptr = p[dig];
|
|
} while (uv >>= 4);
|
|
if (alt) {
|
|
esignbuf[esignlen++] = '0';
|
|
esignbuf[esignlen++] = c; /* 'x' or 'X' */
|
|
}
|
|
break;
|
|
case 8:
|
|
do {
|
|
dig = uv & 7;
|
|
*--eptr = '0' + dig;
|
|
} while (uv >>= 3);
|
|
if (alt && *eptr != '0')
|
|
*--eptr = '0';
|
|
break;
|
|
case 2:
|
|
do {
|
|
dig = uv & 1;
|
|
*--eptr = '0' + dig;
|
|
} while (uv >>= 1);
|
|
if (alt) {
|
|
esignbuf[esignlen++] = '0';
|
|
esignbuf[esignlen++] = 'b';
|
|
}
|
|
break;
|
|
default: /* it had better be ten or less */
|
|
#if defined(PERL_Y2KWARN)
|
|
if (ckWARN(WARN_Y2K)) {
|
|
STRLEN n;
|
|
char *s = SvPV(sv,n);
|
|
if (n >= 2 && s[n-2] == '1' && s[n-1] == '9'
|
|
&& (n == 2 || !isDIGIT(s[n-3])))
|
|
{
|
|
Perl_warner(aTHX_ WARN_Y2K,
|
|
"Possible Y2K bug: %%%c %s",
|
|
c, "format string following '19'");
|
|
}
|
|
}
|
|
#endif
|
|
do {
|
|
dig = uv % base;
|
|
*--eptr = '0' + dig;
|
|
} while (uv /= base);
|
|
break;
|
|
}
|
|
elen = (ebuf + sizeof ebuf) - eptr;
|
|
if (has_precis) {
|
|
if (precis > elen)
|
|
zeros = precis - elen;
|
|
else if (precis == 0 && elen == 1 && *eptr == '0')
|
|
elen = 0;
|
|
}
|
|
break;
|
|
|
|
/* FLOATING POINT */
|
|
|
|
case 'F':
|
|
c = 'f'; /* maybe %F isn't supported here */
|
|
/* FALL THROUGH */
|
|
case 'e': case 'E':
|
|
case 'f':
|
|
case 'g': case 'G':
|
|
|
|
/* This is evil, but floating point is even more evil */
|
|
|
|
vectorize = FALSE;
|
|
if (args)
|
|
nv = va_arg(*args, NV);
|
|
else
|
|
nv = (svix < svmax) ? SvNVx(svargs[svix++]) : 0.0;
|
|
|
|
need = 0;
|
|
if (c != 'e' && c != 'E') {
|
|
i = PERL_INT_MIN;
|
|
(void)Perl_frexp(nv, &i);
|
|
if (i == PERL_INT_MIN)
|
|
Perl_die(aTHX_ "panic: frexp");
|
|
if (i > 0)
|
|
need = BIT_DIGITS(i);
|
|
}
|
|
need += has_precis ? precis : 6; /* known default */
|
|
if (need < width)
|
|
need = width;
|
|
|
|
need += 20; /* fudge factor */
|
|
if (PL_efloatsize < need) {
|
|
Safefree(PL_efloatbuf);
|
|
PL_efloatsize = need + 20; /* more fudge */
|
|
New(906, PL_efloatbuf, PL_efloatsize, char);
|
|
PL_efloatbuf[0] = '\0';
|
|
}
|
|
|
|
eptr = ebuf + sizeof ebuf;
|
|
*--eptr = '\0';
|
|
*--eptr = c;
|
|
#if defined(USE_LONG_DOUBLE) && defined(PERL_PRIfldbl)
|
|
{
|
|
/* Copy the one or more characters in a long double
|
|
* format before the 'base' ([efgEFG]) character to
|
|
* the format string. */
|
|
static char const prifldbl[] = PERL_PRIfldbl;
|
|
char const *p = prifldbl + sizeof(prifldbl) - 3;
|
|
while (p >= prifldbl) { *--eptr = *p--; }
|
|
}
|
|
#endif
|
|
if (has_precis) {
|
|
base = precis;
|
|
do { *--eptr = '0' + (base % 10); } while (base /= 10);
|
|
*--eptr = '.';
|
|
}
|
|
if (width) {
|
|
base = width;
|
|
do { *--eptr = '0' + (base % 10); } while (base /= 10);
|
|
}
|
|
if (fill == '0')
|
|
*--eptr = fill;
|
|
if (left)
|
|
*--eptr = '-';
|
|
if (plus)
|
|
*--eptr = plus;
|
|
if (alt)
|
|
*--eptr = '#';
|
|
*--eptr = '%';
|
|
|
|
/* No taint. Otherwise we are in the strange situation
|
|
* where printf() taints but print($float) doesn't.
|
|
* --jhi */
|
|
(void)sprintf(PL_efloatbuf, eptr, nv);
|
|
|
|
eptr = PL_efloatbuf;
|
|
elen = strlen(PL_efloatbuf);
|
|
break;
|
|
|
|
/* SPECIAL */
|
|
|
|
case 'n':
|
|
vectorize = FALSE;
|
|
i = SvCUR(sv) - origlen;
|
|
if (args) {
|
|
switch (intsize) {
|
|
case 'h': *(va_arg(*args, short*)) = i; break;
|
|
default: *(va_arg(*args, int*)) = i; break;
|
|
case 'l': *(va_arg(*args, long*)) = i; break;
|
|
case 'V': *(va_arg(*args, IV*)) = i; break;
|
|
#ifdef HAS_QUAD
|
|
case 'q': *(va_arg(*args, Quad_t*)) = i; break;
|
|
#endif
|
|
}
|
|
}
|
|
else if (svix < svmax)
|
|
sv_setuv_mg(svargs[svix++], (UV)i);
|
|
continue; /* not "break" */
|
|
|
|
/* UNKNOWN */
|
|
|
|
default:
|
|
unknown:
|
|
vectorize = FALSE;
|
|
if (!args && ckWARN(WARN_PRINTF) &&
|
|
(PL_op->op_type == OP_PRTF || PL_op->op_type == OP_SPRINTF)) {
|
|
SV *msg = sv_newmortal();
|
|
Perl_sv_setpvf(aTHX_ msg, "Invalid conversion in %s: ",
|
|
(PL_op->op_type == OP_PRTF) ? "printf" : "sprintf");
|
|
if (c) {
|
|
if (isPRINT(c))
|
|
Perl_sv_catpvf(aTHX_ msg,
|
|
"\"%%%c\"", c & 0xFF);
|
|
else
|
|
Perl_sv_catpvf(aTHX_ msg,
|
|
"\"%%\\%03"UVof"\"",
|
|
(UV)c & 0xFF);
|
|
} else
|
|
sv_catpv(msg, "end of string");
|
|
Perl_warner(aTHX_ WARN_PRINTF, "%"SVf, msg); /* yes, this is reentrant */
|
|
}
|
|
|
|
/* output mangled stuff ... */
|
|
if (c == '\0')
|
|
--q;
|
|
eptr = p;
|
|
elen = q - p;
|
|
|
|
/* ... right here, because formatting flags should not apply */
|
|
SvGROW(sv, SvCUR(sv) + elen + 1);
|
|
p = SvEND(sv);
|
|
memcpy(p, eptr, elen);
|
|
p += elen;
|
|
*p = '\0';
|
|
SvCUR(sv) = p - SvPVX(sv);
|
|
continue; /* not "break" */
|
|
}
|
|
|
|
have = esignlen + zeros + elen;
|
|
need = (have > width ? have : width);
|
|
gap = need - have;
|
|
|
|
SvGROW(sv, SvCUR(sv) + need + dotstrlen + 1);
|
|
p = SvEND(sv);
|
|
if (esignlen && fill == '0') {
|
|
for (i = 0; i < esignlen; i++)
|
|
*p++ = esignbuf[i];
|
|
}
|
|
if (gap && !left) {
|
|
memset(p, fill, gap);
|
|
p += gap;
|
|
}
|
|
if (esignlen && fill != '0') {
|
|
for (i = 0; i < esignlen; i++)
|
|
*p++ = esignbuf[i];
|
|
}
|
|
if (zeros) {
|
|
for (i = zeros; i; i--)
|
|
*p++ = '0';
|
|
}
|
|
if (elen) {
|
|
memcpy(p, eptr, elen);
|
|
p += elen;
|
|
}
|
|
if (gap && left) {
|
|
memset(p, ' ', gap);
|
|
p += gap;
|
|
}
|
|
if (vectorize) {
|
|
if (veclen) {
|
|
memcpy(p, dotstr, dotstrlen);
|
|
p += dotstrlen;
|
|
}
|
|
else
|
|
vectorize = FALSE; /* done iterating over vecstr */
|
|
}
|
|
if (is_utf)
|
|
SvUTF8_on(sv);
|
|
*p = '\0';
|
|
SvCUR(sv) = p - SvPVX(sv);
|
|
if (vectorize) {
|
|
esignlen = 0;
|
|
goto vector;
|
|
}
|
|
}
|
|
}
|
|
|
|
#if defined(USE_ITHREADS)
|
|
|
|
#if defined(USE_THREADS)
|
|
# include "error: USE_THREADS and USE_ITHREADS are incompatible"
|
|
#endif
|
|
|
|
#ifndef GpREFCNT_inc
|
|
# define GpREFCNT_inc(gp) ((gp) ? (++(gp)->gp_refcnt, (gp)) : (GP*)NULL)
|
|
#endif
|
|
|
|
|
|
#define sv_dup_inc(s) SvREFCNT_inc(sv_dup(s))
|
|
#define av_dup(s) (AV*)sv_dup((SV*)s)
|
|
#define av_dup_inc(s) (AV*)SvREFCNT_inc(sv_dup((SV*)s))
|
|
#define hv_dup(s) (HV*)sv_dup((SV*)s)
|
|
#define hv_dup_inc(s) (HV*)SvREFCNT_inc(sv_dup((SV*)s))
|
|
#define cv_dup(s) (CV*)sv_dup((SV*)s)
|
|
#define cv_dup_inc(s) (CV*)SvREFCNT_inc(sv_dup((SV*)s))
|
|
#define io_dup(s) (IO*)sv_dup((SV*)s)
|
|
#define io_dup_inc(s) (IO*)SvREFCNT_inc(sv_dup((SV*)s))
|
|
#define gv_dup(s) (GV*)sv_dup((SV*)s)
|
|
#define gv_dup_inc(s) (GV*)SvREFCNT_inc(sv_dup((SV*)s))
|
|
#define SAVEPV(p) (p ? savepv(p) : Nullch)
|
|
#define SAVEPVN(p,n) (p ? savepvn(p,n) : Nullch)
|
|
|
|
REGEXP *
|
|
Perl_re_dup(pTHX_ REGEXP *r)
|
|
{
|
|
/* XXX fix when pmop->op_pmregexp becomes shared */
|
|
return ReREFCNT_inc(r);
|
|
}
|
|
|
|
PerlIO *
|
|
Perl_fp_dup(pTHX_ PerlIO *fp, char type)
|
|
{
|
|
PerlIO *ret;
|
|
if (!fp)
|
|
return (PerlIO*)NULL;
|
|
|
|
/* look for it in the table first */
|
|
ret = (PerlIO*)ptr_table_fetch(PL_ptr_table, fp);
|
|
if (ret)
|
|
return ret;
|
|
|
|
/* create anew and remember what it is */
|
|
ret = PerlIO_fdupopen(fp);
|
|
ptr_table_store(PL_ptr_table, fp, ret);
|
|
return ret;
|
|
}
|
|
|
|
DIR *
|
|
Perl_dirp_dup(pTHX_ DIR *dp)
|
|
{
|
|
if (!dp)
|
|
return (DIR*)NULL;
|
|
/* XXX TODO */
|
|
return dp;
|
|
}
|
|
|
|
GP *
|
|
Perl_gp_dup(pTHX_ GP *gp)
|
|
{
|
|
GP *ret;
|
|
if (!gp)
|
|
return (GP*)NULL;
|
|
/* look for it in the table first */
|
|
ret = (GP*)ptr_table_fetch(PL_ptr_table, gp);
|
|
if (ret)
|
|
return ret;
|
|
|
|
/* create anew and remember what it is */
|
|
Newz(0, ret, 1, GP);
|
|
ptr_table_store(PL_ptr_table, gp, ret);
|
|
|
|
/* clone */
|
|
ret->gp_refcnt = 0; /* must be before any other dups! */
|
|
ret->gp_sv = sv_dup_inc(gp->gp_sv);
|
|
ret->gp_io = io_dup_inc(gp->gp_io);
|
|
ret->gp_form = cv_dup_inc(gp->gp_form);
|
|
ret->gp_av = av_dup_inc(gp->gp_av);
|
|
ret->gp_hv = hv_dup_inc(gp->gp_hv);
|
|
ret->gp_egv = gv_dup(gp->gp_egv); /* GvEGV is not refcounted */
|
|
ret->gp_cv = cv_dup_inc(gp->gp_cv);
|
|
ret->gp_cvgen = gp->gp_cvgen;
|
|
ret->gp_flags = gp->gp_flags;
|
|
ret->gp_line = gp->gp_line;
|
|
ret->gp_file = gp->gp_file; /* points to COP.cop_file */
|
|
return ret;
|
|
}
|
|
|
|
MAGIC *
|
|
Perl_mg_dup(pTHX_ MAGIC *mg)
|
|
{
|
|
MAGIC *mgprev = (MAGIC*)NULL;
|
|
MAGIC *mgret;
|
|
if (!mg)
|
|
return (MAGIC*)NULL;
|
|
/* look for it in the table first */
|
|
mgret = (MAGIC*)ptr_table_fetch(PL_ptr_table, mg);
|
|
if (mgret)
|
|
return mgret;
|
|
|
|
for (; mg; mg = mg->mg_moremagic) {
|
|
MAGIC *nmg;
|
|
Newz(0, nmg, 1, MAGIC);
|
|
if (mgprev)
|
|
mgprev->mg_moremagic = nmg;
|
|
else
|
|
mgret = nmg;
|
|
nmg->mg_virtual = mg->mg_virtual; /* XXX copy dynamic vtable? */
|
|
nmg->mg_private = mg->mg_private;
|
|
nmg->mg_type = mg->mg_type;
|
|
nmg->mg_flags = mg->mg_flags;
|
|
if (mg->mg_type == 'r') {
|
|
nmg->mg_obj = (SV*)re_dup((REGEXP*)mg->mg_obj);
|
|
}
|
|
else {
|
|
nmg->mg_obj = (mg->mg_flags & MGf_REFCOUNTED)
|
|
? sv_dup_inc(mg->mg_obj)
|
|
: sv_dup(mg->mg_obj);
|
|
}
|
|
nmg->mg_len = mg->mg_len;
|
|
nmg->mg_ptr = mg->mg_ptr; /* XXX random ptr? */
|
|
if (mg->mg_ptr && mg->mg_type != 'g') {
|
|
if (mg->mg_len >= 0) {
|
|
nmg->mg_ptr = SAVEPVN(mg->mg_ptr, mg->mg_len);
|
|
if (mg->mg_type == 'c' && AMT_AMAGIC((AMT*)mg->mg_ptr)) {
|
|
AMT *amtp = (AMT*)mg->mg_ptr;
|
|
AMT *namtp = (AMT*)nmg->mg_ptr;
|
|
I32 i;
|
|
for (i = 1; i < NofAMmeth; i++) {
|
|
namtp->table[i] = cv_dup_inc(amtp->table[i]);
|
|
}
|
|
}
|
|
}
|
|
else if (mg->mg_len == HEf_SVKEY)
|
|
nmg->mg_ptr = (char*)sv_dup_inc((SV*)mg->mg_ptr);
|
|
}
|
|
mgprev = nmg;
|
|
}
|
|
return mgret;
|
|
}
|
|
|
|
PTR_TBL_t *
|
|
Perl_ptr_table_new(pTHX)
|
|
{
|
|
PTR_TBL_t *tbl;
|
|
Newz(0, tbl, 1, PTR_TBL_t);
|
|
tbl->tbl_max = 511;
|
|
tbl->tbl_items = 0;
|
|
Newz(0, tbl->tbl_ary, tbl->tbl_max + 1, PTR_TBL_ENT_t*);
|
|
return tbl;
|
|
}
|
|
|
|
void *
|
|
Perl_ptr_table_fetch(pTHX_ PTR_TBL_t *tbl, void *sv)
|
|
{
|
|
PTR_TBL_ENT_t *tblent;
|
|
UV hash = PTR2UV(sv);
|
|
assert(tbl);
|
|
tblent = tbl->tbl_ary[hash & tbl->tbl_max];
|
|
for (; tblent; tblent = tblent->next) {
|
|
if (tblent->oldval == sv)
|
|
return tblent->newval;
|
|
}
|
|
return (void*)NULL;
|
|
}
|
|
|
|
void
|
|
Perl_ptr_table_store(pTHX_ PTR_TBL_t *tbl, void *oldv, void *newv)
|
|
{
|
|
PTR_TBL_ENT_t *tblent, **otblent;
|
|
/* XXX this may be pessimal on platforms where pointers aren't good
|
|
* hash values e.g. if they grow faster in the most significant
|
|
* bits */
|
|
UV hash = PTR2UV(oldv);
|
|
bool i = 1;
|
|
|
|
assert(tbl);
|
|
otblent = &tbl->tbl_ary[hash & tbl->tbl_max];
|
|
for (tblent = *otblent; tblent; i=0, tblent = tblent->next) {
|
|
if (tblent->oldval == oldv) {
|
|
tblent->newval = newv;
|
|
tbl->tbl_items++;
|
|
return;
|
|
}
|
|
}
|
|
Newz(0, tblent, 1, PTR_TBL_ENT_t);
|
|
tblent->oldval = oldv;
|
|
tblent->newval = newv;
|
|
tblent->next = *otblent;
|
|
*otblent = tblent;
|
|
tbl->tbl_items++;
|
|
if (i && tbl->tbl_items > tbl->tbl_max)
|
|
ptr_table_split(tbl);
|
|
}
|
|
|
|
void
|
|
Perl_ptr_table_split(pTHX_ PTR_TBL_t *tbl)
|
|
{
|
|
PTR_TBL_ENT_t **ary = tbl->tbl_ary;
|
|
UV oldsize = tbl->tbl_max + 1;
|
|
UV newsize = oldsize * 2;
|
|
UV i;
|
|
|
|
Renew(ary, newsize, PTR_TBL_ENT_t*);
|
|
Zero(&ary[oldsize], newsize-oldsize, PTR_TBL_ENT_t*);
|
|
tbl->tbl_max = --newsize;
|
|
tbl->tbl_ary = ary;
|
|
for (i=0; i < oldsize; i++, ary++) {
|
|
PTR_TBL_ENT_t **curentp, **entp, *ent;
|
|
if (!*ary)
|
|
continue;
|
|
curentp = ary + oldsize;
|
|
for (entp = ary, ent = *ary; ent; ent = *entp) {
|
|
if ((newsize & PTR2UV(ent->oldval)) != i) {
|
|
*entp = ent->next;
|
|
ent->next = *curentp;
|
|
*curentp = ent;
|
|
continue;
|
|
}
|
|
else
|
|
entp = &ent->next;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
Perl_ptr_table_clear(pTHX_ PTR_TBL_t *tbl)
|
|
{
|
|
register PTR_TBL_ENT_t **array;
|
|
register PTR_TBL_ENT_t *entry;
|
|
register PTR_TBL_ENT_t *oentry = Null(PTR_TBL_ENT_t*);
|
|
UV riter = 0;
|
|
UV max;
|
|
|
|
if (!tbl || !tbl->tbl_items) {
|
|
return;
|
|
}
|
|
|
|
array = tbl->tbl_ary;
|
|
entry = array[0];
|
|
max = tbl->tbl_max;
|
|
|
|
for (;;) {
|
|
if (entry) {
|
|
oentry = entry;
|
|
entry = entry->next;
|
|
Safefree(oentry);
|
|
}
|
|
if (!entry) {
|
|
if (++riter > max) {
|
|
break;
|
|
}
|
|
entry = array[riter];
|
|
}
|
|
}
|
|
|
|
tbl->tbl_items = 0;
|
|
}
|
|
|
|
void
|
|
Perl_ptr_table_free(pTHX_ PTR_TBL_t *tbl)
|
|
{
|
|
if (!tbl) {
|
|
return;
|
|
}
|
|
ptr_table_clear(tbl);
|
|
Safefree(tbl->tbl_ary);
|
|
Safefree(tbl);
|
|
}
|
|
|
|
#ifdef DEBUGGING
|
|
char *PL_watch_pvx;
|
|
#endif
|
|
|
|
SV *
|
|
Perl_sv_dup(pTHX_ SV *sstr)
|
|
{
|
|
SV *dstr;
|
|
|
|
if (!sstr || SvTYPE(sstr) == SVTYPEMASK)
|
|
return Nullsv;
|
|
/* look for it in the table first */
|
|
dstr = (SV*)ptr_table_fetch(PL_ptr_table, sstr);
|
|
if (dstr)
|
|
return dstr;
|
|
|
|
/* create anew and remember what it is */
|
|
new_SV(dstr);
|
|
ptr_table_store(PL_ptr_table, sstr, dstr);
|
|
|
|
/* clone */
|
|
SvFLAGS(dstr) = SvFLAGS(sstr);
|
|
SvFLAGS(dstr) &= ~SVf_OOK; /* don't propagate OOK hack */
|
|
SvREFCNT(dstr) = 0; /* must be before any other dups! */
|
|
|
|
#ifdef DEBUGGING
|
|
if (SvANY(sstr) && PL_watch_pvx && SvPVX(sstr) == PL_watch_pvx)
|
|
PerlIO_printf(Perl_debug_log, "watch at %p hit, found string \"%s\"\n",
|
|
PL_watch_pvx, SvPVX(sstr));
|
|
#endif
|
|
|
|
switch (SvTYPE(sstr)) {
|
|
case SVt_NULL:
|
|
SvANY(dstr) = NULL;
|
|
break;
|
|
case SVt_IV:
|
|
SvANY(dstr) = new_XIV();
|
|
SvIVX(dstr) = SvIVX(sstr);
|
|
break;
|
|
case SVt_NV:
|
|
SvANY(dstr) = new_XNV();
|
|
SvNVX(dstr) = SvNVX(sstr);
|
|
break;
|
|
case SVt_RV:
|
|
SvANY(dstr) = new_XRV();
|
|
SvRV(dstr) = sv_dup_inc(SvRV(sstr));
|
|
break;
|
|
case SVt_PV:
|
|
SvANY(dstr) = new_XPV();
|
|
SvCUR(dstr) = SvCUR(sstr);
|
|
SvLEN(dstr) = SvLEN(sstr);
|
|
if (SvROK(sstr))
|
|
SvRV(dstr) = sv_dup_inc(SvRV(sstr));
|
|
else if (SvPVX(sstr) && SvLEN(sstr))
|
|
SvPVX(dstr) = SAVEPVN(SvPVX(sstr), SvLEN(sstr)-1);
|
|
else
|
|
SvPVX(dstr) = SvPVX(sstr); /* XXX shared string/random ptr? */
|
|
break;
|
|
case SVt_PVIV:
|
|
SvANY(dstr) = new_XPVIV();
|
|
SvCUR(dstr) = SvCUR(sstr);
|
|
SvLEN(dstr) = SvLEN(sstr);
|
|
SvIVX(dstr) = SvIVX(sstr);
|
|
if (SvROK(sstr))
|
|
SvRV(dstr) = sv_dup_inc(SvRV(sstr));
|
|
else if (SvPVX(sstr) && SvLEN(sstr))
|
|
SvPVX(dstr) = SAVEPVN(SvPVX(sstr), SvLEN(sstr)-1);
|
|
else
|
|
SvPVX(dstr) = SvPVX(sstr); /* XXX shared string/random ptr? */
|
|
break;
|
|
case SVt_PVNV:
|
|
SvANY(dstr) = new_XPVNV();
|
|
SvCUR(dstr) = SvCUR(sstr);
|
|
SvLEN(dstr) = SvLEN(sstr);
|
|
SvIVX(dstr) = SvIVX(sstr);
|
|
SvNVX(dstr) = SvNVX(sstr);
|
|
if (SvROK(sstr))
|
|
SvRV(dstr) = sv_dup_inc(SvRV(sstr));
|
|
else if (SvPVX(sstr) && SvLEN(sstr))
|
|
SvPVX(dstr) = SAVEPVN(SvPVX(sstr), SvLEN(sstr)-1);
|
|
else
|
|
SvPVX(dstr) = SvPVX(sstr); /* XXX shared string/random ptr? */
|
|
break;
|
|
case SVt_PVMG:
|
|
SvANY(dstr) = new_XPVMG();
|
|
SvCUR(dstr) = SvCUR(sstr);
|
|
SvLEN(dstr) = SvLEN(sstr);
|
|
SvIVX(dstr) = SvIVX(sstr);
|
|
SvNVX(dstr) = SvNVX(sstr);
|
|
SvMAGIC(dstr) = mg_dup(SvMAGIC(sstr));
|
|
SvSTASH(dstr) = hv_dup_inc(SvSTASH(sstr));
|
|
if (SvROK(sstr))
|
|
SvRV(dstr) = sv_dup_inc(SvRV(sstr));
|
|
else if (SvPVX(sstr) && SvLEN(sstr))
|
|
SvPVX(dstr) = SAVEPVN(SvPVX(sstr), SvLEN(sstr)-1);
|
|
else
|
|
SvPVX(dstr) = SvPVX(sstr); /* XXX shared string/random ptr? */
|
|
break;
|
|
case SVt_PVBM:
|
|
SvANY(dstr) = new_XPVBM();
|
|
SvCUR(dstr) = SvCUR(sstr);
|
|
SvLEN(dstr) = SvLEN(sstr);
|
|
SvIVX(dstr) = SvIVX(sstr);
|
|
SvNVX(dstr) = SvNVX(sstr);
|
|
SvMAGIC(dstr) = mg_dup(SvMAGIC(sstr));
|
|
SvSTASH(dstr) = hv_dup_inc(SvSTASH(sstr));
|
|
if (SvROK(sstr))
|
|
SvRV(dstr) = sv_dup_inc(SvRV(sstr));
|
|
else if (SvPVX(sstr) && SvLEN(sstr))
|
|
SvPVX(dstr) = SAVEPVN(SvPVX(sstr), SvLEN(sstr)-1);
|
|
else
|
|
SvPVX(dstr) = SvPVX(sstr); /* XXX shared string/random ptr? */
|
|
BmRARE(dstr) = BmRARE(sstr);
|
|
BmUSEFUL(dstr) = BmUSEFUL(sstr);
|
|
BmPREVIOUS(dstr)= BmPREVIOUS(sstr);
|
|
break;
|
|
case SVt_PVLV:
|
|
SvANY(dstr) = new_XPVLV();
|
|
SvCUR(dstr) = SvCUR(sstr);
|
|
SvLEN(dstr) = SvLEN(sstr);
|
|
SvIVX(dstr) = SvIVX(sstr);
|
|
SvNVX(dstr) = SvNVX(sstr);
|
|
SvMAGIC(dstr) = mg_dup(SvMAGIC(sstr));
|
|
SvSTASH(dstr) = hv_dup_inc(SvSTASH(sstr));
|
|
if (SvROK(sstr))
|
|
SvRV(dstr) = sv_dup_inc(SvRV(sstr));
|
|
else if (SvPVX(sstr) && SvLEN(sstr))
|
|
SvPVX(dstr) = SAVEPVN(SvPVX(sstr), SvLEN(sstr)-1);
|
|
else
|
|
SvPVX(dstr) = SvPVX(sstr); /* XXX shared string/random ptr? */
|
|
LvTARGOFF(dstr) = LvTARGOFF(sstr); /* XXX sometimes holds PMOP* when DEBUGGING */
|
|
LvTARGLEN(dstr) = LvTARGLEN(sstr);
|
|
LvTARG(dstr) = sv_dup_inc(LvTARG(sstr));
|
|
LvTYPE(dstr) = LvTYPE(sstr);
|
|
break;
|
|
case SVt_PVGV:
|
|
SvANY(dstr) = new_XPVGV();
|
|
SvCUR(dstr) = SvCUR(sstr);
|
|
SvLEN(dstr) = SvLEN(sstr);
|
|
SvIVX(dstr) = SvIVX(sstr);
|
|
SvNVX(dstr) = SvNVX(sstr);
|
|
SvMAGIC(dstr) = mg_dup(SvMAGIC(sstr));
|
|
SvSTASH(dstr) = hv_dup_inc(SvSTASH(sstr));
|
|
if (SvROK(sstr))
|
|
SvRV(dstr) = sv_dup_inc(SvRV(sstr));
|
|
else if (SvPVX(sstr) && SvLEN(sstr))
|
|
SvPVX(dstr) = SAVEPVN(SvPVX(sstr), SvLEN(sstr)-1);
|
|
else
|
|
SvPVX(dstr) = SvPVX(sstr); /* XXX shared string/random ptr? */
|
|
GvNAMELEN(dstr) = GvNAMELEN(sstr);
|
|
GvNAME(dstr) = SAVEPVN(GvNAME(sstr), GvNAMELEN(sstr));
|
|
GvSTASH(dstr) = hv_dup_inc(GvSTASH(sstr));
|
|
GvFLAGS(dstr) = GvFLAGS(sstr);
|
|
GvGP(dstr) = gp_dup(GvGP(sstr));
|
|
(void)GpREFCNT_inc(GvGP(dstr));
|
|
break;
|
|
case SVt_PVIO:
|
|
SvANY(dstr) = new_XPVIO();
|
|
SvCUR(dstr) = SvCUR(sstr);
|
|
SvLEN(dstr) = SvLEN(sstr);
|
|
SvIVX(dstr) = SvIVX(sstr);
|
|
SvNVX(dstr) = SvNVX(sstr);
|
|
SvMAGIC(dstr) = mg_dup(SvMAGIC(sstr));
|
|
SvSTASH(dstr) = hv_dup_inc(SvSTASH(sstr));
|
|
if (SvROK(sstr))
|
|
SvRV(dstr) = sv_dup_inc(SvRV(sstr));
|
|
else if (SvPVX(sstr) && SvLEN(sstr))
|
|
SvPVX(dstr) = SAVEPVN(SvPVX(sstr), SvLEN(sstr)-1);
|
|
else
|
|
SvPVX(dstr) = SvPVX(sstr); /* XXX shared string/random ptr? */
|
|
IoIFP(dstr) = fp_dup(IoIFP(sstr), IoTYPE(sstr));
|
|
if (IoOFP(sstr) == IoIFP(sstr))
|
|
IoOFP(dstr) = IoIFP(dstr);
|
|
else
|
|
IoOFP(dstr) = fp_dup(IoOFP(sstr), IoTYPE(sstr));
|
|
/* PL_rsfp_filters entries have fake IoDIRP() */
|
|
if (IoDIRP(sstr) && !(IoFLAGS(sstr) & IOf_FAKE_DIRP))
|
|
IoDIRP(dstr) = dirp_dup(IoDIRP(sstr));
|
|
else
|
|
IoDIRP(dstr) = IoDIRP(sstr);
|
|
IoLINES(dstr) = IoLINES(sstr);
|
|
IoPAGE(dstr) = IoPAGE(sstr);
|
|
IoPAGE_LEN(dstr) = IoPAGE_LEN(sstr);
|
|
IoLINES_LEFT(dstr) = IoLINES_LEFT(sstr);
|
|
IoTOP_NAME(dstr) = SAVEPV(IoTOP_NAME(sstr));
|
|
IoTOP_GV(dstr) = gv_dup(IoTOP_GV(sstr));
|
|
IoFMT_NAME(dstr) = SAVEPV(IoFMT_NAME(sstr));
|
|
IoFMT_GV(dstr) = gv_dup(IoFMT_GV(sstr));
|
|
IoBOTTOM_NAME(dstr) = SAVEPV(IoBOTTOM_NAME(sstr));
|
|
IoBOTTOM_GV(dstr) = gv_dup(IoBOTTOM_GV(sstr));
|
|
IoSUBPROCESS(dstr) = IoSUBPROCESS(sstr);
|
|
IoTYPE(dstr) = IoTYPE(sstr);
|
|
IoFLAGS(dstr) = IoFLAGS(sstr);
|
|
break;
|
|
case SVt_PVAV:
|
|
SvANY(dstr) = new_XPVAV();
|
|
SvCUR(dstr) = SvCUR(sstr);
|
|
SvLEN(dstr) = SvLEN(sstr);
|
|
SvIVX(dstr) = SvIVX(sstr);
|
|
SvNVX(dstr) = SvNVX(sstr);
|
|
SvMAGIC(dstr) = mg_dup(SvMAGIC(sstr));
|
|
SvSTASH(dstr) = hv_dup_inc(SvSTASH(sstr));
|
|
AvARYLEN((AV*)dstr) = sv_dup_inc(AvARYLEN((AV*)sstr));
|
|
AvFLAGS((AV*)dstr) = AvFLAGS((AV*)sstr);
|
|
if (AvARRAY((AV*)sstr)) {
|
|
SV **dst_ary, **src_ary;
|
|
SSize_t items = AvFILLp((AV*)sstr) + 1;
|
|
|
|
src_ary = AvARRAY((AV*)sstr);
|
|
Newz(0, dst_ary, AvMAX((AV*)sstr)+1, SV*);
|
|
ptr_table_store(PL_ptr_table, src_ary, dst_ary);
|
|
SvPVX(dstr) = (char*)dst_ary;
|
|
AvALLOC((AV*)dstr) = dst_ary;
|
|
if (AvREAL((AV*)sstr)) {
|
|
while (items-- > 0)
|
|
*dst_ary++ = sv_dup_inc(*src_ary++);
|
|
}
|
|
else {
|
|
while (items-- > 0)
|
|
*dst_ary++ = sv_dup(*src_ary++);
|
|
}
|
|
items = AvMAX((AV*)sstr) - AvFILLp((AV*)sstr);
|
|
while (items-- > 0) {
|
|
*dst_ary++ = &PL_sv_undef;
|
|
}
|
|
}
|
|
else {
|
|
SvPVX(dstr) = Nullch;
|
|
AvALLOC((AV*)dstr) = (SV**)NULL;
|
|
}
|
|
break;
|
|
case SVt_PVHV:
|
|
SvANY(dstr) = new_XPVHV();
|
|
SvCUR(dstr) = SvCUR(sstr);
|
|
SvLEN(dstr) = SvLEN(sstr);
|
|
SvIVX(dstr) = SvIVX(sstr);
|
|
SvNVX(dstr) = SvNVX(sstr);
|
|
SvMAGIC(dstr) = mg_dup(SvMAGIC(sstr));
|
|
SvSTASH(dstr) = hv_dup_inc(SvSTASH(sstr));
|
|
HvRITER((HV*)dstr) = HvRITER((HV*)sstr);
|
|
if (HvARRAY((HV*)sstr)) {
|
|
STRLEN i = 0;
|
|
XPVHV *dxhv = (XPVHV*)SvANY(dstr);
|
|
XPVHV *sxhv = (XPVHV*)SvANY(sstr);
|
|
Newz(0, dxhv->xhv_array,
|
|
PERL_HV_ARRAY_ALLOC_BYTES(dxhv->xhv_max+1), char);
|
|
while (i <= sxhv->xhv_max) {
|
|
((HE**)dxhv->xhv_array)[i] = he_dup(((HE**)sxhv->xhv_array)[i],
|
|
!!HvSHAREKEYS(sstr));
|
|
++i;
|
|
}
|
|
dxhv->xhv_eiter = he_dup(sxhv->xhv_eiter, !!HvSHAREKEYS(sstr));
|
|
}
|
|
else {
|
|
SvPVX(dstr) = Nullch;
|
|
HvEITER((HV*)dstr) = (HE*)NULL;
|
|
}
|
|
HvPMROOT((HV*)dstr) = HvPMROOT((HV*)sstr); /* XXX */
|
|
HvNAME((HV*)dstr) = SAVEPV(HvNAME((HV*)sstr));
|
|
break;
|
|
case SVt_PVFM:
|
|
SvANY(dstr) = new_XPVFM();
|
|
FmLINES(dstr) = FmLINES(sstr);
|
|
goto dup_pvcv;
|
|
/* NOTREACHED */
|
|
case SVt_PVCV:
|
|
SvANY(dstr) = new_XPVCV();
|
|
dup_pvcv:
|
|
SvCUR(dstr) = SvCUR(sstr);
|
|
SvLEN(dstr) = SvLEN(sstr);
|
|
SvIVX(dstr) = SvIVX(sstr);
|
|
SvNVX(dstr) = SvNVX(sstr);
|
|
SvMAGIC(dstr) = mg_dup(SvMAGIC(sstr));
|
|
SvSTASH(dstr) = hv_dup_inc(SvSTASH(sstr));
|
|
if (SvPVX(sstr) && SvLEN(sstr))
|
|
SvPVX(dstr) = SAVEPVN(SvPVX(sstr), SvLEN(sstr)-1);
|
|
else
|
|
SvPVX(dstr) = SvPVX(sstr); /* XXX shared string/random ptr? */
|
|
CvSTASH(dstr) = hv_dup(CvSTASH(sstr));/* NOTE: not refcounted */
|
|
CvSTART(dstr) = CvSTART(sstr);
|
|
CvROOT(dstr) = OpREFCNT_inc(CvROOT(sstr));
|
|
CvXSUB(dstr) = CvXSUB(sstr);
|
|
CvXSUBANY(dstr) = CvXSUBANY(sstr);
|
|
CvGV(dstr) = gv_dup(CvGV(sstr));
|
|
CvDEPTH(dstr) = CvDEPTH(sstr);
|
|
if (CvPADLIST(sstr) && !AvREAL(CvPADLIST(sstr))) {
|
|
/* XXX padlists are real, but pretend to be not */
|
|
AvREAL_on(CvPADLIST(sstr));
|
|
CvPADLIST(dstr) = av_dup_inc(CvPADLIST(sstr));
|
|
AvREAL_off(CvPADLIST(sstr));
|
|
AvREAL_off(CvPADLIST(dstr));
|
|
}
|
|
else
|
|
CvPADLIST(dstr) = av_dup_inc(CvPADLIST(sstr));
|
|
if (!CvANON(sstr) || CvCLONED(sstr))
|
|
CvOUTSIDE(dstr) = cv_dup_inc(CvOUTSIDE(sstr));
|
|
else
|
|
CvOUTSIDE(dstr) = cv_dup(CvOUTSIDE(sstr));
|
|
CvFLAGS(dstr) = CvFLAGS(sstr);
|
|
break;
|
|
default:
|
|
Perl_croak(aTHX_ "Bizarre SvTYPE [%d]", SvTYPE(sstr));
|
|
break;
|
|
}
|
|
|
|
if (SvOBJECT(dstr) && SvTYPE(dstr) != SVt_PVIO)
|
|
++PL_sv_objcount;
|
|
|
|
return dstr;
|
|
}
|
|
|
|
PERL_CONTEXT *
|
|
Perl_cx_dup(pTHX_ PERL_CONTEXT *cxs, I32 ix, I32 max)
|
|
{
|
|
PERL_CONTEXT *ncxs;
|
|
|
|
if (!cxs)
|
|
return (PERL_CONTEXT*)NULL;
|
|
|
|
/* look for it in the table first */
|
|
ncxs = (PERL_CONTEXT*)ptr_table_fetch(PL_ptr_table, cxs);
|
|
if (ncxs)
|
|
return ncxs;
|
|
|
|
/* create anew and remember what it is */
|
|
Newz(56, ncxs, max + 1, PERL_CONTEXT);
|
|
ptr_table_store(PL_ptr_table, cxs, ncxs);
|
|
|
|
while (ix >= 0) {
|
|
PERL_CONTEXT *cx = &cxs[ix];
|
|
PERL_CONTEXT *ncx = &ncxs[ix];
|
|
ncx->cx_type = cx->cx_type;
|
|
if (CxTYPE(cx) == CXt_SUBST) {
|
|
Perl_croak(aTHX_ "Cloning substitution context is unimplemented");
|
|
}
|
|
else {
|
|
ncx->blk_oldsp = cx->blk_oldsp;
|
|
ncx->blk_oldcop = cx->blk_oldcop;
|
|
ncx->blk_oldretsp = cx->blk_oldretsp;
|
|
ncx->blk_oldmarksp = cx->blk_oldmarksp;
|
|
ncx->blk_oldscopesp = cx->blk_oldscopesp;
|
|
ncx->blk_oldpm = cx->blk_oldpm;
|
|
ncx->blk_gimme = cx->blk_gimme;
|
|
switch (CxTYPE(cx)) {
|
|
case CXt_SUB:
|
|
ncx->blk_sub.cv = (cx->blk_sub.olddepth == 0
|
|
? cv_dup_inc(cx->blk_sub.cv)
|
|
: cv_dup(cx->blk_sub.cv));
|
|
ncx->blk_sub.argarray = (cx->blk_sub.hasargs
|
|
? av_dup_inc(cx->blk_sub.argarray)
|
|
: Nullav);
|
|
ncx->blk_sub.savearray = av_dup_inc(cx->blk_sub.savearray);
|
|
ncx->blk_sub.olddepth = cx->blk_sub.olddepth;
|
|
ncx->blk_sub.hasargs = cx->blk_sub.hasargs;
|
|
ncx->blk_sub.lval = cx->blk_sub.lval;
|
|
break;
|
|
case CXt_EVAL:
|
|
ncx->blk_eval.old_in_eval = cx->blk_eval.old_in_eval;
|
|
ncx->blk_eval.old_op_type = cx->blk_eval.old_op_type;
|
|
ncx->blk_eval.old_namesv = sv_dup_inc(cx->blk_eval.old_namesv);
|
|
ncx->blk_eval.old_eval_root = cx->blk_eval.old_eval_root;
|
|
ncx->blk_eval.cur_text = sv_dup(cx->blk_eval.cur_text);
|
|
break;
|
|
case CXt_LOOP:
|
|
ncx->blk_loop.label = cx->blk_loop.label;
|
|
ncx->blk_loop.resetsp = cx->blk_loop.resetsp;
|
|
ncx->blk_loop.redo_op = cx->blk_loop.redo_op;
|
|
ncx->blk_loop.next_op = cx->blk_loop.next_op;
|
|
ncx->blk_loop.last_op = cx->blk_loop.last_op;
|
|
ncx->blk_loop.iterdata = (CxPADLOOP(cx)
|
|
? cx->blk_loop.iterdata
|
|
: gv_dup((GV*)cx->blk_loop.iterdata));
|
|
ncx->blk_loop.oldcurpad
|
|
= (SV**)ptr_table_fetch(PL_ptr_table,
|
|
cx->blk_loop.oldcurpad);
|
|
ncx->blk_loop.itersave = sv_dup_inc(cx->blk_loop.itersave);
|
|
ncx->blk_loop.iterlval = sv_dup_inc(cx->blk_loop.iterlval);
|
|
ncx->blk_loop.iterary = av_dup_inc(cx->blk_loop.iterary);
|
|
ncx->blk_loop.iterix = cx->blk_loop.iterix;
|
|
ncx->blk_loop.itermax = cx->blk_loop.itermax;
|
|
break;
|
|
case CXt_FORMAT:
|
|
ncx->blk_sub.cv = cv_dup(cx->blk_sub.cv);
|
|
ncx->blk_sub.gv = gv_dup(cx->blk_sub.gv);
|
|
ncx->blk_sub.dfoutgv = gv_dup_inc(cx->blk_sub.dfoutgv);
|
|
ncx->blk_sub.hasargs = cx->blk_sub.hasargs;
|
|
break;
|
|
case CXt_BLOCK:
|
|
case CXt_NULL:
|
|
break;
|
|
}
|
|
}
|
|
--ix;
|
|
}
|
|
return ncxs;
|
|
}
|
|
|
|
PERL_SI *
|
|
Perl_si_dup(pTHX_ PERL_SI *si)
|
|
{
|
|
PERL_SI *nsi;
|
|
|
|
if (!si)
|
|
return (PERL_SI*)NULL;
|
|
|
|
/* look for it in the table first */
|
|
nsi = (PERL_SI*)ptr_table_fetch(PL_ptr_table, si);
|
|
if (nsi)
|
|
return nsi;
|
|
|
|
/* create anew and remember what it is */
|
|
Newz(56, nsi, 1, PERL_SI);
|
|
ptr_table_store(PL_ptr_table, si, nsi);
|
|
|
|
nsi->si_stack = av_dup_inc(si->si_stack);
|
|
nsi->si_cxix = si->si_cxix;
|
|
nsi->si_cxmax = si->si_cxmax;
|
|
nsi->si_cxstack = cx_dup(si->si_cxstack, si->si_cxix, si->si_cxmax);
|
|
nsi->si_type = si->si_type;
|
|
nsi->si_prev = si_dup(si->si_prev);
|
|
nsi->si_next = si_dup(si->si_next);
|
|
nsi->si_markoff = si->si_markoff;
|
|
|
|
return nsi;
|
|
}
|
|
|
|
#define POPINT(ss,ix) ((ss)[--(ix)].any_i32)
|
|
#define TOPINT(ss,ix) ((ss)[ix].any_i32)
|
|
#define POPLONG(ss,ix) ((ss)[--(ix)].any_long)
|
|
#define TOPLONG(ss,ix) ((ss)[ix].any_long)
|
|
#define POPIV(ss,ix) ((ss)[--(ix)].any_iv)
|
|
#define TOPIV(ss,ix) ((ss)[ix].any_iv)
|
|
#define POPPTR(ss,ix) ((ss)[--(ix)].any_ptr)
|
|
#define TOPPTR(ss,ix) ((ss)[ix].any_ptr)
|
|
#define POPDPTR(ss,ix) ((ss)[--(ix)].any_dptr)
|
|
#define TOPDPTR(ss,ix) ((ss)[ix].any_dptr)
|
|
#define POPDXPTR(ss,ix) ((ss)[--(ix)].any_dxptr)
|
|
#define TOPDXPTR(ss,ix) ((ss)[ix].any_dxptr)
|
|
|
|
/* XXXXX todo */
|
|
#define pv_dup_inc(p) SAVEPV(p)
|
|
#define pv_dup(p) SAVEPV(p)
|
|
#define svp_dup_inc(p,pp) any_dup(p,pp)
|
|
|
|
void *
|
|
Perl_any_dup(pTHX_ void *v, PerlInterpreter *proto_perl)
|
|
{
|
|
void *ret;
|
|
|
|
if (!v)
|
|
return (void*)NULL;
|
|
|
|
/* look for it in the table first */
|
|
ret = ptr_table_fetch(PL_ptr_table, v);
|
|
if (ret)
|
|
return ret;
|
|
|
|
/* see if it is part of the interpreter structure */
|
|
if (v >= (void*)proto_perl && v < (void*)(proto_perl+1))
|
|
ret = (void*)(((char*)aTHXo) + (((char*)v) - (char*)proto_perl));
|
|
else
|
|
ret = v;
|
|
|
|
return ret;
|
|
}
|
|
|
|
ANY *
|
|
Perl_ss_dup(pTHX_ PerlInterpreter *proto_perl)
|
|
{
|
|
ANY *ss = proto_perl->Tsavestack;
|
|
I32 ix = proto_perl->Tsavestack_ix;
|
|
I32 max = proto_perl->Tsavestack_max;
|
|
ANY *nss;
|
|
SV *sv;
|
|
GV *gv;
|
|
AV *av;
|
|
HV *hv;
|
|
void* ptr;
|
|
int intval;
|
|
long longval;
|
|
GP *gp;
|
|
IV iv;
|
|
I32 i;
|
|
char *c;
|
|
void (*dptr) (void*);
|
|
void (*dxptr) (pTHXo_ void*);
|
|
OP *o;
|
|
|
|
Newz(54, nss, max, ANY);
|
|
|
|
while (ix > 0) {
|
|
i = POPINT(ss,ix);
|
|
TOPINT(nss,ix) = i;
|
|
switch (i) {
|
|
case SAVEt_ITEM: /* normal string */
|
|
sv = (SV*)POPPTR(ss,ix);
|
|
TOPPTR(nss,ix) = sv_dup_inc(sv);
|
|
sv = (SV*)POPPTR(ss,ix);
|
|
TOPPTR(nss,ix) = sv_dup_inc(sv);
|
|
break;
|
|
case SAVEt_SV: /* scalar reference */
|
|
sv = (SV*)POPPTR(ss,ix);
|
|
TOPPTR(nss,ix) = sv_dup_inc(sv);
|
|
gv = (GV*)POPPTR(ss,ix);
|
|
TOPPTR(nss,ix) = gv_dup_inc(gv);
|
|
break;
|
|
case SAVEt_GENERIC_PVREF: /* generic char* */
|
|
c = (char*)POPPTR(ss,ix);
|
|
TOPPTR(nss,ix) = pv_dup(c);
|
|
ptr = POPPTR(ss,ix);
|
|
TOPPTR(nss,ix) = any_dup(ptr, proto_perl);
|
|
break;
|
|
case SAVEt_GENERIC_SVREF: /* generic sv */
|
|
case SAVEt_SVREF: /* scalar reference */
|
|
sv = (SV*)POPPTR(ss,ix);
|
|
TOPPTR(nss,ix) = sv_dup_inc(sv);
|
|
ptr = POPPTR(ss,ix);
|
|
TOPPTR(nss,ix) = svp_dup_inc((SV**)ptr, proto_perl);/* XXXXX */
|
|
break;
|
|
case SAVEt_AV: /* array reference */
|
|
av = (AV*)POPPTR(ss,ix);
|
|
TOPPTR(nss,ix) = av_dup_inc(av);
|
|
gv = (GV*)POPPTR(ss,ix);
|
|
TOPPTR(nss,ix) = gv_dup(gv);
|
|
break;
|
|
case SAVEt_HV: /* hash reference */
|
|
hv = (HV*)POPPTR(ss,ix);
|
|
TOPPTR(nss,ix) = hv_dup_inc(hv);
|
|
gv = (GV*)POPPTR(ss,ix);
|
|
TOPPTR(nss,ix) = gv_dup(gv);
|
|
break;
|
|
case SAVEt_INT: /* int reference */
|
|
ptr = POPPTR(ss,ix);
|
|
TOPPTR(nss,ix) = any_dup(ptr, proto_perl);
|
|
intval = (int)POPINT(ss,ix);
|
|
TOPINT(nss,ix) = intval;
|
|
break;
|
|
case SAVEt_LONG: /* long reference */
|
|
ptr = POPPTR(ss,ix);
|
|
TOPPTR(nss,ix) = any_dup(ptr, proto_perl);
|
|
longval = (long)POPLONG(ss,ix);
|
|
TOPLONG(nss,ix) = longval;
|
|
break;
|
|
case SAVEt_I32: /* I32 reference */
|
|
case SAVEt_I16: /* I16 reference */
|
|
case SAVEt_I8: /* I8 reference */
|
|
ptr = POPPTR(ss,ix);
|
|
TOPPTR(nss,ix) = any_dup(ptr, proto_perl);
|
|
i = POPINT(ss,ix);
|
|
TOPINT(nss,ix) = i;
|
|
break;
|
|
case SAVEt_IV: /* IV reference */
|
|
ptr = POPPTR(ss,ix);
|
|
TOPPTR(nss,ix) = any_dup(ptr, proto_perl);
|
|
iv = POPIV(ss,ix);
|
|
TOPIV(nss,ix) = iv;
|
|
break;
|
|
case SAVEt_SPTR: /* SV* reference */
|
|
ptr = POPPTR(ss,ix);
|
|
TOPPTR(nss,ix) = any_dup(ptr, proto_perl);
|
|
sv = (SV*)POPPTR(ss,ix);
|
|
TOPPTR(nss,ix) = sv_dup(sv);
|
|
break;
|
|
case SAVEt_VPTR: /* random* reference */
|
|
ptr = POPPTR(ss,ix);
|
|
TOPPTR(nss,ix) = any_dup(ptr, proto_perl);
|
|
ptr = POPPTR(ss,ix);
|
|
TOPPTR(nss,ix) = any_dup(ptr, proto_perl);
|
|
break;
|
|
case SAVEt_PPTR: /* char* reference */
|
|
ptr = POPPTR(ss,ix);
|
|
TOPPTR(nss,ix) = any_dup(ptr, proto_perl);
|
|
c = (char*)POPPTR(ss,ix);
|
|
TOPPTR(nss,ix) = pv_dup(c);
|
|
break;
|
|
case SAVEt_HPTR: /* HV* reference */
|
|
ptr = POPPTR(ss,ix);
|
|
TOPPTR(nss,ix) = any_dup(ptr, proto_perl);
|
|
hv = (HV*)POPPTR(ss,ix);
|
|
TOPPTR(nss,ix) = hv_dup(hv);
|
|
break;
|
|
case SAVEt_APTR: /* AV* reference */
|
|
ptr = POPPTR(ss,ix);
|
|
TOPPTR(nss,ix) = any_dup(ptr, proto_perl);
|
|
av = (AV*)POPPTR(ss,ix);
|
|
TOPPTR(nss,ix) = av_dup(av);
|
|
break;
|
|
case SAVEt_NSTAB:
|
|
gv = (GV*)POPPTR(ss,ix);
|
|
TOPPTR(nss,ix) = gv_dup(gv);
|
|
break;
|
|
case SAVEt_GP: /* scalar reference */
|
|
gp = (GP*)POPPTR(ss,ix);
|
|
TOPPTR(nss,ix) = gp = gp_dup(gp);
|
|
(void)GpREFCNT_inc(gp);
|
|
gv = (GV*)POPPTR(ss,ix);
|
|
TOPPTR(nss,ix) = gv_dup_inc(c);
|
|
c = (char*)POPPTR(ss,ix);
|
|
TOPPTR(nss,ix) = pv_dup(c);
|
|
iv = POPIV(ss,ix);
|
|
TOPIV(nss,ix) = iv;
|
|
iv = POPIV(ss,ix);
|
|
TOPIV(nss,ix) = iv;
|
|
break;
|
|
case SAVEt_FREESV:
|
|
case SAVEt_MORTALIZESV:
|
|
sv = (SV*)POPPTR(ss,ix);
|
|
TOPPTR(nss,ix) = sv_dup_inc(sv);
|
|
break;
|
|
case SAVEt_FREEOP:
|
|
ptr = POPPTR(ss,ix);
|
|
if (ptr && (((OP*)ptr)->op_private & OPpREFCOUNTED)) {
|
|
/* these are assumed to be refcounted properly */
|
|
switch (((OP*)ptr)->op_type) {
|
|
case OP_LEAVESUB:
|
|
case OP_LEAVESUBLV:
|
|
case OP_LEAVEEVAL:
|
|
case OP_LEAVE:
|
|
case OP_SCOPE:
|
|
case OP_LEAVEWRITE:
|
|
TOPPTR(nss,ix) = ptr;
|
|
o = (OP*)ptr;
|
|
OpREFCNT_inc(o);
|
|
break;
|
|
default:
|
|
TOPPTR(nss,ix) = Nullop;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
TOPPTR(nss,ix) = Nullop;
|
|
break;
|
|
case SAVEt_FREEPV:
|
|
c = (char*)POPPTR(ss,ix);
|
|
TOPPTR(nss,ix) = pv_dup_inc(c);
|
|
break;
|
|
case SAVEt_CLEARSV:
|
|
longval = POPLONG(ss,ix);
|
|
TOPLONG(nss,ix) = longval;
|
|
break;
|
|
case SAVEt_DELETE:
|
|
hv = (HV*)POPPTR(ss,ix);
|
|
TOPPTR(nss,ix) = hv_dup_inc(hv);
|
|
c = (char*)POPPTR(ss,ix);
|
|
TOPPTR(nss,ix) = pv_dup_inc(c);
|
|
i = POPINT(ss,ix);
|
|
TOPINT(nss,ix) = i;
|
|
break;
|
|
case SAVEt_DESTRUCTOR:
|
|
ptr = POPPTR(ss,ix);
|
|
TOPPTR(nss,ix) = any_dup(ptr, proto_perl); /* XXX quite arbitrary */
|
|
dptr = POPDPTR(ss,ix);
|
|
TOPDPTR(nss,ix) = (void (*)(void*))any_dup((void *)dptr, proto_perl);
|
|
break;
|
|
case SAVEt_DESTRUCTOR_X:
|
|
ptr = POPPTR(ss,ix);
|
|
TOPPTR(nss,ix) = any_dup(ptr, proto_perl); /* XXX quite arbitrary */
|
|
dxptr = POPDXPTR(ss,ix);
|
|
TOPDXPTR(nss,ix) = (void (*)(pTHXo_ void*))any_dup((void *)dxptr, proto_perl);
|
|
break;
|
|
case SAVEt_REGCONTEXT:
|
|
case SAVEt_ALLOC:
|
|
i = POPINT(ss,ix);
|
|
TOPINT(nss,ix) = i;
|
|
ix -= i;
|
|
break;
|
|
case SAVEt_STACK_POS: /* Position on Perl stack */
|
|
i = POPINT(ss,ix);
|
|
TOPINT(nss,ix) = i;
|
|
break;
|
|
case SAVEt_AELEM: /* array element */
|
|
sv = (SV*)POPPTR(ss,ix);
|
|
TOPPTR(nss,ix) = sv_dup_inc(sv);
|
|
i = POPINT(ss,ix);
|
|
TOPINT(nss,ix) = i;
|
|
av = (AV*)POPPTR(ss,ix);
|
|
TOPPTR(nss,ix) = av_dup_inc(av);
|
|
break;
|
|
case SAVEt_HELEM: /* hash element */
|
|
sv = (SV*)POPPTR(ss,ix);
|
|
TOPPTR(nss,ix) = sv_dup_inc(sv);
|
|
sv = (SV*)POPPTR(ss,ix);
|
|
TOPPTR(nss,ix) = sv_dup_inc(sv);
|
|
hv = (HV*)POPPTR(ss,ix);
|
|
TOPPTR(nss,ix) = hv_dup_inc(hv);
|
|
break;
|
|
case SAVEt_OP:
|
|
ptr = POPPTR(ss,ix);
|
|
TOPPTR(nss,ix) = ptr;
|
|
break;
|
|
case SAVEt_HINTS:
|
|
i = POPINT(ss,ix);
|
|
TOPINT(nss,ix) = i;
|
|
break;
|
|
case SAVEt_COMPPAD:
|
|
av = (AV*)POPPTR(ss,ix);
|
|
TOPPTR(nss,ix) = av_dup(av);
|
|
break;
|
|
case SAVEt_PADSV:
|
|
longval = (long)POPLONG(ss,ix);
|
|
TOPLONG(nss,ix) = longval;
|
|
ptr = POPPTR(ss,ix);
|
|
TOPPTR(nss,ix) = any_dup(ptr, proto_perl);
|
|
sv = (SV*)POPPTR(ss,ix);
|
|
TOPPTR(nss,ix) = sv_dup(sv);
|
|
break;
|
|
default:
|
|
Perl_croak(aTHX_ "panic: ss_dup inconsistency");
|
|
}
|
|
}
|
|
|
|
return nss;
|
|
}
|
|
|
|
#ifdef PERL_OBJECT
|
|
#include "XSUB.h"
|
|
#endif
|
|
|
|
PerlInterpreter *
|
|
perl_clone(PerlInterpreter *proto_perl, UV flags)
|
|
{
|
|
#ifdef PERL_OBJECT
|
|
CPerlObj *pPerl = (CPerlObj*)proto_perl;
|
|
#endif
|
|
|
|
#ifdef PERL_IMPLICIT_SYS
|
|
return perl_clone_using(proto_perl, flags,
|
|
proto_perl->IMem,
|
|
proto_perl->IMemShared,
|
|
proto_perl->IMemParse,
|
|
proto_perl->IEnv,
|
|
proto_perl->IStdIO,
|
|
proto_perl->ILIO,
|
|
proto_perl->IDir,
|
|
proto_perl->ISock,
|
|
proto_perl->IProc);
|
|
}
|
|
|
|
PerlInterpreter *
|
|
perl_clone_using(PerlInterpreter *proto_perl, UV flags,
|
|
struct IPerlMem* ipM, struct IPerlMem* ipMS,
|
|
struct IPerlMem* ipMP, struct IPerlEnv* ipE,
|
|
struct IPerlStdIO* ipStd, struct IPerlLIO* ipLIO,
|
|
struct IPerlDir* ipD, struct IPerlSock* ipS,
|
|
struct IPerlProc* ipP)
|
|
{
|
|
/* XXX many of the string copies here can be optimized if they're
|
|
* constants; they need to be allocated as common memory and just
|
|
* their pointers copied. */
|
|
|
|
IV i;
|
|
# ifdef PERL_OBJECT
|
|
CPerlObj *pPerl = new(ipM) CPerlObj(ipM, ipMS, ipMP, ipE, ipStd, ipLIO,
|
|
ipD, ipS, ipP);
|
|
PERL_SET_THX(pPerl);
|
|
# else /* !PERL_OBJECT */
|
|
PerlInterpreter *my_perl = (PerlInterpreter*)(*ipM->pMalloc)(ipM, sizeof(PerlInterpreter));
|
|
PERL_SET_THX(my_perl);
|
|
|
|
# ifdef DEBUGGING
|
|
memset(my_perl, 0xab, sizeof(PerlInterpreter));
|
|
PL_markstack = 0;
|
|
PL_scopestack = 0;
|
|
PL_savestack = 0;
|
|
PL_retstack = 0;
|
|
# else /* !DEBUGGING */
|
|
Zero(my_perl, 1, PerlInterpreter);
|
|
# endif /* DEBUGGING */
|
|
|
|
/* host pointers */
|
|
PL_Mem = ipM;
|
|
PL_MemShared = ipMS;
|
|
PL_MemParse = ipMP;
|
|
PL_Env = ipE;
|
|
PL_StdIO = ipStd;
|
|
PL_LIO = ipLIO;
|
|
PL_Dir = ipD;
|
|
PL_Sock = ipS;
|
|
PL_Proc = ipP;
|
|
# endif /* PERL_OBJECT */
|
|
#else /* !PERL_IMPLICIT_SYS */
|
|
IV i;
|
|
PerlInterpreter *my_perl = (PerlInterpreter*)PerlMem_malloc(sizeof(PerlInterpreter));
|
|
PERL_SET_THX(my_perl);
|
|
|
|
# ifdef DEBUGGING
|
|
memset(my_perl, 0xab, sizeof(PerlInterpreter));
|
|
PL_markstack = 0;
|
|
PL_scopestack = 0;
|
|
PL_savestack = 0;
|
|
PL_retstack = 0;
|
|
# else /* !DEBUGGING */
|
|
Zero(my_perl, 1, PerlInterpreter);
|
|
# endif /* DEBUGGING */
|
|
#endif /* PERL_IMPLICIT_SYS */
|
|
|
|
/* arena roots */
|
|
PL_xiv_arenaroot = NULL;
|
|
PL_xiv_root = NULL;
|
|
PL_xnv_arenaroot = NULL;
|
|
PL_xnv_root = NULL;
|
|
PL_xrv_arenaroot = NULL;
|
|
PL_xrv_root = NULL;
|
|
PL_xpv_arenaroot = NULL;
|
|
PL_xpv_root = NULL;
|
|
PL_xpviv_arenaroot = NULL;
|
|
PL_xpviv_root = NULL;
|
|
PL_xpvnv_arenaroot = NULL;
|
|
PL_xpvnv_root = NULL;
|
|
PL_xpvcv_arenaroot = NULL;
|
|
PL_xpvcv_root = NULL;
|
|
PL_xpvav_arenaroot = NULL;
|
|
PL_xpvav_root = NULL;
|
|
PL_xpvhv_arenaroot = NULL;
|
|
PL_xpvhv_root = NULL;
|
|
PL_xpvmg_arenaroot = NULL;
|
|
PL_xpvmg_root = NULL;
|
|
PL_xpvlv_arenaroot = NULL;
|
|
PL_xpvlv_root = NULL;
|
|
PL_xpvbm_arenaroot = NULL;
|
|
PL_xpvbm_root = NULL;
|
|
PL_he_arenaroot = NULL;
|
|
PL_he_root = NULL;
|
|
PL_nice_chunk = NULL;
|
|
PL_nice_chunk_size = 0;
|
|
PL_sv_count = 0;
|
|
PL_sv_objcount = 0;
|
|
PL_sv_root = Nullsv;
|
|
PL_sv_arenaroot = Nullsv;
|
|
|
|
PL_debug = proto_perl->Idebug;
|
|
|
|
/* create SV map for pointer relocation */
|
|
PL_ptr_table = ptr_table_new();
|
|
|
|
/* initialize these special pointers as early as possible */
|
|
SvANY(&PL_sv_undef) = NULL;
|
|
SvREFCNT(&PL_sv_undef) = (~(U32)0)/2;
|
|
SvFLAGS(&PL_sv_undef) = SVf_READONLY|SVt_NULL;
|
|
ptr_table_store(PL_ptr_table, &proto_perl->Isv_undef, &PL_sv_undef);
|
|
|
|
#ifdef PERL_OBJECT
|
|
SvUPGRADE(&PL_sv_no, SVt_PVNV);
|
|
#else
|
|
SvANY(&PL_sv_no) = new_XPVNV();
|
|
#endif
|
|
SvREFCNT(&PL_sv_no) = (~(U32)0)/2;
|
|
SvFLAGS(&PL_sv_no) = SVp_NOK|SVf_NOK|SVp_POK|SVf_POK|SVf_READONLY|SVt_PVNV;
|
|
SvPVX(&PL_sv_no) = SAVEPVN(PL_No, 0);
|
|
SvCUR(&PL_sv_no) = 0;
|
|
SvLEN(&PL_sv_no) = 1;
|
|
SvNVX(&PL_sv_no) = 0;
|
|
ptr_table_store(PL_ptr_table, &proto_perl->Isv_no, &PL_sv_no);
|
|
|
|
#ifdef PERL_OBJECT
|
|
SvUPGRADE(&PL_sv_yes, SVt_PVNV);
|
|
#else
|
|
SvANY(&PL_sv_yes) = new_XPVNV();
|
|
#endif
|
|
SvREFCNT(&PL_sv_yes) = (~(U32)0)/2;
|
|
SvFLAGS(&PL_sv_yes) = SVp_NOK|SVf_NOK|SVp_POK|SVf_POK|SVf_READONLY|SVt_PVNV;
|
|
SvPVX(&PL_sv_yes) = SAVEPVN(PL_Yes, 1);
|
|
SvCUR(&PL_sv_yes) = 1;
|
|
SvLEN(&PL_sv_yes) = 2;
|
|
SvNVX(&PL_sv_yes) = 1;
|
|
ptr_table_store(PL_ptr_table, &proto_perl->Isv_yes, &PL_sv_yes);
|
|
|
|
/* create shared string table */
|
|
PL_strtab = newHV();
|
|
HvSHAREKEYS_off(PL_strtab);
|
|
hv_ksplit(PL_strtab, 512);
|
|
ptr_table_store(PL_ptr_table, proto_perl->Istrtab, PL_strtab);
|
|
|
|
PL_compiling = proto_perl->Icompiling;
|
|
PL_compiling.cop_stashpv = SAVEPV(PL_compiling.cop_stashpv);
|
|
PL_compiling.cop_file = SAVEPV(PL_compiling.cop_file);
|
|
ptr_table_store(PL_ptr_table, &proto_perl->Icompiling, &PL_compiling);
|
|
if (!specialWARN(PL_compiling.cop_warnings))
|
|
PL_compiling.cop_warnings = sv_dup_inc(PL_compiling.cop_warnings);
|
|
PL_curcop = (COP*)any_dup(proto_perl->Tcurcop, proto_perl);
|
|
|
|
/* pseudo environmental stuff */
|
|
PL_origargc = proto_perl->Iorigargc;
|
|
i = PL_origargc;
|
|
New(0, PL_origargv, i+1, char*);
|
|
PL_origargv[i] = '\0';
|
|
while (i-- > 0) {
|
|
PL_origargv[i] = SAVEPV(proto_perl->Iorigargv[i]);
|
|
}
|
|
PL_envgv = gv_dup(proto_perl->Ienvgv);
|
|
PL_incgv = gv_dup(proto_perl->Iincgv);
|
|
PL_hintgv = gv_dup(proto_perl->Ihintgv);
|
|
PL_origfilename = SAVEPV(proto_perl->Iorigfilename);
|
|
PL_diehook = sv_dup_inc(proto_perl->Idiehook);
|
|
PL_warnhook = sv_dup_inc(proto_perl->Iwarnhook);
|
|
|
|
/* switches */
|
|
PL_minus_c = proto_perl->Iminus_c;
|
|
PL_patchlevel = sv_dup_inc(proto_perl->Ipatchlevel);
|
|
PL_localpatches = proto_perl->Ilocalpatches;
|
|
PL_splitstr = proto_perl->Isplitstr;
|
|
PL_preprocess = proto_perl->Ipreprocess;
|
|
PL_minus_n = proto_perl->Iminus_n;
|
|
PL_minus_p = proto_perl->Iminus_p;
|
|
PL_minus_l = proto_perl->Iminus_l;
|
|
PL_minus_a = proto_perl->Iminus_a;
|
|
PL_minus_F = proto_perl->Iminus_F;
|
|
PL_doswitches = proto_perl->Idoswitches;
|
|
PL_dowarn = proto_perl->Idowarn;
|
|
PL_doextract = proto_perl->Idoextract;
|
|
PL_sawampersand = proto_perl->Isawampersand;
|
|
PL_unsafe = proto_perl->Iunsafe;
|
|
PL_inplace = SAVEPV(proto_perl->Iinplace);
|
|
PL_e_script = sv_dup_inc(proto_perl->Ie_script);
|
|
PL_perldb = proto_perl->Iperldb;
|
|
PL_perl_destruct_level = proto_perl->Iperl_destruct_level;
|
|
|
|
/* magical thingies */
|
|
/* XXX time(&PL_basetime) when asked for? */
|
|
PL_basetime = proto_perl->Ibasetime;
|
|
PL_formfeed = sv_dup(proto_perl->Iformfeed);
|
|
|
|
PL_maxsysfd = proto_perl->Imaxsysfd;
|
|
PL_multiline = proto_perl->Imultiline;
|
|
PL_statusvalue = proto_perl->Istatusvalue;
|
|
#ifdef VMS
|
|
PL_statusvalue_vms = proto_perl->Istatusvalue_vms;
|
|
#endif
|
|
|
|
/* shortcuts to various I/O objects */
|
|
PL_stdingv = gv_dup(proto_perl->Istdingv);
|
|
PL_stderrgv = gv_dup(proto_perl->Istderrgv);
|
|
PL_defgv = gv_dup(proto_perl->Idefgv);
|
|
PL_argvgv = gv_dup(proto_perl->Iargvgv);
|
|
PL_argvoutgv = gv_dup(proto_perl->Iargvoutgv);
|
|
PL_argvout_stack = av_dup_inc(proto_perl->Iargvout_stack);
|
|
|
|
/* shortcuts to regexp stuff */
|
|
PL_replgv = gv_dup(proto_perl->Ireplgv);
|
|
|
|
/* shortcuts to misc objects */
|
|
PL_errgv = gv_dup(proto_perl->Ierrgv);
|
|
|
|
/* shortcuts to debugging objects */
|
|
PL_DBgv = gv_dup(proto_perl->IDBgv);
|
|
PL_DBline = gv_dup(proto_perl->IDBline);
|
|
PL_DBsub = gv_dup(proto_perl->IDBsub);
|
|
PL_DBsingle = sv_dup(proto_perl->IDBsingle);
|
|
PL_DBtrace = sv_dup(proto_perl->IDBtrace);
|
|
PL_DBsignal = sv_dup(proto_perl->IDBsignal);
|
|
PL_lineary = av_dup(proto_perl->Ilineary);
|
|
PL_dbargs = av_dup(proto_perl->Idbargs);
|
|
|
|
/* symbol tables */
|
|
PL_defstash = hv_dup_inc(proto_perl->Tdefstash);
|
|
PL_curstash = hv_dup(proto_perl->Tcurstash);
|
|
PL_debstash = hv_dup(proto_perl->Idebstash);
|
|
PL_globalstash = hv_dup(proto_perl->Iglobalstash);
|
|
PL_curstname = sv_dup_inc(proto_perl->Icurstname);
|
|
|
|
PL_beginav = av_dup_inc(proto_perl->Ibeginav);
|
|
PL_endav = av_dup_inc(proto_perl->Iendav);
|
|
PL_checkav = av_dup_inc(proto_perl->Icheckav);
|
|
PL_initav = av_dup_inc(proto_perl->Iinitav);
|
|
|
|
PL_sub_generation = proto_perl->Isub_generation;
|
|
|
|
/* funky return mechanisms */
|
|
PL_forkprocess = proto_perl->Iforkprocess;
|
|
|
|
/* subprocess state */
|
|
PL_fdpid = av_dup_inc(proto_perl->Ifdpid);
|
|
|
|
/* internal state */
|
|
PL_tainting = proto_perl->Itainting;
|
|
PL_maxo = proto_perl->Imaxo;
|
|
if (proto_perl->Iop_mask)
|
|
PL_op_mask = SAVEPVN(proto_perl->Iop_mask, PL_maxo);
|
|
else
|
|
PL_op_mask = Nullch;
|
|
|
|
/* current interpreter roots */
|
|
PL_main_cv = cv_dup_inc(proto_perl->Imain_cv);
|
|
PL_main_root = OpREFCNT_inc(proto_perl->Imain_root);
|
|
PL_main_start = proto_perl->Imain_start;
|
|
PL_eval_root = proto_perl->Ieval_root;
|
|
PL_eval_start = proto_perl->Ieval_start;
|
|
|
|
/* runtime control stuff */
|
|
PL_curcopdb = (COP*)any_dup(proto_perl->Icurcopdb, proto_perl);
|
|
PL_copline = proto_perl->Icopline;
|
|
|
|
PL_filemode = proto_perl->Ifilemode;
|
|
PL_lastfd = proto_perl->Ilastfd;
|
|
PL_oldname = proto_perl->Ioldname; /* XXX not quite right */
|
|
PL_Argv = NULL;
|
|
PL_Cmd = Nullch;
|
|
PL_gensym = proto_perl->Igensym;
|
|
PL_preambled = proto_perl->Ipreambled;
|
|
PL_preambleav = av_dup_inc(proto_perl->Ipreambleav);
|
|
PL_laststatval = proto_perl->Ilaststatval;
|
|
PL_laststype = proto_perl->Ilaststype;
|
|
PL_mess_sv = Nullsv;
|
|
|
|
PL_orslen = proto_perl->Iorslen;
|
|
PL_ors = SAVEPVN(proto_perl->Iors, PL_orslen);
|
|
PL_ofmt = SAVEPV(proto_perl->Iofmt);
|
|
|
|
/* interpreter atexit processing */
|
|
PL_exitlistlen = proto_perl->Iexitlistlen;
|
|
if (PL_exitlistlen) {
|
|
New(0, PL_exitlist, PL_exitlistlen, PerlExitListEntry);
|
|
Copy(proto_perl->Iexitlist, PL_exitlist, PL_exitlistlen, PerlExitListEntry);
|
|
}
|
|
else
|
|
PL_exitlist = (PerlExitListEntry*)NULL;
|
|
PL_modglobal = hv_dup_inc(proto_perl->Imodglobal);
|
|
|
|
PL_profiledata = NULL;
|
|
PL_rsfp = fp_dup(proto_perl->Irsfp, '<');
|
|
/* PL_rsfp_filters entries have fake IoDIRP() */
|
|
PL_rsfp_filters = av_dup_inc(proto_perl->Irsfp_filters);
|
|
|
|
PL_compcv = cv_dup(proto_perl->Icompcv);
|
|
PL_comppad = av_dup(proto_perl->Icomppad);
|
|
PL_comppad_name = av_dup(proto_perl->Icomppad_name);
|
|
PL_comppad_name_fill = proto_perl->Icomppad_name_fill;
|
|
PL_comppad_name_floor = proto_perl->Icomppad_name_floor;
|
|
PL_curpad = (SV**)ptr_table_fetch(PL_ptr_table,
|
|
proto_perl->Tcurpad);
|
|
|
|
#ifdef HAVE_INTERP_INTERN
|
|
sys_intern_dup(&proto_perl->Isys_intern, &PL_sys_intern);
|
|
#endif
|
|
|
|
/* more statics moved here */
|
|
PL_generation = proto_perl->Igeneration;
|
|
PL_DBcv = cv_dup(proto_perl->IDBcv);
|
|
|
|
PL_in_clean_objs = proto_perl->Iin_clean_objs;
|
|
PL_in_clean_all = proto_perl->Iin_clean_all;
|
|
|
|
PL_uid = proto_perl->Iuid;
|
|
PL_euid = proto_perl->Ieuid;
|
|
PL_gid = proto_perl->Igid;
|
|
PL_egid = proto_perl->Iegid;
|
|
PL_nomemok = proto_perl->Inomemok;
|
|
PL_an = proto_perl->Ian;
|
|
PL_cop_seqmax = proto_perl->Icop_seqmax;
|
|
PL_op_seqmax = proto_perl->Iop_seqmax;
|
|
PL_evalseq = proto_perl->Ievalseq;
|
|
PL_origenviron = proto_perl->Iorigenviron; /* XXX not quite right */
|
|
PL_origalen = proto_perl->Iorigalen;
|
|
PL_pidstatus = newHV(); /* XXX flag for cloning? */
|
|
PL_osname = SAVEPV(proto_perl->Iosname);
|
|
PL_sh_path = SAVEPV(proto_perl->Ish_path);
|
|
PL_sighandlerp = proto_perl->Isighandlerp;
|
|
|
|
|
|
PL_runops = proto_perl->Irunops;
|
|
|
|
Copy(proto_perl->Itokenbuf, PL_tokenbuf, 256, char);
|
|
|
|
#ifdef CSH
|
|
PL_cshlen = proto_perl->Icshlen;
|
|
PL_cshname = SAVEPVN(proto_perl->Icshname, PL_cshlen);
|
|
#endif
|
|
|
|
PL_lex_state = proto_perl->Ilex_state;
|
|
PL_lex_defer = proto_perl->Ilex_defer;
|
|
PL_lex_expect = proto_perl->Ilex_expect;
|
|
PL_lex_formbrack = proto_perl->Ilex_formbrack;
|
|
PL_lex_dojoin = proto_perl->Ilex_dojoin;
|
|
PL_lex_starts = proto_perl->Ilex_starts;
|
|
PL_lex_stuff = sv_dup_inc(proto_perl->Ilex_stuff);
|
|
PL_lex_repl = sv_dup_inc(proto_perl->Ilex_repl);
|
|
PL_lex_op = proto_perl->Ilex_op;
|
|
PL_lex_inpat = proto_perl->Ilex_inpat;
|
|
PL_lex_inwhat = proto_perl->Ilex_inwhat;
|
|
PL_lex_brackets = proto_perl->Ilex_brackets;
|
|
i = (PL_lex_brackets < 120 ? 120 : PL_lex_brackets);
|
|
PL_lex_brackstack = SAVEPVN(proto_perl->Ilex_brackstack,i);
|
|
PL_lex_casemods = proto_perl->Ilex_casemods;
|
|
i = (PL_lex_casemods < 12 ? 12 : PL_lex_casemods);
|
|
PL_lex_casestack = SAVEPVN(proto_perl->Ilex_casestack,i);
|
|
|
|
Copy(proto_perl->Inextval, PL_nextval, 5, YYSTYPE);
|
|
Copy(proto_perl->Inexttype, PL_nexttype, 5, I32);
|
|
PL_nexttoke = proto_perl->Inexttoke;
|
|
|
|
PL_linestr = sv_dup_inc(proto_perl->Ilinestr);
|
|
i = proto_perl->Ibufptr - SvPVX(proto_perl->Ilinestr);
|
|
PL_bufptr = SvPVX(PL_linestr) + (i < 0 ? 0 : i);
|
|
i = proto_perl->Ioldbufptr - SvPVX(proto_perl->Ilinestr);
|
|
PL_oldbufptr = SvPVX(PL_linestr) + (i < 0 ? 0 : i);
|
|
i = proto_perl->Ioldoldbufptr - SvPVX(proto_perl->Ilinestr);
|
|
PL_oldoldbufptr = SvPVX(PL_linestr) + (i < 0 ? 0 : i);
|
|
PL_bufend = SvPVX(PL_linestr) + SvCUR(PL_linestr);
|
|
i = proto_perl->Ilinestart - SvPVX(proto_perl->Ilinestr);
|
|
PL_linestart = SvPVX(PL_linestr) + (i < 0 ? 0 : i);
|
|
PL_pending_ident = proto_perl->Ipending_ident;
|
|
PL_sublex_info = proto_perl->Isublex_info; /* XXX not quite right */
|
|
|
|
PL_expect = proto_perl->Iexpect;
|
|
|
|
PL_multi_start = proto_perl->Imulti_start;
|
|
PL_multi_end = proto_perl->Imulti_end;
|
|
PL_multi_open = proto_perl->Imulti_open;
|
|
PL_multi_close = proto_perl->Imulti_close;
|
|
|
|
PL_error_count = proto_perl->Ierror_count;
|
|
PL_subline = proto_perl->Isubline;
|
|
PL_subname = sv_dup_inc(proto_perl->Isubname);
|
|
|
|
PL_min_intro_pending = proto_perl->Imin_intro_pending;
|
|
PL_max_intro_pending = proto_perl->Imax_intro_pending;
|
|
PL_padix = proto_perl->Ipadix;
|
|
PL_padix_floor = proto_perl->Ipadix_floor;
|
|
PL_pad_reset_pending = proto_perl->Ipad_reset_pending;
|
|
|
|
i = proto_perl->Ilast_uni - SvPVX(proto_perl->Ilinestr);
|
|
PL_last_uni = SvPVX(PL_linestr) + (i < 0 ? 0 : i);
|
|
i = proto_perl->Ilast_lop - SvPVX(proto_perl->Ilinestr);
|
|
PL_last_lop = SvPVX(PL_linestr) + (i < 0 ? 0 : i);
|
|
PL_last_lop_op = proto_perl->Ilast_lop_op;
|
|
PL_in_my = proto_perl->Iin_my;
|
|
PL_in_my_stash = hv_dup(proto_perl->Iin_my_stash);
|
|
#ifdef FCRYPT
|
|
PL_cryptseen = proto_perl->Icryptseen;
|
|
#endif
|
|
|
|
PL_hints = proto_perl->Ihints;
|
|
|
|
PL_amagic_generation = proto_perl->Iamagic_generation;
|
|
|
|
#ifdef USE_LOCALE_COLLATE
|
|
PL_collation_ix = proto_perl->Icollation_ix;
|
|
PL_collation_name = SAVEPV(proto_perl->Icollation_name);
|
|
PL_collation_standard = proto_perl->Icollation_standard;
|
|
PL_collxfrm_base = proto_perl->Icollxfrm_base;
|
|
PL_collxfrm_mult = proto_perl->Icollxfrm_mult;
|
|
#endif /* USE_LOCALE_COLLATE */
|
|
|
|
#ifdef USE_LOCALE_NUMERIC
|
|
PL_numeric_name = SAVEPV(proto_perl->Inumeric_name);
|
|
PL_numeric_standard = proto_perl->Inumeric_standard;
|
|
PL_numeric_local = proto_perl->Inumeric_local;
|
|
PL_numeric_radix_sv = sv_dup_inc(proto_perl->Inumeric_radix_sv);
|
|
#endif /* !USE_LOCALE_NUMERIC */
|
|
|
|
/* utf8 character classes */
|
|
PL_utf8_alnum = sv_dup_inc(proto_perl->Iutf8_alnum);
|
|
PL_utf8_alnumc = sv_dup_inc(proto_perl->Iutf8_alnumc);
|
|
PL_utf8_ascii = sv_dup_inc(proto_perl->Iutf8_ascii);
|
|
PL_utf8_alpha = sv_dup_inc(proto_perl->Iutf8_alpha);
|
|
PL_utf8_space = sv_dup_inc(proto_perl->Iutf8_space);
|
|
PL_utf8_cntrl = sv_dup_inc(proto_perl->Iutf8_cntrl);
|
|
PL_utf8_graph = sv_dup_inc(proto_perl->Iutf8_graph);
|
|
PL_utf8_digit = sv_dup_inc(proto_perl->Iutf8_digit);
|
|
PL_utf8_upper = sv_dup_inc(proto_perl->Iutf8_upper);
|
|
PL_utf8_lower = sv_dup_inc(proto_perl->Iutf8_lower);
|
|
PL_utf8_print = sv_dup_inc(proto_perl->Iutf8_print);
|
|
PL_utf8_punct = sv_dup_inc(proto_perl->Iutf8_punct);
|
|
PL_utf8_xdigit = sv_dup_inc(proto_perl->Iutf8_xdigit);
|
|
PL_utf8_mark = sv_dup_inc(proto_perl->Iutf8_mark);
|
|
PL_utf8_toupper = sv_dup_inc(proto_perl->Iutf8_toupper);
|
|
PL_utf8_totitle = sv_dup_inc(proto_perl->Iutf8_totitle);
|
|
PL_utf8_tolower = sv_dup_inc(proto_perl->Iutf8_tolower);
|
|
|
|
/* swatch cache */
|
|
PL_last_swash_hv = Nullhv; /* reinits on demand */
|
|
PL_last_swash_klen = 0;
|
|
PL_last_swash_key[0]= '\0';
|
|
PL_last_swash_tmps = (U8*)NULL;
|
|
PL_last_swash_slen = 0;
|
|
|
|
/* perly.c globals */
|
|
PL_yydebug = proto_perl->Iyydebug;
|
|
PL_yynerrs = proto_perl->Iyynerrs;
|
|
PL_yyerrflag = proto_perl->Iyyerrflag;
|
|
PL_yychar = proto_perl->Iyychar;
|
|
PL_yyval = proto_perl->Iyyval;
|
|
PL_yylval = proto_perl->Iyylval;
|
|
|
|
PL_glob_index = proto_perl->Iglob_index;
|
|
PL_srand_called = proto_perl->Isrand_called;
|
|
PL_uudmap['M'] = 0; /* reinits on demand */
|
|
PL_bitcount = Nullch; /* reinits on demand */
|
|
|
|
if (proto_perl->Ipsig_ptr) {
|
|
int sig_num[] = { SIG_NUM };
|
|
Newz(0, PL_psig_ptr, sizeof(sig_num)/sizeof(*sig_num), SV*);
|
|
Newz(0, PL_psig_name, sizeof(sig_num)/sizeof(*sig_num), SV*);
|
|
for (i = 1; PL_sig_name[i]; i++) {
|
|
PL_psig_ptr[i] = sv_dup_inc(proto_perl->Ipsig_ptr[i]);
|
|
PL_psig_name[i] = sv_dup_inc(proto_perl->Ipsig_name[i]);
|
|
}
|
|
}
|
|
else {
|
|
PL_psig_ptr = (SV**)NULL;
|
|
PL_psig_name = (SV**)NULL;
|
|
}
|
|
|
|
/* thrdvar.h stuff */
|
|
|
|
if (flags & CLONEf_COPY_STACKS) {
|
|
/* next allocation will be PL_tmps_stack[PL_tmps_ix+1] */
|
|
PL_tmps_ix = proto_perl->Ttmps_ix;
|
|
PL_tmps_max = proto_perl->Ttmps_max;
|
|
PL_tmps_floor = proto_perl->Ttmps_floor;
|
|
Newz(50, PL_tmps_stack, PL_tmps_max, SV*);
|
|
i = 0;
|
|
while (i <= PL_tmps_ix) {
|
|
PL_tmps_stack[i] = sv_dup_inc(proto_perl->Ttmps_stack[i]);
|
|
++i;
|
|
}
|
|
|
|
/* next PUSHMARK() sets *(PL_markstack_ptr+1) */
|
|
i = proto_perl->Tmarkstack_max - proto_perl->Tmarkstack;
|
|
Newz(54, PL_markstack, i, I32);
|
|
PL_markstack_max = PL_markstack + (proto_perl->Tmarkstack_max
|
|
- proto_perl->Tmarkstack);
|
|
PL_markstack_ptr = PL_markstack + (proto_perl->Tmarkstack_ptr
|
|
- proto_perl->Tmarkstack);
|
|
Copy(proto_perl->Tmarkstack, PL_markstack,
|
|
PL_markstack_ptr - PL_markstack + 1, I32);
|
|
|
|
/* next push_scope()/ENTER sets PL_scopestack[PL_scopestack_ix]
|
|
* NOTE: unlike the others! */
|
|
PL_scopestack_ix = proto_perl->Tscopestack_ix;
|
|
PL_scopestack_max = proto_perl->Tscopestack_max;
|
|
Newz(54, PL_scopestack, PL_scopestack_max, I32);
|
|
Copy(proto_perl->Tscopestack, PL_scopestack, PL_scopestack_ix, I32);
|
|
|
|
/* next push_return() sets PL_retstack[PL_retstack_ix]
|
|
* NOTE: unlike the others! */
|
|
PL_retstack_ix = proto_perl->Tretstack_ix;
|
|
PL_retstack_max = proto_perl->Tretstack_max;
|
|
Newz(54, PL_retstack, PL_retstack_max, OP*);
|
|
Copy(proto_perl->Tretstack, PL_retstack, PL_retstack_ix, I32);
|
|
|
|
/* NOTE: si_dup() looks at PL_markstack */
|
|
PL_curstackinfo = si_dup(proto_perl->Tcurstackinfo);
|
|
|
|
/* PL_curstack = PL_curstackinfo->si_stack; */
|
|
PL_curstack = av_dup(proto_perl->Tcurstack);
|
|
PL_mainstack = av_dup(proto_perl->Tmainstack);
|
|
|
|
/* next PUSHs() etc. set *(PL_stack_sp+1) */
|
|
PL_stack_base = AvARRAY(PL_curstack);
|
|
PL_stack_sp = PL_stack_base + (proto_perl->Tstack_sp
|
|
- proto_perl->Tstack_base);
|
|
PL_stack_max = PL_stack_base + AvMAX(PL_curstack);
|
|
|
|
/* next SSPUSHFOO() sets PL_savestack[PL_savestack_ix]
|
|
* NOTE: unlike the others! */
|
|
PL_savestack_ix = proto_perl->Tsavestack_ix;
|
|
PL_savestack_max = proto_perl->Tsavestack_max;
|
|
/*Newz(54, PL_savestack, PL_savestack_max, ANY);*/
|
|
PL_savestack = ss_dup(proto_perl);
|
|
}
|
|
else {
|
|
init_stacks();
|
|
ENTER; /* perl_destruct() wants to LEAVE; */
|
|
}
|
|
|
|
PL_start_env = proto_perl->Tstart_env; /* XXXXXX */
|
|
PL_top_env = &PL_start_env;
|
|
|
|
PL_op = proto_perl->Top;
|
|
|
|
PL_Sv = Nullsv;
|
|
PL_Xpv = (XPV*)NULL;
|
|
PL_na = proto_perl->Tna;
|
|
|
|
PL_statbuf = proto_perl->Tstatbuf;
|
|
PL_statcache = proto_perl->Tstatcache;
|
|
PL_statgv = gv_dup(proto_perl->Tstatgv);
|
|
PL_statname = sv_dup_inc(proto_perl->Tstatname);
|
|
#ifdef HAS_TIMES
|
|
PL_timesbuf = proto_perl->Ttimesbuf;
|
|
#endif
|
|
|
|
PL_tainted = proto_perl->Ttainted;
|
|
PL_curpm = proto_perl->Tcurpm; /* XXX No PMOP ref count */
|
|
PL_nrs = sv_dup_inc(proto_perl->Tnrs);
|
|
PL_rs = sv_dup_inc(proto_perl->Trs);
|
|
PL_last_in_gv = gv_dup(proto_perl->Tlast_in_gv);
|
|
PL_ofslen = proto_perl->Tofslen;
|
|
PL_ofs = SAVEPVN(proto_perl->Tofs, PL_ofslen);
|
|
PL_defoutgv = gv_dup_inc(proto_perl->Tdefoutgv);
|
|
PL_chopset = proto_perl->Tchopset; /* XXX never deallocated */
|
|
PL_toptarget = sv_dup_inc(proto_perl->Ttoptarget);
|
|
PL_bodytarget = sv_dup_inc(proto_perl->Tbodytarget);
|
|
PL_formtarget = sv_dup(proto_perl->Tformtarget);
|
|
|
|
PL_restartop = proto_perl->Trestartop;
|
|
PL_in_eval = proto_perl->Tin_eval;
|
|
PL_delaymagic = proto_perl->Tdelaymagic;
|
|
PL_dirty = proto_perl->Tdirty;
|
|
PL_localizing = proto_perl->Tlocalizing;
|
|
|
|
#ifdef PERL_FLEXIBLE_EXCEPTIONS
|
|
PL_protect = proto_perl->Tprotect;
|
|
#endif
|
|
PL_errors = sv_dup_inc(proto_perl->Terrors);
|
|
PL_av_fetch_sv = Nullsv;
|
|
PL_hv_fetch_sv = Nullsv;
|
|
Zero(&PL_hv_fetch_ent_mh, 1, HE); /* XXX */
|
|
PL_modcount = proto_perl->Tmodcount;
|
|
PL_lastgotoprobe = Nullop;
|
|
PL_dumpindent = proto_perl->Tdumpindent;
|
|
|
|
PL_sortcop = (OP*)any_dup(proto_perl->Tsortcop, proto_perl);
|
|
PL_sortstash = hv_dup(proto_perl->Tsortstash);
|
|
PL_firstgv = gv_dup(proto_perl->Tfirstgv);
|
|
PL_secondgv = gv_dup(proto_perl->Tsecondgv);
|
|
PL_sortcxix = proto_perl->Tsortcxix;
|
|
PL_efloatbuf = Nullch; /* reinits on demand */
|
|
PL_efloatsize = 0; /* reinits on demand */
|
|
|
|
/* regex stuff */
|
|
|
|
PL_screamfirst = NULL;
|
|
PL_screamnext = NULL;
|
|
PL_maxscream = -1; /* reinits on demand */
|
|
PL_lastscream = Nullsv;
|
|
|
|
PL_watchaddr = NULL;
|
|
PL_watchok = Nullch;
|
|
|
|
PL_regdummy = proto_perl->Tregdummy;
|
|
PL_regcomp_parse = Nullch;
|
|
PL_regxend = Nullch;
|
|
PL_regcode = (regnode*)NULL;
|
|
PL_regnaughty = 0;
|
|
PL_regsawback = 0;
|
|
PL_regprecomp = Nullch;
|
|
PL_regnpar = 0;
|
|
PL_regsize = 0;
|
|
PL_regflags = 0;
|
|
PL_regseen = 0;
|
|
PL_seen_zerolen = 0;
|
|
PL_seen_evals = 0;
|
|
PL_regcomp_rx = (regexp*)NULL;
|
|
PL_extralen = 0;
|
|
PL_colorset = 0; /* reinits PL_colors[] */
|
|
/*PL_colors[6] = {0,0,0,0,0,0};*/
|
|
PL_reg_whilem_seen = 0;
|
|
PL_reginput = Nullch;
|
|
PL_regbol = Nullch;
|
|
PL_regeol = Nullch;
|
|
PL_regstartp = (I32*)NULL;
|
|
PL_regendp = (I32*)NULL;
|
|
PL_reglastparen = (U32*)NULL;
|
|
PL_regtill = Nullch;
|
|
PL_regprev = '\n';
|
|
PL_reg_start_tmp = (char**)NULL;
|
|
PL_reg_start_tmpl = 0;
|
|
PL_regdata = (struct reg_data*)NULL;
|
|
PL_bostr = Nullch;
|
|
PL_reg_flags = 0;
|
|
PL_reg_eval_set = 0;
|
|
PL_regnarrate = 0;
|
|
PL_regprogram = (regnode*)NULL;
|
|
PL_regindent = 0;
|
|
PL_regcc = (CURCUR*)NULL;
|
|
PL_reg_call_cc = (struct re_cc_state*)NULL;
|
|
PL_reg_re = (regexp*)NULL;
|
|
PL_reg_ganch = Nullch;
|
|
PL_reg_sv = Nullsv;
|
|
PL_reg_magic = (MAGIC*)NULL;
|
|
PL_reg_oldpos = 0;
|
|
PL_reg_oldcurpm = (PMOP*)NULL;
|
|
PL_reg_curpm = (PMOP*)NULL;
|
|
PL_reg_oldsaved = Nullch;
|
|
PL_reg_oldsavedlen = 0;
|
|
PL_reg_maxiter = 0;
|
|
PL_reg_leftiter = 0;
|
|
PL_reg_poscache = Nullch;
|
|
PL_reg_poscache_size= 0;
|
|
|
|
/* RE engine - function pointers */
|
|
PL_regcompp = proto_perl->Tregcompp;
|
|
PL_regexecp = proto_perl->Tregexecp;
|
|
PL_regint_start = proto_perl->Tregint_start;
|
|
PL_regint_string = proto_perl->Tregint_string;
|
|
PL_regfree = proto_perl->Tregfree;
|
|
|
|
PL_reginterp_cnt = 0;
|
|
PL_reg_starttry = 0;
|
|
|
|
if (!(flags & CLONEf_KEEP_PTR_TABLE)) {
|
|
ptr_table_free(PL_ptr_table);
|
|
PL_ptr_table = NULL;
|
|
}
|
|
|
|
#ifdef PERL_OBJECT
|
|
return (PerlInterpreter*)pPerl;
|
|
#else
|
|
return my_perl;
|
|
#endif
|
|
}
|
|
|
|
#else /* !USE_ITHREADS */
|
|
|
|
#ifdef PERL_OBJECT
|
|
#include "XSUB.h"
|
|
#endif
|
|
|
|
#endif /* USE_ITHREADS */
|
|
|
|
static void
|
|
do_report_used(pTHXo_ SV *sv)
|
|
{
|
|
if (SvTYPE(sv) != SVTYPEMASK) {
|
|
PerlIO_printf(Perl_debug_log, "****\n");
|
|
sv_dump(sv);
|
|
}
|
|
}
|
|
|
|
static void
|
|
do_clean_objs(pTHXo_ SV *sv)
|
|
{
|
|
SV* rv;
|
|
|
|
if (SvROK(sv) && SvOBJECT(rv = SvRV(sv))) {
|
|
DEBUG_D((PerlIO_printf(Perl_debug_log, "Cleaning object ref:\n "), sv_dump(sv));)
|
|
if (SvWEAKREF(sv)) {
|
|
sv_del_backref(sv);
|
|
SvWEAKREF_off(sv);
|
|
SvRV(sv) = 0;
|
|
} else {
|
|
SvROK_off(sv);
|
|
SvRV(sv) = 0;
|
|
SvREFCNT_dec(rv);
|
|
}
|
|
}
|
|
|
|
/* XXX Might want to check arrays, etc. */
|
|
}
|
|
|
|
#ifndef DISABLE_DESTRUCTOR_KLUDGE
|
|
static void
|
|
do_clean_named_objs(pTHXo_ SV *sv)
|
|
{
|
|
if (SvTYPE(sv) == SVt_PVGV && GvGP(sv)) {
|
|
if ( SvOBJECT(GvSV(sv)) ||
|
|
(GvAV(sv) && SvOBJECT(GvAV(sv))) ||
|
|
(GvHV(sv) && SvOBJECT(GvHV(sv))) ||
|
|
(GvIO(sv) && SvOBJECT(GvIO(sv))) ||
|
|
(GvCV(sv) && SvOBJECT(GvCV(sv))) )
|
|
{
|
|
DEBUG_D((PerlIO_printf(Perl_debug_log, "Cleaning named glob object:\n "), sv_dump(sv));)
|
|
SvREFCNT_dec(sv);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
static void
|
|
do_clean_all(pTHXo_ SV *sv)
|
|
{
|
|
DEBUG_D((PerlIO_printf(Perl_debug_log, "Cleaning loops: SV at 0x%"UVxf"\n", PTR2UV(sv)) );)
|
|
SvFLAGS(sv) |= SVf_BREAK;
|
|
SvREFCNT_dec(sv);
|
|
}
|
|
|