X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=doop.c;h=22495e6fa0f28ccb89d0856db493592f1ad799ff;hb=469bf43793110471bf2ceb5e99f0e9cc630d60fe;hp=7209e1dc64e737dea380a77d2f29ee99a26d167e;hpb=4e35701fd273ba8d0093a29660dee38a92408e9b;p=p5sagit%2Fp5-mst-13.2.git diff --git a/doop.c b/doop.c index 7209e1d..22495e6 100644 --- a/doop.c +++ b/doop.c @@ -18,67 +18,629 @@ #include #endif -I32 -do_trans(SV *sv, OP *arg) +#ifndef PERL_OBJECT +static I32 do_trans_CC_simple _((SV *sv)); +static I32 do_trans_CC_count _((SV *sv)); +static I32 do_trans_CC_complex _((SV *sv)); +static I32 do_trans_UU_simple _((SV *sv)); +static I32 do_trans_UU_count _((SV *sv)); +static I32 do_trans_UU_complex _((SV *sv)); +static I32 do_trans_UC_simple _((SV *sv)); +static I32 do_trans_CU_simple _((SV *sv)); +static I32 do_trans_UC_trivial _((SV *sv)); +static I32 do_trans_CU_trivial _((SV *sv)); +#endif + +STATIC I32 +do_trans_CC_simple(SV *sv) { dTHR; - register short *tbl; - register U8 *s; - register U8 *send; - register U8 *d; - register I32 ch; - register I32 matches = 0; - register I32 squash = op->op_private & OPpTRANS_SQUASH; + U8 *s; + U8 *send; + I32 matches = 0; STRLEN len; + short *tbl; + I32 ch; - if (SvREADONLY(sv)) - croak(no_modify); tbl = (short*)cPVOP->op_pv; + if (!tbl) + croak("panic: do_trans"); + s = (U8*)SvPV(sv, len); - if (!len) - return 0; - if (!SvPOKp(sv)) - s = (U8*)SvPV_force(sv, len); - (void)SvPOK_only(sv); send = s + len; - if (!tbl || !s) + + while (s < send) { + if ((ch = tbl[*s]) >= 0) { + matches++; + *s = ch; + } + s++; + } + SvSETMAGIC(sv); + + return matches; +} + +STATIC I32 +do_trans_CC_count(SV *sv) +{ + dTHR; + U8 *s; + U8 *send; + I32 matches = 0; + STRLEN len; + short *tbl; + + tbl = (short*)cPVOP->op_pv; + if (!tbl) croak("panic: do_trans"); - DEBUG_t( deb("2.TBL\n")); - if (!op->op_private) { + + s = (U8*)SvPV(sv, len); + send = s + len; + + while (s < send) { + if (tbl[*s] >= 0) + matches++; + s++; + } + + return matches; +} + +STATIC I32 +do_trans_CC_complex(SV *sv) +{ + dTHR; + U8 *s; + U8 *send; + U8 *d; + I32 matches = 0; + STRLEN len; + short *tbl; + I32 ch; + + tbl = (short*)cPVOP->op_pv; + if (!tbl) + croak("panic: do_trans"); + + s = (U8*)SvPV(sv, len); + send = s + len; + + d = s; + if (PL_op->op_private & OPpTRANS_SQUASH) { + U8* p = send; + while (s < send) { if ((ch = tbl[*s]) >= 0) { + *d = ch; matches++; - *s = ch; + if (p == d - 1 && *p == *d) + matches--; + else + p = d++; } + else if (ch == -1) /* -1 is unmapped character */ + *d++ = *s; /* -2 is delete character */ s++; } } else { - d = s; while (s < send) { if ((ch = tbl[*s]) >= 0) { *d = ch; - if (matches++ && squash) { - if (d[-1] == *d) - matches--; - else - d++; - } - else - d++; + matches++; + d++; } else if (ch == -1) /* -1 is unmapped character */ *d++ = *s; /* -2 is delete character */ s++; } - matches += send - d; /* account for disappeared chars */ + } + matches += send - d; /* account for disappeared chars */ + *d = '\0'; + SvCUR_set(sv, d - (U8*)SvPVX(sv)); + SvSETMAGIC(sv); + + return matches; +} + +STATIC I32 +do_trans_UU_simple(SV *sv) +{ + dTHR; + U8 *s; + U8 *send; + U8 *d; + I32 matches = 0; + STRLEN len; + + SV* rv = (SV*)cSVOP->op_sv; + HV* hv = (HV*)SvRV(rv); + SV** svp = hv_fetch(hv, "NONE", 4, FALSE); + UV none = svp ? SvUV(*svp) : 0x7fffffff; + UV extra = none + 1; + UV final; + UV uv; + + s = (U8*)SvPV(sv, len); + send = s + len; + + svp = hv_fetch(hv, "FINAL", 5, FALSE); + if (svp) + final = SvUV(*svp); + + d = s; + while (s < send) { + if ((uv = swash_fetch(rv, s)) < none) { + s += UTF8SKIP(s); + matches++; + d = uv_to_utf8(d, uv); + } + else if (uv == none) { + int i; + for (i = UTF8SKIP(s); i; i--) + *d++ = *s++; + } + else if (uv == extra) { + s += UTF8SKIP(s); + matches++; + d = uv_to_utf8(d, final); + } + else + s += UTF8SKIP(s); + } + *d = '\0'; + SvCUR_set(sv, d - (U8*)SvPVX(sv)); + SvSETMAGIC(sv); + + return matches; +} + +STATIC I32 +do_trans_UU_count(SV *sv) +{ + dTHR; + U8 *s; + U8 *send; + I32 matches = 0; + STRLEN len; + + SV* rv = (SV*)cSVOP->op_sv; + HV* hv = (HV*)SvRV(rv); + SV** svp = hv_fetch(hv, "NONE", 4, FALSE); + UV none = svp ? SvUV(*svp) : 0x7fffffff; + UV uv; + + s = (U8*)SvPV(sv, len); + send = s + len; + + while (s < send) { + if ((uv = swash_fetch(rv, s)) < none) + matches++; + s += UTF8SKIP(s); + } + + return matches; +} + +STATIC I32 +do_trans_UC_simple(SV *sv) +{ + dTHR; + U8 *s; + U8 *send; + U8 *d; + I32 matches = 0; + STRLEN len; + + SV* rv = (SV*)cSVOP->op_sv; + HV* hv = (HV*)SvRV(rv); + SV** svp = hv_fetch(hv, "NONE", 4, FALSE); + UV none = svp ? SvUV(*svp) : 0x7fffffff; + UV extra = none + 1; + UV final; + UV uv; + + s = (U8*)SvPV(sv, len); + send = s + len; + + svp = hv_fetch(hv, "FINAL", 5, FALSE); + if (svp) + final = SvUV(*svp); + + d = s; + while (s < send) { + if ((uv = swash_fetch(rv, s)) < none) { + s += UTF8SKIP(s); + matches++; + *d++ = (U8)uv; + } + else if (uv == none) { + I32 ulen; + uv = utf8_to_uv(s, &ulen); + s += ulen; + *d++ = (U8)uv; + } + else if (uv == extra) { + s += UTF8SKIP(s); + matches++; + *d++ = (U8)final; + } + else + s += UTF8SKIP(s); + } + *d = '\0'; + SvCUR_set(sv, d - (U8*)SvPVX(sv)); + SvSETMAGIC(sv); + + return matches; +} + +STATIC I32 +do_trans_CU_simple(SV *sv) +{ + dTHR; + U8 *s; + U8 *send; + U8 *d; + U8 *dst; + I32 matches = 0; + STRLEN len; + + SV* rv = (SV*)cSVOP->op_sv; + HV* hv = (HV*)SvRV(rv); + SV** svp = hv_fetch(hv, "NONE", 4, FALSE); + UV none = svp ? SvUV(*svp) : 0x7fffffff; + UV extra = none + 1; + UV final; + UV uv; + U8 tmpbuf[10]; + I32 bits = 16; + + s = (U8*)SvPV(sv, len); + send = s + len; + + svp = hv_fetch(hv, "BITS", 4, FALSE); + if (svp) + bits = (I32)SvIV(*svp); + + svp = hv_fetch(hv, "FINAL", 5, FALSE); + if (svp) + final = SvUV(*svp); + + Newz(801, d, len * (bits >> 3) + 1, U8); + dst = d; + + while (s < send) { + uv = *s++; + if (uv < 0x80) + tmpbuf[0] = uv; + else { + tmpbuf[0] = (( uv >> 6) | 0xc0); + tmpbuf[1] = (( uv & 0x3f) | 0x80); + } + + if ((uv = swash_fetch(rv, tmpbuf)) < none) { + matches++; + d = uv_to_utf8(d, uv); + } + else if (uv == none) + d = uv_to_utf8(d, s[-1]); + else if (uv == extra) { + matches++; + d = uv_to_utf8(d, final); + } + } + *d = '\0'; + sv_usepvn_mg(sv, (char*)dst, d - dst); + + return matches; +} + +/* utf-8 to latin-1 */ + +STATIC I32 +do_trans_UC_trivial(SV *sv) +{ + dTHR; + U8 *s; + U8 *send; + U8 *d; + STRLEN len; + + s = (U8*)SvPV(sv, len); + send = s + len; + + d = s; + while (s < send) { + if (*s < 0x80) + *d++ = *s++; + else { + I32 ulen; + UV uv = utf8_to_uv(s, &ulen); + s += ulen; + *d++ = (U8)uv; + } + } + *d = '\0'; + SvCUR_set(sv, d - (U8*)SvPVX(sv)); + SvSETMAGIC(sv); + + return SvCUR(sv); +} + +/* latin-1 to utf-8 */ + +STATIC I32 +do_trans_CU_trivial(SV *sv) +{ + dTHR; + U8 *s; + U8 *send; + U8 *d; + U8 *dst; + I32 matches; + STRLEN len; + + s = (U8*)SvPV(sv, len); + send = s + len; + + Newz(801, d, len * 2 + 1, U8); + dst = d; + + matches = send - s; + + while (s < send) { + if (*s < 0x80) + *d++ = *s++; + else { + UV uv = *s++; + *d++ = (( uv >> 6) | 0xc0); + *d++ = (( uv & 0x3f) | 0x80); + } + } + *d = '\0'; + sv_usepvn_mg(sv, (char*)dst, d - dst); + + return matches; +} + +STATIC I32 +do_trans_UU_complex(SV *sv) +{ + dTHR; + U8 *s; + U8 *send; + U8 *d; + I32 matches = 0; + I32 squash = PL_op->op_private & OPpTRANS_SQUASH; + I32 from_utf = PL_op->op_private & OPpTRANS_FROM_UTF; + I32 to_utf = PL_op->op_private & OPpTRANS_TO_UTF; + I32 del = PL_op->op_private & OPpTRANS_DELETE; + SV* rv = (SV*)cSVOP->op_sv; + HV* hv = (HV*)SvRV(rv); + SV** svp = hv_fetch(hv, "NONE", 4, FALSE); + UV none = svp ? SvUV(*svp) : 0x7fffffff; + UV extra = none + 1; + UV final; + UV uv; + STRLEN len; + U8 *dst; + + s = (U8*)SvPV(sv, len); + send = s + len; + + svp = hv_fetch(hv, "FINAL", 5, FALSE); + if (svp) + final = SvUV(*svp); + + if (PL_op->op_private & OPpTRANS_GROWS) { + I32 bits = 16; + + svp = hv_fetch(hv, "BITS", 4, FALSE); + if (svp) + bits = (I32)SvIV(*svp); + + Newz(801, d, len * (bits >> 3) + 1, U8); + dst = d; + } + else { + d = s; + dst = 0; + } + + if (squash) { + UV puv = 0xfeedface; + while (s < send) { + if (from_utf) { + uv = swash_fetch(rv, s); + } + else { + U8 tmpbuf[2]; + uv = *s++; + if (uv < 0x80) + tmpbuf[0] = uv; + else { + tmpbuf[0] = (( uv >> 6) | 0xc0); + tmpbuf[1] = (( uv & 0x3f) | 0x80); + } + uv = swash_fetch(rv, tmpbuf); + } + if (uv < none) { + matches++; + if (uv != puv) { + if (uv >= 0x80 && to_utf) + d = uv_to_utf8(d, uv); + else + *d++ = (U8)uv; + puv = uv; + } + if (from_utf) + s += UTF8SKIP(s); + continue; + } + else if (uv == none) { /* "none" is unmapped character */ + if (from_utf) { + if (*s < 0x80) + *d++ = *s++; + else if (to_utf) { + int i; + for (i = UTF8SKIP(s); i; --i) + *d++ = *s++; + } + else { + I32 ulen; + *d++ = (U8)utf8_to_uv(s, &ulen); + s += ulen; + } + } + else { /* must be to_utf only */ + d = uv_to_utf8(d, s[-1]); + } + puv = 0xfeedface; + continue; + } + else if (uv == extra && !del) { + matches++; + if (uv != puv) { + if (final >= 0x80 && to_utf) + d = uv_to_utf8(d, final); + else + *d++ = (U8)final; + puv = final; + } + if (from_utf) + s += UTF8SKIP(s); + continue; + } + matches++; /* "none+1" is delete character */ + if (from_utf) + s += UTF8SKIP(s); + } + } + else { + while (s < send) { + if (from_utf) { + uv = swash_fetch(rv, s); + } + else { + U8 tmpbuf[2]; + uv = *s++; + if (uv < 0x80) + tmpbuf[0] = uv; + else { + tmpbuf[0] = (( uv >> 6) | 0xc0); + tmpbuf[1] = (( uv & 0x3f) | 0x80); + } + uv = swash_fetch(rv, tmpbuf); + } + if (uv < none) { + matches++; + if (uv >= 0x80 && to_utf) + d = uv_to_utf8(d, uv); + else + *d++ = (U8)uv; + if (from_utf) + s += UTF8SKIP(s); + continue; + } + else if (uv == none) { /* "none" is unmapped character */ + if (from_utf) { + if (*s < 0x80) + *d++ = *s++; + else if (to_utf) { + int i; + for (i = UTF8SKIP(s); i; --i) + *d++ = *s++; + } + else { + I32 ulen; + *d++ = (U8)utf8_to_uv(s, &ulen); + s += ulen; + } + } + else { /* must be to_utf only */ + d = uv_to_utf8(d, s[-1]); + } + continue; + } + else if (uv == extra && !del) { + matches++; + if (final >= 0x80 && to_utf) + d = uv_to_utf8(d, final); + else + *d++ = (U8)final; + if (from_utf) + s += UTF8SKIP(s); + continue; + } + matches++; /* "none+1" is delete character */ + if (from_utf) + s += UTF8SKIP(s); + } + } + if (dst) + sv_usepvn(sv, (char*)dst, d - dst); + else { *d = '\0'; SvCUR_set(sv, d - (U8*)SvPVX(sv)); } SvSETMAGIC(sv); + return matches; } +I32 +do_trans(SV *sv) +{ + dTHR; + STRLEN len; + + if (SvREADONLY(sv) && !(PL_op->op_private & OPpTRANS_IDENTICAL)) + croak(PL_no_modify); + + (void)SvPV(sv, len); + if (!len) + return 0; + if (!SvPOKp(sv)) + (void)SvPV_force(sv, len); + (void)SvPOK_only(sv); + + DEBUG_t( deb("2.TBL\n")); + + switch (PL_op->op_private & 63) { + case 0: + return do_trans_CC_simple(sv); + + case OPpTRANS_FROM_UTF: + return do_trans_UC_simple(sv); + + case OPpTRANS_TO_UTF: + return do_trans_CU_simple(sv); + + case OPpTRANS_FROM_UTF|OPpTRANS_TO_UTF: + return do_trans_UU_simple(sv); + + case OPpTRANS_IDENTICAL: + return do_trans_CC_count(sv); + + case OPpTRANS_FROM_UTF|OPpTRANS_IDENTICAL: + return do_trans_UC_trivial(sv); + + case OPpTRANS_TO_UTF|OPpTRANS_IDENTICAL: + return do_trans_CU_trivial(sv); + + case OPpTRANS_FROM_UTF|OPpTRANS_TO_UTF|OPpTRANS_IDENTICAL: + return do_trans_UU_count(sv); + + default: + if (PL_op->op_private & (OPpTRANS_FROM_UTF|OPpTRANS_TO_UTF)) + return do_trans_UU_complex(sv); /* could be UC or CU too */ + else + return do_trans_CC_complex(sv); + } +} + void do_join(register SV *sv, SV *del, register SV **mark, register SV **sp) { @@ -91,11 +653,10 @@ do_join(register SV *sv, SV *del, register SV **mark, register SV **sp) mark++; len = (items > 0 ? (delimlen * (items - 1) ) : 0); - if (SvTYPE(sv) < SVt_PV) - sv_upgrade(sv, SVt_PV); + (void)SvUPGRADE(sv, SVt_PV); if (SvLEN(sv) < len + items) { /* current length is way too short */ while (items-- > 0) { - if (*mark) { + if (*mark && !SvGMAGICAL(*mark) && SvOK(*mark)) { SvPV(*mark, tmplen); len += tmplen; } @@ -204,6 +765,7 @@ do_chop(register SV *astr, register SV *sv) { STRLEN len; char *s; + dTHR; if (SvTYPE(sv) == SVt_PVAV) { register I32 i; @@ -212,7 +774,7 @@ do_chop(register SV *astr, register SV *sv) max = AvFILL(av); for (i = 0; i <= max; i++) { sv = (SV*)av_fetch(av, i, FALSE); - if (sv && ((sv = *(SV**)sv), sv != &sv_undef)) + if (sv && ((sv = *(SV**)sv), sv != &PL_sv_undef)) do_chop(astr, sv); } return; @@ -229,6 +791,24 @@ do_chop(register SV *astr, register SV *sv) s = SvPV(sv, len); if (len && !SvPOK(sv)) s = SvPV_force(sv, len); + if (IN_UTF8) { + if (s && len) { + char *send = s + len; + char *start = s; + s = send - 1; + while ((*s & 0xc0) == 0x80) + --s; + if (UTF8SKIP(s) != send - s) + warn("Malformed UTF-8 character"); + sv_setpvn(astr, s, send - s); + *s = '\0'; + SvCUR_set(sv, s - start); + SvNIOK_off(sv); + } + else + sv_setpvn(astr, "", 0); + } + else if (s && len) { s += --len; sv_setpvn(astr, s, 1); @@ -244,11 +824,12 @@ do_chop(register SV *astr, register SV *sv) I32 do_chomp(register SV *sv) { + dTHR; register I32 count; STRLEN len; char *s; - if (RsSNARF(rs)) + if (RsSNARF(PL_rs)) return 0; count = 0; if (SvTYPE(sv) == SVt_PVAV) { @@ -258,7 +839,7 @@ do_chomp(register SV *sv) max = AvFILL(av); for (i = 0; i <= max; i++) { sv = (SV*)av_fetch(av, i, FALSE); - if (sv && ((sv = *(SV**)sv), sv != &sv_undef)) + if (sv && ((sv = *(SV**)sv), sv != &PL_sv_undef)) count += do_chomp(sv); } return count; @@ -277,7 +858,7 @@ do_chomp(register SV *sv) s = SvPV_force(sv, len); if (s && len) { s += --len; - if (RsPARA(rs)) { + if (RsPARA(PL_rs)) { if (*s != '\n') goto nope; ++count; @@ -289,7 +870,7 @@ do_chomp(register SV *sv) } else { STRLEN rslen; - char *rsptr = SvPV(rs, rslen); + char *rsptr = SvPV(PL_rs, rslen); if (rslen == 1) { if (*s != *rsptr) goto nope; @@ -317,6 +898,7 @@ do_chomp(register SV *sv) void do_vop(I32 optype, SV *sv, SV *left, SV *right) { + dTHR; /* just for taint */ #ifdef LIBERAL register long *dl; register long *ll; @@ -339,7 +921,8 @@ do_vop(I32 optype, SV *sv, SV *left, SV *right) len = leftlen < rightlen ? leftlen : rightlen; lensave = len; if (SvOK(sv) || SvTYPE(sv) > SVt_PVMG) { - dc = SvPV_force(sv, na); + STRLEN n_a; + dc = SvPV_force(sv, n_a); if (SvCUR(sv) < len) { dc = SvGROW(sv, len + 1); (void)memzero(dc + SvCUR(sv), len - SvCUR(sv) + 1); @@ -432,18 +1015,19 @@ do_kv(ARGSproto) { djSP; HV *hv = (HV*)POPs; + HV *keys; register HE *entry; SV *tmpstr; I32 gimme = GIMME_V; - I32 dokeys = (op->op_type == OP_KEYS); - I32 dovalues = (op->op_type == OP_VALUES); + I32 dokeys = (PL_op->op_type == OP_KEYS); + I32 dovalues = (PL_op->op_type == OP_VALUES); I32 realhv = (SvTYPE(hv) == SVt_PVHV); - if (op->op_type == OP_RV2HV || op->op_type == OP_PADHV) + if (PL_op->op_type == OP_RV2HV || PL_op->op_type == OP_PADHV) dokeys = dovalues = TRUE; if (!hv) { - if (op->op_flags & OPf_MOD) { /* lvalue */ + if (PL_op->op_flags & OPf_MOD) { /* lvalue */ dTARGET; /* make sure to clear its target here */ if (SvTYPE(TARG) == SVt_PVLV) LvTARG(TARG) = Nullsv; @@ -452,59 +1036,57 @@ do_kv(ARGSproto) RETURN; } - if (realhv) - (void)hv_iterinit(hv); /* always reset iterator regardless */ - else - (void)avhv_iterinit((AV*)hv); + keys = realhv ? hv : avhv_keys((AV*)hv); + (void)hv_iterinit(keys); /* always reset iterator regardless */ if (gimme == G_VOID) RETURN; if (gimme == G_SCALAR) { - I32 i; + IV i; dTARGET; - if (op->op_flags & OPf_MOD) { /* lvalue */ + if (PL_op->op_flags & OPf_MOD) { /* lvalue */ if (SvTYPE(TARG) < SVt_PVLV) { sv_upgrade(TARG, SVt_PVLV); sv_magic(TARG, Nullsv, 'k', Nullch, 0); } LvTYPE(TARG) = 'k'; - LvTARG(TARG) = (SV*)hv; + if (LvTARG(TARG) != (SV*)keys) { + if (LvTARG(TARG)) + SvREFCNT_dec(LvTARG(TARG)); + LvTARG(TARG) = SvREFCNT_inc(keys); + } PUSHs(TARG); RETURN; } - if (!SvRMAGICAL(hv) || !mg_find((SV*)hv,'P')) - i = HvKEYS(hv); + if (! SvTIED_mg((SV*)keys, 'P')) + i = HvKEYS(keys); else { i = 0; /*SUPPRESS 560*/ - while (entry = realhv ? hv_iternext(hv) : avhv_iternext((AV*)hv)) { - i++; - } + while (hv_iternext(keys)) i++; } PUSHi( i ); RETURN; } - /* Guess how much room we need. hv_max may be a few too many. Oh well. */ - EXTEND(sp, HvMAX(hv) * (dokeys + dovalues)); + EXTEND(SP, HvKEYS(keys) * (dokeys + dovalues)); PUTBACK; /* hv_iternext and hv_iterval might clobber stack_sp */ - while (entry = realhv ? hv_iternext(hv) : avhv_iternext((AV*)hv)) { + while (entry = hv_iternext(keys)) { SPAGAIN; if (dokeys) XPUSHs(hv_iterkeysv(entry)); /* won't clobber stack_sp */ if (dovalues) { - tmpstr = sv_newmortal(); PUTBACK; - sv_setsv(tmpstr,realhv ? - hv_iterval(hv,entry) : avhv_iterval((AV*)hv,entry)); + tmpstr = realhv ? + hv_iterval(hv,entry) : avhv_iterval((AV*)hv,entry); DEBUG_H(sv_setpvf(tmpstr, "%lu%%%d=%lu", (unsigned long)HeHASH(entry), - HvMAX(hv)+1, - (unsigned long)(HeHASH(entry) & HvMAX(hv)))); + HvMAX(keys)+1, + (unsigned long)(HeHASH(entry) & HvMAX(keys)))); SPAGAIN; XPUSHs(tmpstr); }