s = SvPV(sv, len);
if (chomping) {
- char *temp_buffer = NULL;
- SV *svrecode = NULL;
-
if (s && len) {
+ char *temp_buffer = NULL;
+ SV *svrecode = NULL;
s += --len;
if (RsPARA(PL_rs)) {
if (*s != '\n')
- goto nope;
+ goto nope_free_nothing;
++count;
while (len && s[-1] == '\n') {
--len;
temp_buffer = (char*)bytes_from_utf8((U8*)rsptr,
&rslen, &is_utf8);
if (is_utf8) {
- /* Cannot downgrade, therefore cannot possibly match
+ /* Cannot downgrade, therefore cannot possibly match.
+ At this point, temp_buffer is not alloced, and
+ is the buffer inside PL_rs, so dont free it.
*/
assert (temp_buffer == rsptr);
- temp_buffer = NULL;
- goto nope;
+ goto nope_free_sv;
}
rsptr = temp_buffer;
}
}
if (rslen == 1) {
if (*s != *rsptr)
- goto nope;
+ goto nope_free_all;
++count;
}
else {
if (len < rslen - 1)
- goto nope;
+ goto nope_free_all;
len -= rslen - 1;
s -= rslen - 1;
if (memNE(s, rsptr, rslen))
- goto nope;
+ goto nope_free_all;
count += rs_charlen;
}
}
*SvEND(sv) = '\0';
SvNIOK_off(sv);
SvSETMAGIC(sv);
- }
- nope:
-
- SvREFCNT_dec(svrecode);
- Safefree(temp_buffer);
+ nope_free_all:
+ Safefree(temp_buffer);
+ nope_free_sv:
+ SvREFCNT_dec(svrecode);
+ nope_free_nothing: ;
+ }
} else {
if (len && (!SvPOK(sv) || SvIsCOW(sv)))
s = SvPV_force_nomg(sv, len);
if (GIMME_V == G_ARRAY && PL_op->op_private & OPpREPEAT_DOLIST) {
dMARK;
- static const char* const oom_list_extend = "Out of memory during list extend";
- const I32 items = SP - MARK;
- const I32 max = items * count;
+ const Size_t items = SP - MARK;
const U8 mod = PL_op->op_flags & OPf_MOD;
- MEM_WRAP_CHECK_1(max, SV*, oom_list_extend);
- /* Did the max computation overflow? */
- if (items > 0 && max > 0 && (max < items || max < count))
- Perl_croak(aTHX_ "%s", oom_list_extend);
- MEXTEND(MARK, max);
if (count > 1) {
+ Size_t max;
+
+ if ( items > MEM_SIZE_MAX / (UV)count /* max would overflow */
+ || items > (U32)I32_MAX / sizeof(SV *) /* repeatcpy would overflow */
+ )
+ Perl_croak(aTHX_ "%s","Out of memory during list extend");
+ max = items * count;
+ MEXTEND(MARK, max);
+
while (SP > MARK) {
if (*SP) {
if (mod && SvPADTMP(*SP)) {
SV * const tmpstr = POPs;
STRLEN len;
bool isutf;
- static const char* const oom_string_extend =
- "Out of memory during string extend";
if (TARG != tmpstr)
sv_setsv_nomg(TARG, tmpstr);
if (count < 1)
SvCUR_set(TARG, 0);
else {
- const STRLEN max = (UV)count * len;
- if (len > MEM_SIZE_MAX / count)
- Perl_croak(aTHX_ "%s", oom_string_extend);
- MEM_WRAP_CHECK_1(max, char, oom_string_extend);
- SvGROW(TARG, max + 1);
+ STRLEN max;
+
+ if ( len > (MEM_SIZE_MAX-1) / (UV)count /* max would overflow */
+ || len > (U32)I32_MAX /* repeatcpy would overflow */
+ )
+ Perl_croak(aTHX_ "%s",
+ "Out of memory during string extend");
+ max = (UV)count * len + 1;
+ SvGROW(TARG, max);
+
repeatcpy(SvPVX(TARG) + len, SvPVX(TARG), len, count - 1);
SvCUR_set(TARG, SvCUR(TARG) * count);
}
}
}
+#define IV_BITS (IVSIZE * 8)
+
+static UV S_uv_shift(UV uv, int shift, bool left)
+{
+ if (shift < 0) {
+ shift = -shift;
+ left = !left;
+ }
+ if (shift >= IV_BITS) {
+ return 0;
+ }
+ return left ? uv << shift : uv >> shift;
+}
+
+static IV S_iv_shift(IV iv, int shift, bool left)
+{
+ if (shift < 0) {
+ shift = -shift;
+ left = !left;
+ }
+ if (shift >= IV_BITS) {
+ return iv < 0 && !left ? -1 : 0;
+ }
+ return left ? iv << shift : iv >> shift;
+}
+
+#define UV_LEFT_SHIFT(uv, shift) S_uv_shift(uv, shift, TRUE)
+#define UV_RIGHT_SHIFT(uv, shift) S_uv_shift(uv, shift, FALSE)
+#define IV_LEFT_SHIFT(iv, shift) S_iv_shift(iv, shift, TRUE)
+#define IV_RIGHT_SHIFT(iv, shift) S_iv_shift(iv, shift, FALSE)
+
PP(pp_left_shift)
{
dSP; dATARGET; SV *svl, *svr;
{
const IV shift = SvIV_nomg(svr);
if (PL_op->op_private & HINT_INTEGER) {
- const IV i = SvIV_nomg(svl);
- SETi(i << shift);
+ SETi(IV_LEFT_SHIFT(SvIV_nomg(svl), shift));
}
else {
- const UV u = SvUV_nomg(svl);
- SETu(u << shift);
+ SETu(UV_LEFT_SHIFT(SvUV_nomg(svl), shift));
}
RETURN;
}
{
const IV shift = SvIV_nomg(svr);
if (PL_op->op_private & HINT_INTEGER) {
- const IV i = SvIV_nomg(svl);
- SETi(i >> shift);
+ SETi(IV_RIGHT_SHIFT(SvIV_nomg(svl), shift));
}
else {
- const UV u = SvUV_nomg(svl);
- SETu(u >> shift);
+ SETu(UV_RIGHT_SHIFT(SvUV_nomg(svl), shift));
}
RETURN;
}
}
}
+PP(pp_nbit_and)
+{
+ dSP;
+ tryAMAGICbin_MG(band_amg, AMGf_assign|AMGf_numarg);
+ {
+ dATARGET; dPOPTOPssrl;
+ if (PL_op->op_private & HINT_INTEGER) {
+ const IV i = SvIV_nomg(left) & SvIV_nomg(right);
+ SETi(i);
+ }
+ else {
+ const UV u = SvUV_nomg(left) & SvUV_nomg(right);
+ SETu(u);
+ }
+ }
+ RETURN;
+}
+
+PP(pp_sbit_and)
+{
+ dSP;
+ tryAMAGICbin_MG(sband_amg, AMGf_assign);
+ {
+ dATARGET; dPOPTOPssrl;
+ do_vop(OP_BIT_AND, TARG, left, right);
+ RETSETTARG;
+ }
+}
/* also used for: pp_bit_xor() */
}
}
+/* also used for: pp_nbit_xor() */
+
+PP(pp_nbit_or)
+{
+ dSP;
+ const int op_type = PL_op->op_type;
+
+ tryAMAGICbin_MG((op_type == OP_NBIT_OR ? bor_amg : bxor_amg),
+ AMGf_assign|AMGf_numarg);
+ {
+ dATARGET; dPOPTOPssrl;
+ if (PL_op->op_private & HINT_INTEGER) {
+ const IV l = (USE_LEFT(left) ? SvIV_nomg(left) : 0);
+ const IV r = SvIV_nomg(right);
+ const IV result = op_type == OP_NBIT_OR ? (l | r) : (l ^ r);
+ SETi(result);
+ }
+ else {
+ const UV l = (USE_LEFT(left) ? SvUV_nomg(left) : 0);
+ const UV r = SvUV_nomg(right);
+ const UV result = op_type == OP_NBIT_OR ? (l | r) : (l ^ r);
+ SETu(result);
+ }
+ }
+ RETURN;
+}
+
+/* also used for: pp_sbit_xor() */
+
+PP(pp_sbit_or)
+{
+ dSP;
+ const int op_type = PL_op->op_type;
+
+ tryAMAGICbin_MG((op_type == OP_SBIT_OR ? sbor_amg : sbxor_amg),
+ AMGf_assign);
+ {
+ dATARGET; dPOPTOPssrl;
+ do_vop(op_type == OP_SBIT_OR ? OP_BIT_OR : OP_BIT_XOR, TARG, left,
+ right);
+ RETSETTARG;
+ }
+}
+
PERL_STATIC_INLINE bool
S_negate_string(pTHX)
{
return NORMAL;
}
-PP(pp_complement)
+static void
+S_scomplement(pTHX_ SV *targ, SV *sv)
{
- dSP; dTARGET;
- tryAMAGICun_MG(compl_amg, AMGf_numeric);
- {
- dTOPss;
- if (SvNIOKp(sv)) {
- if (PL_op->op_private & HINT_INTEGER) {
- const IV i = ~SvIV_nomg(sv);
- SETi(i);
- }
- else {
- const UV u = ~SvUV_nomg(sv);
- SETu(u);
- }
- }
- else {
U8 *tmps;
I32 anum;
STRLEN len;
while (tmps < send) {
const UV c = utf8n_to_uvchr(tmps, send-tmps, &l, utf8flags);
tmps += l;
- targlen += UNISKIP(~c);
+ targlen += UVCHR_SKIP(~c);
nchar++;
if (c > 0xff)
nwide++;
sv_usepvn_flags(TARG, (char*)result, nchar, SV_HAS_TRAILING_NUL);
SvUTF8_off(TARG);
}
- SETTARG;
- return NORMAL;
+ return;
}
#ifdef LIBERAL
{
#endif
for ( ; anum > 0; anum--, tmps++)
*tmps = ~*tmps;
+}
+
+PP(pp_complement)
+{
+ dSP; dTARGET;
+ tryAMAGICun_MG(compl_amg, AMGf_numeric);
+ {
+ dTOPss;
+ if (SvNIOKp(sv)) {
+ if (PL_op->op_private & HINT_INTEGER) {
+ const IV i = ~SvIV_nomg(sv);
+ SETi(i);
+ }
+ else {
+ const UV u = ~SvUV_nomg(sv);
+ SETu(u);
+ }
+ }
+ else {
+ S_scomplement(aTHX_ TARG, sv);
SETTARG;
}
return NORMAL;
}
}
+PP(pp_ncomplement)
+{
+ dSP;
+ tryAMAGICun_MG(compl_amg, AMGf_numeric|AMGf_numarg);
+ {
+ dTARGET; dTOPss;
+ if (PL_op->op_private & HINT_INTEGER) {
+ const IV i = ~SvIV_nomg(sv);
+ SETi(i);
+ }
+ else {
+ const UV u = ~SvUV_nomg(sv);
+ SETu(u);
+ }
+ }
+ return NORMAL;
+}
+
+PP(pp_scomplement)
+{
+ dSP;
+ tryAMAGICun_MG(scompl_amg, AMGf_numeric);
+ {
+ dTARGET; dTOPss;
+ S_scomplement(aTHX_ TARG, sv);
+ SETTARG;
+ return NORMAL;
+ }
+}
+
/* integer versions of some of the above */
PP(pp_i_multiply)
}
RETURN;
-bound_fail:
+ bound_fail:
if (repl)
Perl_croak(aTHX_ "substr outside of string");
Perl_ck_warner(aTHX_ packWARN(WARN_SUBSTR), "substr outside of string");
SvPV_const some lines above. We can't remove that, as we need to
call some SvPV to trigger overloading early and find out if the
string is UTF-8.
- This is all getting to messy. The API isn't quite clean enough,
+ This is all getting too messy. The API isn't quite clean enough,
because data access has side effects.
*/
little = newSVpvn_flags(little_p, llen,
&& ((SvIOKp(top) && !SvIsUV(top) && SvIV_nomg(top) < 0)
||
((SvNOKp(top) || (SvOK(top) && !SvIsUV(top)))
- && SvNV_nomg(top) < 0.0))) {
+ && SvNV_nomg(top) < 0.0)))
+ {
if (ckWARN(WARN_UTF8)) {
if (SvGMAGICAL(top)) {
SV *top2 = sv_newmortal();
SvUPGRADE(TARG,SVt_PV);
if (value > 255 && !IN_BYTES) {
- SvGROW(TARG, (STRLEN)UNISKIP(value)+1);
+ SvGROW(TARG, (STRLEN)UVCHR_SKIP(value)+1);
tmps = (char*)uvchr_to_utf8_flags((U8*)SvPVX(TARG), value, 0);
SvCUR_set(TARG, tmps - SvPVX_const(TARG));
*tmps = '\0';
* just above.
* Use the source to distinguish between the three cases */
+#if UNICODE_MAJOR_VERSION > 2 \
+ || (UNICODE_MAJOR_VERSION == 2 && UNICODE_DOT_VERSION >= 1 \
+ && UNICODE_DOT_DOT_VERSION >= 8)
if (*s == LATIN_SMALL_LETTER_SHARP_S) {
/* uc() of this requires 2 characters, but they are
*d++ = 'S'; *d = 'S'; /* upper case is 'SS' */
continue; /* Back to the tight loop; still in ASCII */
}
+#endif
/* The other two special handling characters have their
* upper cases outside the latin1 range, hence need to be
IN_LC_RUNTIME(LC_CTYPE)
||
#endif
- _isQUOTEMETA(TWO_BYTE_UTF8_TO_NATIVE(*s, *(s + 1))))
+ _isQUOTEMETA(EIGHT_BIT_UTF8_TO_NATIVE(*s, *(s + 1))))
{
to_quote = TRUE;
}
const U8 *send;
U8 *d;
U8 tmpbuf[UTF8_MAXBYTES_CASE + 1];
+#if UNICODE_MAJOR_VERSION > 3 /* no multifolds in early Unicode */ \
+ || (UNICODE_MAJOR_VERSION == 3 && ( UNICODE_DOT_VERSION > 0) \
+ || UNICODE_DOT_DOT_VERSION > 0)
const bool full_folding = TRUE; /* This variable is here so we can easily
move to more generality later */
+#else
+ const bool full_folding = FALSE;
+#endif
const U8 flags = ( full_folding ? FOLD_FLAGS_FULL : 0 )
#ifdef USE_LOCALE_CTYPE
| ( IN_LC_RUNTIME(LC_CTYPE) ? FOLD_FLAGS_LOCALE : 0 )
}
-/* Smart dereferencing for keys, values and each */
-
-/* also used for: pp_reach() pp_rvalues() */
-
-PP(pp_rkeys)
-{
- dSP;
- dPOPss;
-
- SvGETMAGIC(sv);
-
- if (
- !SvROK(sv)
- || (sv = SvRV(sv),
- (SvTYPE(sv) != SVt_PVHV && SvTYPE(sv) != SVt_PVAV)
- || SvOBJECT(sv)
- )
- ) {
- DIE(aTHX_
- "Type of argument to %s must be unblessed hashref or arrayref",
- PL_op_desc[PL_op->op_type] );
- }
-
- if (PL_op->op_flags & OPf_SPECIAL && SvTYPE(sv) == SVt_PVAV)
- DIE(aTHX_
- "Can't modify %s in %s",
- PL_op_desc[PL_op->op_type], PL_op_desc[PL_op->op_next->op_type]
- );
-
- /* Delegate to correct function for op type */
- PUSHs(sv);
- if (PL_op->op_type == OP_RKEYS || PL_op->op_type == OP_RVALUES) {
- return (SvTYPE(sv) == SVt_PVHV) ? Perl_do_kv(aTHX) : Perl_pp_akeys(aTHX);
- }
- else {
- return (SvTYPE(sv) == SVt_PVHV)
- ? Perl_pp_each(aTHX)
- : Perl_pp_aeach(aTHX);
- }
-}
-
PP(pp_aeach)
{
dSP;
EXTEND(SP, n + 1);
- if (PL_op->op_type == OP_AKEYS || PL_op->op_type == OP_RKEYS) {
+ if (PL_op->op_type == OP_AKEYS) {
for (i = 0; i <= n; i++) {
mPUSHi(i);
}
ENTER_with_name("call_PUSH");
call_sv(SV_CONST(PUSH),G_SCALAR|G_DISCARD|G_METHOD_NAMED);
LEAVE_with_name("call_PUSH");
- SPAGAIN;
+ /* SPAGAIN; not needed: SP is assigned to immediately below */
}
else {
if (SvREADONLY(ary) && MARK < SP) Perl_croak_no_modify();
ENTER_with_name("call_UNSHIFT");
call_sv(SV_CONST(UNSHIFT),G_SCALAR|G_DISCARD|G_METHOD_NAMED);
LEAVE_with_name("call_UNSHIFT");
- SPAGAIN;
+ /* SPAGAIN; not needed: SP is assigned to immediately below */
}
else {
SSize_t i = 0;
SvSETMAGIC(left);
break;
case SVt_PVAV:
+ assert(key);
if (UNLIKELY(PL_op->op_private & OPpLVAL_INTRO)) {
S_localise_aelem_lval(aTHX_ (AV *)left, key,
SvCANEXISTDELETE(left));
av_store((AV *)left, SvIV(key), SvREFCNT_inc_simple_NN(SvRV(sv)));
break;
case SVt_PVHV:
- if (UNLIKELY(PL_op->op_private & OPpLVAL_INTRO))
+ if (UNLIKELY(PL_op->op_private & OPpLVAL_INTRO)) {
+ assert(key);
S_localise_helem_lval(aTHX_ (HV *)left, key,
SvCANEXISTDELETE(left));
+ }
(void)hv_store_ent((HV *)left, key, SvREFCNT_inc_simple_NN(SvRV(sv)), 0);
}
if (PL_op->op_flags & OPf_MOD)
mg->mg_flags |= MGf_PERSIST;
if (UNLIKELY(PL_op->op_private & OPpLVAL_INTRO)) {
if (elem) {
- MAGIC *mg;
- HV *stash;
- const bool can_preserve = SvCANEXISTDELETE(arg);
- if (SvTYPE(arg) == SVt_PVAV)
- S_localise_aelem_lval(aTHX_ (AV *)arg, elem, can_preserve);
- else
- S_localise_helem_lval(aTHX_ (HV *)arg, elem, can_preserve);
+ MAGIC *mg;
+ HV *stash;
+ assert(arg);
+ {
+ const bool can_preserve = SvCANEXISTDELETE(arg);
+ if (SvTYPE(arg) == SVt_PVAV)
+ S_localise_aelem_lval(aTHX_ (AV *)arg, elem, can_preserve);
+ else
+ S_localise_helem_lval(aTHX_ (HV *)arg, elem, can_preserve);
+ }
}
else if (arg) {
S_localise_gv_slot(aTHX_ (GV *)arg,
}
/*
- * Local variables:
- * c-indentation-style: bsd
- * c-basic-offset: 4
- * indent-tabs-mode: nil
- * End:
- *
* ex: set ts=8 sts=4 sw=4 et:
*/