X-Git-Url: https://perl5.git.perl.org/perl5.git/blobdiff_plain/991e6d419e6cb68835dda77416b60c341a13a26e..fb622db0657a53699cb72fa7e5cdf67e58366454:/doop.c diff --git a/doop.c b/doop.c index 9f0fa64..b1de08d 100644 --- a/doop.c +++ b/doop.c @@ -1,6 +1,7 @@ /* doop.c * - * Copyright (c) 1991-2001, Larry Wall + * Copyright (C) 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, + * 2000, 2001, 2002, 2004, by Larry Wall and others * * You may distribute under the terms of either the GNU General Public * License or the Artistic License, as specified in the README file. @@ -11,15 +12,18 @@ * "'So that was the job I felt I had to do when I started,' thought Sam." */ +/* This file contains some common functions needed to carry out certain + * ops. For example both pp_schomp() and pp_chomp() - scalar and array + * chomp operations - call the function do_chomp() found in this file. + */ + #include "EXTERN.h" #define PERL_IN_DOOP_C #include "perl.h" #ifndef PERL_MICRO -#if !defined(NSIG) || defined(M_UNIX) || defined(M_XENIX) #include #endif -#endif STATIC I32 S_do_trans_simple(pTHX_ SV *sv) @@ -41,12 +45,12 @@ S_do_trans_simple(pTHX_ SV *sv) s = (U8*)SvPV(sv, len); send = s + len; - /* First, take care of non-UTF8 input strings, because they're easy */ + /* First, take care of non-UTF-8 input strings, because they're easy */ if (!SvUTF8(sv)) { while (s < send) { if ((ch = tbl[*s]) >= 0) { matches++; - *s++ = ch; + *s++ = (U8)ch; } else s++; @@ -73,7 +77,7 @@ S_do_trans_simple(pTHX_ SV *sv) s += ulen; } else { /* No match -> copy */ - Copy(s, d, ulen, U8); + Move(s, d, ulen, U8); d += ulen; s += ulen; } @@ -159,7 +163,7 @@ S_do_trans_complex(pTHX_ SV *sv) U8* p = send; while (s < send) { if ((ch = tbl[*s]) >= 0) { - *d = ch; + *d = (U8)ch; matches++; if (p != d - 1 || *p != *d) p = d++; @@ -175,7 +179,7 @@ S_do_trans_complex(pTHX_ SV *sv) while (s < send) { if ((ch = tbl[*s]) >= 0) { matches++; - *d++ = ch; + *d++ = (U8)ch; } else if (ch == -1) /* -1 is unmapped character */ *d++ = *s; @@ -217,9 +221,9 @@ S_do_trans_complex(pTHX_ SV *sv) ch = (rlen == 0) ? comp : (comp - 0x100 < rlen) ? tbl[comp+1] : tbl[0x100+rlen]; - if (ch != pch) { + if ((UV)ch != pch) { d = uvchr_to_utf8(d, ch); - pch = ch; + pch = (UV)ch; } s += len; continue; @@ -228,9 +232,9 @@ S_do_trans_complex(pTHX_ SV *sv) } else if ((ch = tbl[comp]) >= 0) { matches++; - if (ch != pch) { + if ((UV)ch != pch) { d = uvchr_to_utf8(d, ch); - pch = ch; + pch = (UV)ch; } s += len; continue; @@ -251,7 +255,7 @@ S_do_trans_complex(pTHX_ SV *sv) UV comp = utf8_to_uvchr(s, &len); if (comp > 0xff) { if (!complement) { - Copy(s, d, len, U8); + Move(s, d, len, U8); d += len; } else { @@ -351,7 +355,7 @@ S_do_trans_simple_utf8(pTHX_ SV *sv) } else if (uv == none) { int i = UTF8SKIP(s); - Copy(s, d, i, U8); + Move(s, d, i, U8); d += i; s += i; } @@ -510,7 +514,7 @@ S_do_trans_complex_utf8(pTHX_ SV *sv) } else if (uv == none) { /* "none" is unmapped character */ int i = UTF8SKIP(s); - Copy(s, d, i, U8); + Move(s, d, i, U8); d += i; s += i; puv = 0xfeedface; @@ -529,7 +533,7 @@ S_do_trans_complex_utf8(pTHX_ SV *sv) STRLEN len; uv = utf8_to_uvuni(s, &len); if (uv != puv) { - Copy(s, d, len, U8); + Move(s, d, len, U8); d += len; puv = uv; } @@ -561,7 +565,7 @@ S_do_trans_complex_utf8(pTHX_ SV *sv) } else if (uv == none) { /* "none" is unmapped character */ int i = UTF8SKIP(s); - Copy(s, d, i, U8); + Move(s, d, i, U8); d += i; s += i; continue; @@ -600,22 +604,25 @@ Perl_do_trans(pTHX_ SV *sv) (OPpTRANS_FROM_UTF|OPpTRANS_TO_UTF)); if (SvREADONLY(sv)) { - if (SvFAKE(sv)) - sv_force_normal(sv); + if (SvIsCOW(sv)) + sv_force_normal_flags(sv, 0); if (SvREADONLY(sv) && !(PL_op->op_private & OPpTRANS_IDENTICAL)) Perl_croak(aTHX_ PL_no_modify); } (void)SvPV(sv, len); if (!len) return 0; - if (!SvPOKp(sv)) - (void)SvPV_force(sv, len); - if (!(PL_op->op_private & OPpTRANS_IDENTICAL)) + if (!(PL_op->op_private & OPpTRANS_IDENTICAL)) { + if (!SvPOKp(sv)) + (void)SvPV_force(sv, len); (void)SvPOK_only_UTF8(sv); + } DEBUG_t( Perl_deb(aTHX_ "2.TBL\n")); - switch (PL_op->op_private & ~hasutf & 63) { + switch (PL_op->op_private & ~hasutf & ( + OPpTRANS_FROM_UTF|OPpTRANS_TO_UTF|OPpTRANS_IDENTICAL| + OPpTRANS_SQUASH|OPpTRANS_DELETE|OPpTRANS_COMPLEMENT)) { case 0: if (hasutf) return do_trans_simple_utf8(sv); @@ -667,7 +674,10 @@ Perl_do_join(pTHX_ register SV *sv, SV *del, register SV **mark, register SV **s ++mark; } - sv_setpv(sv, ""); + sv_setpvn(sv, "", 0); + /* sv_setpv retains old UTF8ness [perl #24846] */ + SvUTF8_off(sv); + if (PL_tainting && SvMAGICAL(sv)) SvTAINTED_off(sv); @@ -697,6 +707,9 @@ Perl_do_sprintf(pTHX_ SV *sv, I32 len, SV **sarg) char *pat = SvPV(*sarg, patlen); bool do_taint = FALSE; + SvUTF8_off(sv); + if (DO_UTF8(*sarg)) + SvUTF8_on(sv); sv_vsetpvfn(sv, pat, patlen, Null(va_list*), sarg + 1, len - 1, &do_taint); SvSETMAGIC(sv); if (do_taint) @@ -727,18 +740,18 @@ Perl_do_vecget(pTHX_ SV *sv, I32 offset, I32 size) else { offset >>= 3; /* turn into byte offset */ if (size == 16) { - if (offset >= srclen) + if ((STRLEN)offset >= srclen) retnum = 0; else retnum = (UV) s[offset] << 8; } else if (size == 32) { - if (offset >= srclen) + if ((STRLEN)offset >= srclen) retnum = 0; - else if (offset + 1 >= srclen) + else if ((STRLEN)(offset + 1) >= srclen) retnum = ((UV) s[offset ] << 24); - else if (offset + 2 >= srclen) + else if ((STRLEN)(offset + 2) >= srclen) retnum = ((UV) s[offset ] << 24) + ((UV) s[offset + 1] << 16); @@ -751,7 +764,7 @@ Perl_do_vecget(pTHX_ SV *sv, I32 offset, I32 size) #ifdef UV_IS_QUAD else if (size == 64) { if (ckWARN(WARN_PORTABLE)) - Perl_warner(aTHX_ WARN_PORTABLE, + Perl_warner(aTHX_ packWARN(WARN_PORTABLE), "Bit vector size > 32 non-portable"); if (offset >= srclen) retnum = 0; @@ -820,7 +833,7 @@ Perl_do_vecget(pTHX_ SV *sv, I32 offset, I32 size) #ifdef UV_IS_QUAD else if (size == 64) { if (ckWARN(WARN_PORTABLE)) - Perl_warner(aTHX_ WARN_PORTABLE, + Perl_warner(aTHX_ packWARN(WARN_PORTABLE), "Bit vector size > 32 non-portable"); retnum = ((UV) s[offset ] << 56) + @@ -869,7 +882,7 @@ Perl_do_vecset(pTHX_ SV *sv) lval = SvUV(sv); offset = LvTARGOFF(sv); if (offset < 0) - Perl_croak(aTHX_ "Assigning to negative offset in vec"); + Perl_croak(aTHX_ "Negative offset to vec in lvalue context"); size = LvTARGLEN(sv); if (size < 1 || (size & (size-1))) /* size < 1 or not a power of two */ Perl_croak(aTHX_ "Illegal number of bits in vec"); @@ -893,30 +906,30 @@ Perl_do_vecset(pTHX_ SV *sv) else { offset >>= 3; /* turn into byte offset */ if (size == 8) - s[offset ] = lval & 0xff; + s[offset ] = (U8)( lval & 0xff); else if (size == 16) { - s[offset ] = (lval >> 8) & 0xff; - s[offset+1] = lval & 0xff; + s[offset ] = (U8)((lval >> 8) & 0xff); + s[offset+1] = (U8)( lval & 0xff); } else if (size == 32) { - s[offset ] = (lval >> 24) & 0xff; - s[offset+1] = (lval >> 16) & 0xff; - s[offset+2] = (lval >> 8) & 0xff; - s[offset+3] = lval & 0xff; + s[offset ] = (U8)((lval >> 24) & 0xff); + s[offset+1] = (U8)((lval >> 16) & 0xff); + s[offset+2] = (U8)((lval >> 8) & 0xff); + s[offset+3] = (U8)( lval & 0xff); } #ifdef UV_IS_QUAD else if (size == 64) { if (ckWARN(WARN_PORTABLE)) - Perl_warner(aTHX_ WARN_PORTABLE, + Perl_warner(aTHX_ packWARN(WARN_PORTABLE), "Bit vector size > 32 non-portable"); - s[offset ] = (lval >> 56) & 0xff; - s[offset+1] = (lval >> 48) & 0xff; - s[offset+2] = (lval >> 40) & 0xff; - s[offset+3] = (lval >> 32) & 0xff; - s[offset+4] = (lval >> 24) & 0xff; - s[offset+5] = (lval >> 16) & 0xff; - s[offset+6] = (lval >> 8) & 0xff; - s[offset+7] = lval & 0xff; + s[offset ] = (U8)((lval >> 56) & 0xff); + s[offset+1] = (U8)((lval >> 48) & 0xff); + s[offset+2] = (U8)((lval >> 40) & 0xff); + s[offset+3] = (U8)((lval >> 32) & 0xff); + s[offset+4] = (U8)((lval >> 24) & 0xff); + s[offset+5] = (U8)((lval >> 16) & 0xff); + s[offset+6] = (U8)((lval >> 8) & 0xff); + s[offset+7] = (U8)( lval & 0xff); } #endif } @@ -999,6 +1012,8 @@ Perl_do_chomp(pTHX_ register SV *sv) STRLEN len; STRLEN n_a; char *s; + char *temp_buffer = NULL; + SV* svrecode = Nullsv; if (RsSNARF(PL_rs)) return 0; @@ -1034,6 +1049,18 @@ Perl_do_chomp(pTHX_ register SV *sv) if (SvREADONLY(sv)) Perl_croak(aTHX_ PL_no_modify); } + + if (PL_encoding) { + if (!SvUTF8(sv)) { + /* XXX, here sv is utf8-ized as a side-effect! + If encoding.pm is used properly, almost string-generating + operations, including literal strings, chr(), input data, etc. + should have been utf8-ized already, right? + */ + sv_recode_to_utf8(sv, PL_encoding); + } + } + s = SvPV(sv, len); if (s && len) { s += --len; @@ -1048,8 +1075,43 @@ Perl_do_chomp(pTHX_ register SV *sv) } } else { - STRLEN rslen; + STRLEN rslen, rs_charlen; char *rsptr = SvPV(PL_rs, rslen); + + rs_charlen = SvUTF8(PL_rs) + ? sv_len_utf8(PL_rs) + : rslen; + + if (SvUTF8(PL_rs) != SvUTF8(sv)) { + /* Assumption is that rs is shorter than the scalar. */ + if (SvUTF8(PL_rs)) { + /* RS is utf8, scalar is 8 bit. */ + bool is_utf8 = TRUE; + temp_buffer = (char*)bytes_from_utf8((U8*)rsptr, + &rslen, &is_utf8); + if (is_utf8) { + /* Cannot downgrade, therefore cannot possibly match + */ + assert (temp_buffer == rsptr); + temp_buffer = NULL; + goto nope; + } + rsptr = temp_buffer; + } + else if (PL_encoding) { + /* RS is 8 bit, encoding.pm is used. + * Do not recode PL_rs as a side-effect. */ + svrecode = newSVpvn(rsptr, rslen); + sv_recode_to_utf8(svrecode, PL_encoding); + rsptr = SvPV(svrecode, rslen); + rs_charlen = sv_len_utf8(svrecode); + } + else { + /* RS is 8 bit, scalar is utf8. */ + temp_buffer = (char*)bytes_to_utf8((U8*)rsptr, &rslen); + rsptr = temp_buffer; + } + } if (rslen == 1) { if (*s != *rsptr) goto nope; @@ -1062,7 +1124,7 @@ Perl_do_chomp(pTHX_ register SV *sv) s -= rslen - 1; if (memNE(s, rsptr, rslen)) goto nope; - count += rslen; + count += rs_charlen; } } s = SvPV_force(sv, n_a); @@ -1072,6 +1134,11 @@ Perl_do_chomp(pTHX_ register SV *sv) SvSETMAGIC(sv); } nope: + + if (svrecode) + SvREFCNT_dec(svrecode); + + Safefree(temp_buffer); return count; } @@ -1103,8 +1170,8 @@ Perl_do_vop(pTHX_ I32 optype, SV *sv, SV *left, SV *right) if (sv != left || (optype != OP_BIT_AND && !SvOK(sv) && !SvGMAGICAL(sv))) sv_setpvn(sv, "", 0); /* avoid undef warning on |= and ^= */ - lsave = lc = SvPV(left, leftlen); - rsave = rc = SvPV(right, rightlen); + lsave = lc = SvPV_nomg(left, leftlen); + rsave = rc = SvPV_nomg(right, rightlen); len = leftlen < rightlen ? leftlen : rightlen; lensave = len; if ((left_utf || right_utf) && (sv == left || sv == right)) { @@ -1113,9 +1180,9 @@ Perl_do_vop(pTHX_ I32 optype, SV *sv, SV *left, SV *right) } else if (SvOK(sv) || SvTYPE(sv) > SVt_PVMG) { STRLEN n_a; - dc = SvPV_force(sv, n_a); - if (SvCUR(sv) < len) { - dc = SvGROW(sv, len + 1); + dc = SvPV_force_nomg(sv, n_a); + if (SvCUR(sv) < (STRLEN)len) { + dc = SvGROW(sv, (STRLEN)(len + 1)); (void)memzero(dc + SvCUR(sv), len - SvCUR(sv) + 1); } if (optype != OP_BIT_AND && (left_utf || right_utf)) @@ -1253,9 +1320,9 @@ Perl_do_vop(pTHX_ I32 optype, SV *sv, SV *left, SV *right) *dc++ = *lc++ | *rc++; mop_up: len = lensave; - if (rightlen > len) + if (rightlen > (STRLEN)len) sv_catpvn(sv, rsave + len, rightlen - len); - else if (leftlen > len) + else if (leftlen > (STRLEN)len) sv_catpvn(sv, lsave + len, leftlen - len); else *SvEND(sv) = '\0'; @@ -1277,7 +1344,6 @@ Perl_do_kv(pTHX) I32 gimme = GIMME_V; I32 dokeys = (PL_op->op_type == OP_KEYS); I32 dovalues = (PL_op->op_type == OP_VALUES); - I32 realhv = (SvTYPE(hv) == SVt_PVHV); if (PL_op->op_type == OP_RV2HV || PL_op->op_type == OP_PADHV) dokeys = dovalues = TRUE; @@ -1292,7 +1358,7 @@ Perl_do_kv(pTHX) RETURN; } - keys = realhv ? hv : avhv_keys((AV*)hv); + keys = hv; (void)hv_iterinit(keys); /* always reset iterator regardless */ if (gimme == G_VOID) @@ -1333,12 +1399,13 @@ Perl_do_kv(pTHX) PUTBACK; /* hv_iternext and hv_iterval might clobber stack_sp */ while ((entry = hv_iternext(keys))) { SPAGAIN; - if (dokeys) - XPUSHs(hv_iterkeysv(entry)); /* won't clobber stack_sp */ + if (dokeys) { + SV* sv = hv_iterkeysv(entry); + XPUSHs(sv); /* won't clobber stack_sp */ + } if (dovalues) { PUTBACK; - tmpstr = realhv ? - hv_iterval(hv,entry) : avhv_iterval((AV*)hv,entry); + tmpstr = hv_iterval(hv,entry); DEBUG_H(Perl_sv_setpvf(aTHX_ tmpstr, "%lu%%%d=%lu", (unsigned long)HeHASH(entry), HvMAX(keys)+1,