#include "regcomp.h"
#define FCALL *f
-#define SV_CHECK_THINKFIRST(sv) if (SvTHINKFIRST(sv)) sv_force_normal(sv)
+#ifdef PERL_COPY_ON_WRITE
+#define SV_COW_NEXT_SV(sv) INT2PTR(SV *,SvUVX(sv))
+/* This is a pessamistic view. Scalar must be purely a read-write PV to copy-
+ on-write. */
+#define CAN_COW_MASK (SVs_OBJECT|SVs_GMG|SVs_SMG|SVf_IOK|SVf_NOK|SVf_POK| \
+ SVf_ROK|SVp_IOK|SVp_NOK|SVp_POK|SVf_FAKE|SVf_OOK| \
+ SVf_BREAK|SVf_READONLY|SVf_AMAGIC)
+#define CAN_COW_FLAGS (SVp_POK|SVf_POK)
+#endif
/* ============================================================================
MAGIC* magic = NULL;
HV* stash = Nullhv;
- if (mt != SVt_PV && SvREADONLY(sv) && SvFAKE(sv)) {
- sv_force_normal(sv);
+ if (mt != SVt_PV && SvIsCOW(sv)) {
+ sv_force_normal_flags(sv, 0);
}
if (SvTYPE(sv) == mt)
Renew(s,newlen,char);
}
else {
- /* sv_force_normal_flags() must not try to unshare the new
- PVX we allocate below. AMS 20010713 */
- if (SvREADONLY(sv) && SvFAKE(sv)) {
- SvFAKE_off(sv);
- SvREADONLY_off(sv);
- }
New(703, s, newlen, char);
if (SvPVX(sv) && SvCUR(sv)) {
Move(SvPVX(sv), s, (newlen < SvCUR(sv)) ? newlen : SvCUR(sv), char);
void
Perl_sv_setiv(pTHX_ register SV *sv, IV i)
{
- SV_CHECK_THINKFIRST(sv);
+ SV_CHECK_THINKFIRST_COW_DROP(sv);
switch (SvTYPE(sv)) {
case SVt_NULL:
sv_upgrade(sv, SVt_IV);
void
Perl_sv_setnv(pTHX_ register SV *sv, NV num)
{
- SV_CHECK_THINKFIRST(sv);
+ SV_CHECK_THINKFIRST_COW_DROP(sv);
switch (SvTYPE(sv)) {
case SVt_NULL:
case SVt_IV:
return SvIV(tmpstr);
return PTR2IV(SvRV(sv));
}
- if (SvREADONLY(sv) && SvFAKE(sv)) {
- sv_force_normal(sv);
+ if (SvIsCOW(sv)) {
+ sv_force_normal_flags(sv, 0);
}
if (SvREADONLY(sv) && !SvOK(sv)) {
if (ckWARN(WARN_UNINITIALIZED))
return SvUV(tmpstr);
return PTR2UV(SvRV(sv));
}
- if (SvREADONLY(sv) && SvFAKE(sv)) {
- sv_force_normal(sv);
+ if (SvIsCOW(sv)) {
+ sv_force_normal_flags(sv, 0);
}
if (SvREADONLY(sv) && !SvOK(sv)) {
if (ckWARN(WARN_UNINITIALIZED))
return SvNV(tmpstr);
return PTR2NV(SvRV(sv));
}
- if (SvREADONLY(sv) && SvFAKE(sv)) {
- sv_force_normal(sv);
+ if (SvIsCOW(sv)) {
+ sv_force_normal_flags(sv, 0);
}
if (SvREADONLY(sv) && !SvOK(sv)) {
if (ckWARN(WARN_UNINITIALIZED))
if (SvUTF8(sv))
return SvCUR(sv);
- if (SvREADONLY(sv) && SvFAKE(sv)) {
- sv_force_normal(sv);
+ if (SvIsCOW(sv)) {
+ sv_force_normal_flags(sv, 0);
}
if (PL_encoding)
U8 *s;
STRLEN len;
- if (SvREADONLY(sv) && SvFAKE(sv))
- sv_force_normal(sv);
+ if (SvIsCOW(sv)) {
+ sv_force_normal_flags(sv, 0);
+ }
s = (U8 *) SvPV(sv, len);
if (!utf8_to_bytes(s, &len)) {
if (fail_ok)
if (sstr == dstr)
return;
- SV_CHECK_THINKFIRST(dstr);
+ SV_CHECK_THINKFIRST_COW_DROP(dstr);
if (!sstr)
sstr = &PL_sv_undef;
stype = SvTYPE(sstr);
}
}
else if (sflags & SVp_POK) {
+ bool isSwipe = 0;
/*
* Check to see if we can just swipe the string. If so, it's a
* 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? */
- SvLEN(sstr) && /* and really is a string */
+ if (
+#ifdef PERL_COPY_ON_WRITE
+ (sflags & (SVf_FAKE | SVf_READONLY)) != (SVf_FAKE | SVf_READONLY)
+ &&
+#endif
+ !(isSwipe =
+ (sflags & SVs_TEMP) && /* slated for free anyway? */
+ !(sflags & SVf_OOK) && /* and not involved in OOK hack? */
+ SvREFCNT(sstr) == 1 && /* and no other references to it? */
+ SvLEN(sstr) && /* and really is a string */
/* and won't be needed again, potentially */
- !(PL_op && PL_op->op_type == OP_AASSIGN))
- {
+ !(PL_op && PL_op->op_type == OP_AASSIGN))
+#ifdef PERL_COPY_ON_WRITE
+ && !((sflags & CAN_COW_MASK) == CAN_COW_FLAGS
+ && SvTYPE(sstr) >= SVt_PVIV)
+#endif
+ ) {
+ /* Failed the swipe test, and it's not a shared hash key either.
+ Have to copy the 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);
+ } else {
+ /* If PERL_COPY_ON_WRITE is not defined, then isSwipe will always
+ be true in here. */
+#ifdef PERL_COPY_ON_WRITE
+ /* Either it's a shared hash key, or it's suitable for
+ copy-on-write or we can swipe the string. */
+ if (DEBUG_C_TEST) {
+ PerlIO_printf(Perl_debug_log,
+ "Copy on write: sstr --> dstr\n");
+ Perl_sv_dump(sstr);
+ Perl_sv_dump(dstr);
+ }
+ if (!isSwipe) {
+ /* I believe I should acquire a global SV mutex if
+ it's a COW sv (not a shared hash key) to stop
+ it going un copy-on-write.
+ If the source SV has gone un copy on write between up there
+ and down here, then (assert() that) it is of the correct
+ form to make it copy on write again */
+ if ((sflags & (SVf_FAKE | SVf_READONLY))
+ != (SVf_FAKE | SVf_READONLY)) {
+ SvREADONLY_on(sstr);
+ SvFAKE_on(sstr);
+ /* Make the source SV into a loop of 1.
+ (about to become 2) */
+ SV_COW_NEXT_SV(sstr) = sstr;
+ }
+ }
+#endif
+ /* Initial code is common. */
if (SvPVX(dstr)) { /* we know that dtype >= SVt_PV */
if (SvOOK(dstr)) {
SvFLAGS(dstr) &= ~SVf_OOK;
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);
- }
+
+#ifdef PERL_COPY_ON_WRITE
+ if (!isSwipe) {
+ /* making another shared SV. */
+ STRLEN cur = SvCUR(sstr);
+ STRLEN len = SvLEN(sstr);
+ if (len) {
+ /* SvIsCOW_normal */
+ /* splice us in between source and next-after-source. */
+ SV_COW_NEXT_SV(dstr) = SV_COW_NEXT_SV(sstr);
+ SV_COW_NEXT_SV(sstr) = dstr;
+ SvPV_set(dstr, SvPVX(sstr));
+ } else {
+ /* SvIsCOW_shared_hash */
+ UV hash = SvUVX(sstr);
+ DEBUG_C(PerlIO_printf(Perl_debug_log,
+ "Copy on write: Sharing hash\n"));
+ SvPV_set(dstr,
+ sharepvn(SvPVX(sstr),
+ (sflags & SVf_UTF8?-cur:cur), hash));
+ SvUVX(dstr) = hash;
+ }
+ SvLEN(dstr) = len;
+ SvCUR(dstr) = cur;
+ SvREADONLY_on(dstr);
+ SvFAKE_on(dstr);
+ /* Relesase a global SV mutex. */
+ }
+ else
+#endif
+ { /* Passes the swipe test. */
+ 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);
+ }
+ }
if (sflags & SVf_UTF8)
SvUTF8_on(dstr);
/*SUPPRESS 560*/
SvIsUV_on(dstr);
SvIVX(dstr) = SvIVX(sstr);
}
+ if (SvVOK(sstr)) {
+ MAGIC *mg = SvMAGIC(sstr);
+ sv_magicext(dstr, NULL, PERL_MAGIC_vstring, NULL,
+ mg->mg_ptr, mg->mg_len);
+ SvRMAGICAL_on(dstr);
+ }
}
else if (sflags & SVp_IOK) {
if (sflags & SVf_IOK)
{
register char *dptr;
- SV_CHECK_THINKFIRST(sv);
+ SV_CHECK_THINKFIRST_COW_DROP(sv);
if (!ptr) {
(void)SvOK_off(sv);
return;
{
register STRLEN len;
- SV_CHECK_THINKFIRST(sv);
+ SV_CHECK_THINKFIRST_COW_DROP(sv);
if (!ptr) {
(void)SvOK_off(sv);
return;
void
Perl_sv_usepvn(pTHX_ register SV *sv, register char *ptr, register STRLEN len)
{
- SV_CHECK_THINKFIRST(sv);
+ SV_CHECK_THINKFIRST_COW_DROP(sv);
(void)SvUPGRADE(sv, SVt_PV);
if (!ptr) {
(void)SvOK_off(sv);
SvSETMAGIC(sv);
}
+#ifdef PERL_COPY_ON_WRITE
+/* Need to do this *after* making the SV normal, as we need the buffer
+ pointer to remain valid until after we've copied it. If we let go too early,
+ another thread could invalidate it by unsharing last of the same hash key
+ (which it can do by means other than releasing copy-on-write Svs)
+ or by changing the other copy-on-write SVs in the loop. */
+STATIC void
+S_sv_release_COW(pTHX_ register SV *sv, char *pvx, STRLEN cur, STRLEN len,
+ U32 hash, SV *after)
+{
+ if (len) { /* this SV was SvIsCOW_normal(sv) */
+ /* we need to find the SV pointing to us. */
+ SV *current = SV_COW_NEXT_SV(after);
+
+ if (current == sv) {
+ /* The SV we point to points back to us (there were only two of us
+ in the loop.)
+ Hence other SV is no longer copy on write either. */
+ SvFAKE_off(after);
+ SvREADONLY_off(after);
+ } else {
+ /* We need to follow the pointers around the loop. */
+ SV *next;
+ while ((next = SV_COW_NEXT_SV(current)) != sv) {
+ assert (next);
+ current = next;
+ /* don't loop forever if the structure is bust, and we have
+ a pointer into a closed loop. */
+ assert (current != after);
+ }
+ /* Make the SV before us point to the SV after us. */
+ SV_COW_NEXT_SV(current) = after;
+ }
+ } else {
+ unsharepvn(pvx, SvUTF8(sv) ? -(I32)cur : cur, hash);
+ }
+}
+
+int
+Perl_sv_release_IVX(pTHX_ register SV *sv)
+{
+ if (SvIsCOW(sv))
+ sv_force_normal_flags(sv, 0);
+ return SvOOK_off(sv);
+}
+#endif
/*
=for apidoc sv_force_normal_flags
Undo various types of fakery on an SV: if the PV is a shared string, make
a private copy; if we're a ref, stop refing; if we're a glob, downgrade to
-an xpvmg. The C<flags> parameter gets passed to C<sv_unref_flags()>
-when unrefing. C<sv_force_normal> calls this function with flags set to 0.
+an xpvmg; if we're a copy-on-write scalar, this is the on-write time when
+we do the copy, and is also used locally. If C<SV_COW_DROP_PV> is set
+then a copy-on-write scalar drops its PV buffer (if any) and becomes
+SvPOK_off rather than making a copy. (Used where this scalar is about to be
+set to some other value. In addtion, the C<flags> parameter gets passed to
+C<sv_unref_flags()> when unrefing. C<sv_force_normal> calls this function
+with flags set to 0.
=cut
*/
void
Perl_sv_force_normal_flags(pTHX_ register SV *sv, U32 flags)
{
+#ifdef PERL_COPY_ON_WRITE
+ if (SvREADONLY(sv)) {
+ /* At this point I believe I should acquire a global SV mutex. */
+ if (SvFAKE(sv)) {
+ char *pvx = SvPVX(sv);
+ STRLEN len = SvLEN(sv);
+ STRLEN cur = SvCUR(sv);
+ U32 hash = SvUVX(sv);
+ SV *next = SV_COW_NEXT_SV(sv); /* next COW sv in the loop. */
+ if (DEBUG_C_TEST) {
+ PerlIO_printf(Perl_debug_log,
+ "Copy on write: Force normal %ld\n",
+ (long) flags);
+ Perl_sv_dump(sv);
+ }
+ SvFAKE_off(sv);
+ SvREADONLY_off(sv);
+ /* This SV doesn't own the buffer, so need to New() a new one: */
+ SvPVX(sv) = 0;
+ SvLEN(sv) = 0;
+ if (flags & SV_COW_DROP_PV) {
+ /* OK, so we don't need to copy our buffer. */
+ SvPOK_off(sv);
+ } else {
+ SvGROW(sv, cur + 1);
+ Move(pvx,SvPVX(sv),cur,char);
+ SvCUR(sv) = cur;
+ *SvEND(sv) = '\0';
+ }
+ S_sv_release_COW(sv, pvx, cur, len, hash, next);
+ if (DEBUG_C_TEST) {
+ Perl_sv_dump(sv);
+ }
+ }
+ else if (PL_curcop != &PL_compiling)
+ Perl_croak(aTHX_ PL_no_modify);
+ /* At this point I believe that I can drop the global SV mutex. */
+ }
+#else
if (SvREADONLY(sv)) {
if (SvFAKE(sv)) {
char *pvx = SvPVX(sv);
else if (PL_curcop != &PL_compiling)
Perl_croak(aTHX_ PL_no_modify);
}
+#endif
if (SvROK(sv))
sv_unref_flags(sv, flags);
else if (SvFAKE(sv) && SvTYPE(sv) == SVt_PVGV)
each other. To prevent 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.
+
Note we cannot do this to avoid self-tie loops as intervening RV must
- have its REFCNT incremented to keep it in existence - instead special
- case them in mg_free().
- */
+ have its REFCNT incremented to keep it in existence - instead we could
+ special case them in sv_free() -- NI-S
+
+ */
if (!obj || obj == sv ||
how == PERL_MAGIC_arylen ||
how == PERL_MAGIC_qr ||
else {
mg->mg_obj = SvREFCNT_inc(obj);
mg->mg_flags |= MGf_REFCOUNTED;
-
- /* Break self-tie loops */
- if (how == PERL_MAGIC_tiedscalar && SvROK(obj) &&
- (SvRV(obj) == sv || GvIO(SvRV(obj)) == (IO *) sv)) {
- /* We have to have a REFCNT to obj, so drop REFCNT
- of what if references instead
- */
- SvREFCNT_dec(SvRV(obj));
- }
}
mg->mg_type = how;
mg->mg_len = namlen;
MAGIC* mg;
MGVTBL *vtable = 0;
+#ifdef PERL_COPY_ON_WRITE
+ if (SvIsCOW(sv))
+ sv_force_normal_flags(sv, 0);
+#endif
if (SvREADONLY(sv)) {
if (PL_curcop != &PL_compiling
&& how != PERL_MAGIC_regex_global
Perl_sv_replace(pTHX_ register SV *sv, register SV *nsv)
{
U32 refcnt = SvREFCNT(sv);
- SV_CHECK_THINKFIRST(sv);
+ SV_CHECK_THINKFIRST_COW_DROP(sv);
if (SvREFCNT(nsv) != 1 && ckWARN_d(WARN_INTERNAL))
Perl_warner(aTHX_ packWARN(WARN_INTERNAL), "Reference miscount in sv_replace()");
if (SvMAGICAL(sv)) {
else
SvREFCNT_dec(SvRV(sv));
}
+#ifdef PERL_COPY_ON_WRITE
+ else if (SvPVX(sv)) {
+ if (SvIsCOW(sv)) {
+ /* I believe I need to grab the global SV mutex here and
+ then recheck the COW status. */
+ if (DEBUG_C_TEST) {
+ PerlIO_printf(Perl_debug_log, "Copy on write: clear\n");
+ Perl_sv_dump(sv);
+ }
+ S_sv_release_COW(sv, SvPVX(sv), SvCUR(sv), SvLEN(sv),
+ SvUVX(sv), SV_COW_NEXT_SV(sv));
+ /* And drop it here. */
+ SvFAKE_off(sv);
+ } else if (SvLEN(sv)) {
+ Safefree(SvPVX(sv));
+ }
+ }
+#else
else if (SvPVX(sv) && SvLEN(sv))
Safefree(SvPVX(sv));
else if (SvPVX(sv) && SvREADONLY(sv) && SvFAKE(sv)) {
SvUVX(sv));
SvFAKE_off(sv);
}
+#endif
break;
/*
case SVt_NV:
return;
}
ATOMIC_DEC_AND_TEST(refcount_is_zero, SvREFCNT(sv));
- if (!refcount_is_zero) {
- /* Do not be tempted to test SvMAGIC here till scope.c
- stops sharing MAGIC * between SVs
- */
+ if (!refcount_is_zero)
return;
- }
#ifdef DEBUGGING
if (SvTEMP(sv)) {
if (ckWARN_d(WARN_DEBUGGING))
send = s + *offsetp;
len = 0;
while (s < send) {
- STRLEN n;
- /* Call utf8n_to_uvchr() to validate the sequence */
- utf8n_to_uvchr(s, UTF8SKIP(s), &n, 0);
+ STRLEN n = 1;
+ /* Call utf8n_to_uvchr() to validate the sequence
+ * (unless a simple non-UTF character) */
+ if (!UTF8_IS_INVARIANT(*s))
+ utf8n_to_uvchr(s, UTF8SKIP(s), &n, 0);
if (n > 0) {
s += n;
len++;
}
if (cur1 == cur2)
- eq = memEQ(pv1, pv2, cur1);
+ eq = (pv1 == pv2) || memEQ(pv1, pv2, cur1);
if (svrecode)
SvREFCNT_dec(svrecode);
I32 i = 0;
I32 rspara = 0;
- SV_CHECK_THINKFIRST(sv);
+ SV_CHECK_THINKFIRST_COW_DROP(sv);
+ /* XXX. If you make this PVIV, then copy on write can copy scalars read
+ from <>.
+ However, perlbench says it's slower, because the existing swipe code
+ is faster than copy on write.
+ Swings and roundabouts. */
(void)SvUPGRADE(sv, SVt_PV);
SvSCREAM_off(sv);
/* 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 (cnt > 0)
+ i = (U8)buf[cnt - 1];
+ else
+ i = EOF;
}
+ if (cnt < 0)
+ cnt = 0; /* we do need to re-set the sv even when cnt <= 0 */
if (append)
- sv_catpvn(sv, (char *) buf, cnt);
+ sv_catpvn(sv, (char *) buf, cnt);
else
- sv_setpvn(sv, (char *) buf, cnt);
+ sv_setpvn(sv, (char *) buf, cnt);
if (i != EOF && /* joy */
(!rslen ||
if (SvGMAGICAL(sv))
mg_get(sv);
if (SvTHINKFIRST(sv)) {
- if (SvREADONLY(sv) && SvFAKE(sv))
- sv_force_normal(sv);
+ if (SvIsCOW(sv))
+ sv_force_normal_flags(sv, 0);
if (SvREADONLY(sv)) {
if (PL_curcop != &PL_compiling)
Perl_croak(aTHX_ PL_no_modify);
if (SvGMAGICAL(sv))
mg_get(sv);
if (SvTHINKFIRST(sv)) {
- if (SvREADONLY(sv) && SvFAKE(sv))
- sv_force_normal(sv);
+ if (SvIsCOW(sv))
+ sv_force_normal_flags(sv, 0);
if (SvREADONLY(sv)) {
if (PL_curcop != &PL_compiling)
Perl_croak(aTHX_ PL_no_modify);
Perl_sv_mortalcopy(pTHX_ SV *oldstr)
{
register SV *sv;
+
new_SV(sv);
sv_setsv(sv,oldstr);
EXTEND_MORTAL(1);
char *s = NULL;
if (SvTHINKFIRST(sv) && !SvROK(sv))
- sv_force_normal(sv);
+ sv_force_normal_flags(sv, 0);
if (SvPOK(sv)) {
*lp = SvCUR(sv);
case SVt_PVNV:
case SVt_PVMG:
case SVt_PVBM:
+ if (SvVOK(sv))
+ return "VSTRING";
if (SvROK(sv))
return "REF";
else
new_SV(sv);
- SV_CHECK_THINKFIRST(rv);
+ SV_CHECK_THINKFIRST_COW_DROP(rv);
SvAMAGIC_off(rv);
if (SvTYPE(rv) >= SVt_PVMG) {
}
SvRV(sv) = 0;
SvROK_off(sv);
- if (SvREFCNT(rv) != 1 || SvREADONLY(rv) || flags) /* SV_IMMEDIATE_UNREF */
+ if (SvREFCNT(rv) != 1 || SvREADONLY(rv) || (flags & SV_IMMEDIATE_UNREF))
SvREFCNT_dec(rv);
else /* XXX Hack, but hard to make $a=$a->[1] work otherwise */
sv_2mortal(rv); /* Schedule for freeing later */
/* large enough for "%#.#f" --chip */
/* what about long double NVs? --jhi */
- SV *vecsv;
+ SV *vecsv = Nullsv;
U8 *vecstr = Null(U8*);
STRLEN veclen = 0;
char c = 0;
unsigned base = 0;
IV iv = 0;
UV uv = 0;
+ /* we need a long double target in case HAS_LONG_DOUBLE but
+ not USE_LONG_DOUBLE
+ */
+#if defined(HAS_LONG_DOUBLE) && LONG_DOUBLESIZE > DOUBLESIZE
+ long double nv;
+#else
NV nv;
+#endif
STRLEN have;
STRLEN need;
STRLEN gap;
We allow format specification elements in this order:
\d+\$ explicit format parameter index
[-+ 0#]+ flags
- \*?(\d+\$)?v vector with optional (optionally specified) arg
+ v|\*(\d+\$)?v vector with optional (optionally specified) arg
\d+|\*(\d+\$)? width using optional (optionally specified) arg
\.(\d*|\*(\d+\$)?) precision using optional (optionally specified) arg
[hlqLV] size
q++;
if (*q == '*') {
q++;
- if (EXPECT_NUMBER(q, epix) && *q++ != '$') /* epix currently unused */
+ if (EXPECT_NUMBER(q, epix) && *q++ != '$')
+ goto unknown;
+ /* XXX: todo, support specified precision parameter */
+ if (epix)
goto unknown;
if (args)
i = va_arg(*args, int);
q++;
break;
#endif
-#if defined(HAS_QUAD) || (defined(HAS_LONG_DOUBLE) && defined(USE_LONG_DOUBLE))
+#if defined(HAS_QUAD) || defined(HAS_LONG_DOUBLE)
case 'L': /* Ld */
/* FALL THROUGH */
-#endif
#ifdef HAS_QUAD
case 'q': /* qd */
+#endif
intsize = 'q';
q++;
break;
#endif
case 'l':
-#if defined(HAS_QUAD) || (defined(HAS_LONG_DOUBLE) && defined(USE_LONG_DOUBLE))
+#if defined(HAS_QUAD) || defined(HAS_LONG_DOUBLE)
if (*(q + 1) == 'l') { /* lld, llf */
intsize = 'q';
q += 2;
goto string;
}
- if (!args)
+ if (vectorize)
+ argsv = vecsv;
+ else if (!args)
argsv = (efix ? efix <= svmax : svix < svmax) ?
svargs[efix ? efix-1 : svix++] : &PL_sv_undef;
/* STRINGS */
case 'c':
- uv = args ? va_arg(*args, int) : SvIVx(argsv);
+ uv = (args && !vectorize) ? va_arg(*args, int) : SvIVx(argsv);
if ((uv > 255 ||
(!UNI_IS_INVARIANT(uv) && SvUTF8(sv)))
&& !IN_BYTES) {
goto string;
case 's':
- if (args) {
+ if (args && !vectorize) {
eptr = va_arg(*args, char*);
if (eptr)
#ifdef MACOS_TRADITIONAL
* if ISO or ANSI decide to use '_' for something.
* So we keep it hidden from users' code.
*/
- if (!args)
+ if (!args || vectorize)
goto unknown;
argsv = va_arg(*args, SV*);
eptr = SvPVx(argsv, elen);
/* INTEGERS */
case 'p':
- if (alt)
+ if (alt || vectorize)
goto unknown;
uv = PTR2UV(args ? va_arg(*args, void*) : argsv);
base = 16;
/* This is evil, but floating point is even more evil */
- vectorize = FALSE;
- nv = args ? va_arg(*args, NV) : SvNVx(argsv);
+ /* for SV-style calling, we can only get NV
+ for C-style calling, we assume %f is double;
+ for simplicity we allow any of %Lf, %llf, %qf for long double
+ */
+ switch (intsize) {
+ case 'V':
+#if defined(USE_LONG_DOUBLE)
+ intsize = 'q';
+#endif
+ break;
+ default:
+#if defined(USE_LONG_DOUBLE)
+ intsize = args ? 0 : 'q';
+#endif
+ break;
+ case 'q':
+#if defined(HAS_LONG_DOUBLE)
+ break;
+#else
+ /* FALL THROUGH */
+#endif
+ case 'h':
+ /* FALL THROUGH */
+ case 'l':
+ goto unknown;
+ }
+
+ /* now we need (long double) if intsize == 'q', else (double) */
+ nv = (args && !vectorize) ?
+#if LONG_DOUBLESIZE > DOUBLESIZE
+ intsize == 'q' ?
+ va_arg(*args, long double) :
+ va_arg(*args, double)
+#else
+ va_arg(*args, double)
+#endif
+ : SvNVx(argsv);
need = 0;
+ vectorize = FALSE;
if (c != 'e' && c != 'E') {
i = PERL_INT_MIN;
+ /* FIXME: if HAS_LONG_DOUBLE but not USE_LONG_DOUBLE this
+ will cast our (long double) to (double) */
(void)Perl_frexp(nv, &i);
if (i == PERL_INT_MIN)
Perl_die(aTHX_ "panic: frexp");
eptr = ebuf + sizeof ebuf;
*--eptr = '\0';
*--eptr = c;
-#if defined(USE_LONG_DOUBLE) && defined(PERL_PRIfldbl)
- {
+ /* FIXME: what to do if HAS_LONG_DOUBLE but not PERL_PRIfldbl? */
+#if defined(HAS_LONG_DOUBLE) && defined(PERL_PRIfldbl)
+ if (intsize == 'q') {
/* Copy the one or more characters in a long double
* format before the 'base' ([efgEFG]) character to
* the format string. */
/* No taint. Otherwise we are in the strange situation
* where printf() taints but print($float) doesn't.
* --jhi */
+#if defined(HAS_LONG_DOUBLE)
+ if (intsize == 'q')
+ (void)sprintf(PL_efloatbuf, eptr, nv);
+ else
+ (void)sprintf(PL_efloatbuf, eptr, (double)nv);
+#else
(void)sprintf(PL_efloatbuf, eptr, nv);
-
+#endif
eptr = PL_efloatbuf;
elen = strlen(PL_efloatbuf);
break;
/* SPECIAL */
case 'n':
- vectorize = FALSE;
i = SvCUR(sv) - origlen;
- if (args) {
+ if (args && !vectorize) {
switch (intsize) {
case 'h': *(va_arg(*args, short*)) = i; break;
default: *(va_arg(*args, int*)) = i; break;
}
else
sv_setuv_mg(argsv, (UV)i);
+ vectorize = FALSE;
continue; /* not "break" */
/* UNKNOWN */
for (tblent = *otblent; tblent; i=0, tblent = tblent->next) {
if (tblent->oldval == oldv) {
tblent->newval = newv;
- tbl->tbl_items++;
return;
}
}
/* attempt to make everything in the typeglob readonly */
STATIC SV *
-S_gv_share(pTHX_ SV *sstr)
+S_gv_share(pTHX_ SV *sstr, CLONE_PARAMS *param)
{
GV *gv = (GV*)sstr;
- SV *sv = &PL_sv_no; /* just need SvREADONLY-ness */
+ SV *sv = ¶m->proto_perl->Isv_no; /* just need SvREADONLY-ness */
if (GvIO(gv) || GvFORM(gv)) {
GvUNIQUE_off(gv); /* GvIOs cannot be shared. nor can GvFORMs */
}
else {
/* CvPADLISTs cannot be shared */
- if (!CvXSUB(GvCV(gv))) {
+ if (!SvREADONLY(GvCV(gv)) && !CvXSUB(GvCV(gv))) {
GvUNIQUE_off(gv);
}
}
case SVt_PVGV:
if (GvUNIQUE((GV*)sstr)) {
SV *share;
- if ((share = gv_share(sstr))) {
+ if ((share = gv_share(sstr, param))) {
del_SV(dstr);
dstr = share;
+ ptr_table_store(PL_ptr_table, sstr, dstr);
#if 0
PerlIO_printf(Perl_debug_log, "sv_dup: sharing %s::%s\n",
HvNAME(GvSTASH(share)), GvNAME(share));
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, param);;
+ ncx->blk_eval.old_namesv = sv_dup_inc(cx->blk_eval.old_namesv, param);
ncx->blk_eval.old_eval_root = cx->blk_eval.old_eval_root;
ncx->blk_eval.cur_text = sv_dup(cx->blk_eval.cur_text, param);
break;
# endif /* DEBUGGING */
#endif /* PERL_IMPLICIT_SYS */
param->flags = flags;
+ param->proto_perl = proto_perl;
/* arena roots */
PL_xiv_arenaroot = NULL;
Copy(proto_perl->Inexttype, PL_nexttype, 5, I32);
PL_nexttoke = proto_perl->Inexttoke;
- PL_linestr = sv_dup_inc(proto_perl->Ilinestr, param);
- 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);
+ /* XXX This is probably masking the deeper issue of why
+ * SvANY(proto_perl->Ilinestr) can be NULL at this point. For test case:
+ * http://archive.develooper.com/perl5-porters%40perl.org/msg83298.html
+ * (A little debugging with a watchpoint on it may help.)
+ */
+ if (SvANY(proto_perl->Ilinestr)) {
+ PL_linestr = sv_dup_inc(proto_perl->Ilinestr, param);
+ 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);
+ i = proto_perl->Ilinestart - SvPVX(proto_perl->Ilinestr);
+ PL_linestart = SvPVX(PL_linestr) + (i < 0 ? 0 : i);
+ }
+ else {
+ PL_linestr = NEWSV(65,79);
+ sv_upgrade(PL_linestr,SVt_PVIV);
+ sv_setpvn(PL_linestr,"",0);
+ PL_bufptr = PL_oldbufptr = PL_oldoldbufptr = PL_linestart = SvPVX(PL_linestr);
+ }
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_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;
+ /* XXX See comment on SvANY(proto_perl->Ilinestr) above */
+ if (SvANY(proto_perl->Ilinestr)) {
+ 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;
+ }
+ else {
+ PL_last_uni = SvPVX(PL_linestr);
+ PL_last_lop = SvPVX(PL_linestr);
+ PL_last_lop_op = 0;
+ }
PL_in_my = proto_perl->Iin_my;
PL_in_my_stash = hv_dup(proto_perl->Iin_my_stash, param);
#ifdef FCRYPT
char *
Perl_sv_recode_to_utf8(pTHX_ SV *sv, SV *encoding)
{
- if (SvPOK(sv) && !DO_UTF8(sv) && SvROK(encoding)) {
+ if (SvPOK(sv) && !DO_UTF8(sv) && SvROK(encoding)) {
SV *uni;
STRLEN len;
char *s;
EXTEND(SP, 3);
XPUSHs(encoding);
XPUSHs(sv);
+/*
+ NI-S 2002/07/09
+ Passing sv_yes is wrong - it needs to be or'ed set of constants
+ for Encode::XS, while UTf-8 decode (currently) assumes a true value means
+ remove converted chars from source.
+
+ Both will default the value - let them.
+
XPUSHs(&PL_sv_yes);
+*/
PUTBACK;
call_method("decode", G_SCALAR);
SPAGAIN;
FREETMPS;
LEAVE;
SvUTF8_on(sv);
- }
- return SvPVX(sv);
+ }
+ return SvPVX(sv);
}
+