X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=utf8.c;h=87b9088e16766fbd63654c07adba8d02ea9b86b0;hb=6008b2cdded3e19383438abf72747730e4e5f4a3;hp=93c112837b2521b39bc09f896444c11ace5268bb;hpb=ccfc67b7b0a9fa9e1a1cbb2090b71ea33fc44ae7;p=p5sagit%2Fp5-mst-13.2.git diff --git a/utf8.c b/utf8.c index 93c1128..87b9088 100644 --- a/utf8.c +++ b/utf8.c @@ -1,6 +1,6 @@ /* utf8.c * - * Copyright (c) 1998-2001, Larry Wall + * Copyright (c) 1998-2002, 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. @@ -54,7 +54,7 @@ is the recommended Unicode-aware way of saying U8 * Perl_uvuni_to_utf8_flags(pTHX_ U8 *d, UV uv, UV flags) { - if (ckWARN_d(WARN_UTF8)) { + if (ckWARN(WARN_UTF8)) { if (UNICODE_IS_SURROGATE(uv) && !(flags & UNICODE_ALLOW_SURROGATE)) Perl_warner(aTHX_ WARN_UTF8, "UTF-16 surrogate 0x%04"UVxf, uv); @@ -841,7 +841,7 @@ bool Perl_is_uni_alnum(pTHX_ UV c) { U8 tmpbuf[UTF8_MAXLEN+1]; - uvchr_to_utf8(tmpbuf, (UV)c); + uvchr_to_utf8(tmpbuf, c); return is_utf8_alnum(tmpbuf); } @@ -849,7 +849,7 @@ bool Perl_is_uni_alnumc(pTHX_ UV c) { U8 tmpbuf[UTF8_MAXLEN+1]; - uvchr_to_utf8(tmpbuf, (UV)c); + uvchr_to_utf8(tmpbuf, c); return is_utf8_alnumc(tmpbuf); } @@ -857,7 +857,7 @@ bool Perl_is_uni_idfirst(pTHX_ UV c) { U8 tmpbuf[UTF8_MAXLEN+1]; - uvchr_to_utf8(tmpbuf, (UV)c); + uvchr_to_utf8(tmpbuf, c); return is_utf8_idfirst(tmpbuf); } @@ -865,7 +865,7 @@ bool Perl_is_uni_alpha(pTHX_ UV c) { U8 tmpbuf[UTF8_MAXLEN+1]; - uvchr_to_utf8(tmpbuf, (UV)c); + uvchr_to_utf8(tmpbuf, c); return is_utf8_alpha(tmpbuf); } @@ -873,7 +873,7 @@ bool Perl_is_uni_ascii(pTHX_ UV c) { U8 tmpbuf[UTF8_MAXLEN+1]; - uvchr_to_utf8(tmpbuf, (UV)c); + uvchr_to_utf8(tmpbuf, c); return is_utf8_ascii(tmpbuf); } @@ -881,7 +881,7 @@ bool Perl_is_uni_space(pTHX_ UV c) { U8 tmpbuf[UTF8_MAXLEN+1]; - uvchr_to_utf8(tmpbuf, (UV)c); + uvchr_to_utf8(tmpbuf, c); return is_utf8_space(tmpbuf); } @@ -889,7 +889,7 @@ bool Perl_is_uni_digit(pTHX_ UV c) { U8 tmpbuf[UTF8_MAXLEN+1]; - uvchr_to_utf8(tmpbuf, (UV)c); + uvchr_to_utf8(tmpbuf, c); return is_utf8_digit(tmpbuf); } @@ -897,7 +897,7 @@ bool Perl_is_uni_upper(pTHX_ UV c) { U8 tmpbuf[UTF8_MAXLEN+1]; - uvchr_to_utf8(tmpbuf, (UV)c); + uvchr_to_utf8(tmpbuf, c); return is_utf8_upper(tmpbuf); } @@ -905,7 +905,7 @@ bool Perl_is_uni_lower(pTHX_ UV c) { U8 tmpbuf[UTF8_MAXLEN+1]; - uvchr_to_utf8(tmpbuf, (UV)c); + uvchr_to_utf8(tmpbuf, c); return is_utf8_lower(tmpbuf); } @@ -913,7 +913,7 @@ bool Perl_is_uni_cntrl(pTHX_ UV c) { U8 tmpbuf[UTF8_MAXLEN+1]; - uvchr_to_utf8(tmpbuf, (UV)c); + uvchr_to_utf8(tmpbuf, c); return is_utf8_cntrl(tmpbuf); } @@ -921,7 +921,7 @@ bool Perl_is_uni_graph(pTHX_ UV c) { U8 tmpbuf[UTF8_MAXLEN+1]; - uvchr_to_utf8(tmpbuf, (UV)c); + uvchr_to_utf8(tmpbuf, c); return is_utf8_graph(tmpbuf); } @@ -929,7 +929,7 @@ bool Perl_is_uni_print(pTHX_ UV c) { U8 tmpbuf[UTF8_MAXLEN+1]; - uvchr_to_utf8(tmpbuf, (UV)c); + uvchr_to_utf8(tmpbuf, c); return is_utf8_print(tmpbuf); } @@ -937,7 +937,7 @@ bool Perl_is_uni_punct(pTHX_ UV c) { U8 tmpbuf[UTF8_MAXLEN+1]; - uvchr_to_utf8(tmpbuf, (UV)c); + uvchr_to_utf8(tmpbuf, c); return is_utf8_punct(tmpbuf); } @@ -945,40 +945,36 @@ bool Perl_is_uni_xdigit(pTHX_ UV c) { U8 tmpbuf[UTF8_MAXLEN_UCLC+1]; - uvchr_to_utf8(tmpbuf, (UV)c); + uvchr_to_utf8(tmpbuf, c); return is_utf8_xdigit(tmpbuf); } UV Perl_to_uni_upper(pTHX_ UV c, U8* p, STRLEN *lenp) { - U8 tmpbuf[UTF8_MAXLEN_UCLC+1]; - uvchr_to_utf8(tmpbuf, (UV)c); - return to_utf8_upper(tmpbuf, p, lenp); + uvchr_to_utf8(p, c); + return to_utf8_upper(p, p, lenp); } UV Perl_to_uni_title(pTHX_ UV c, U8* p, STRLEN *lenp) { - U8 tmpbuf[UTF8_MAXLEN_UCLC+1]; - uvchr_to_utf8(tmpbuf, (UV)c); - return to_utf8_title(tmpbuf, p, lenp); + uvchr_to_utf8(p, c); + return to_utf8_title(p, p, lenp); } UV Perl_to_uni_lower(pTHX_ UV c, U8* p, STRLEN *lenp) { - U8 tmpbuf[UTF8_MAXLEN_UCLC+1]; - uvchr_to_utf8(tmpbuf, (UV)c); - return to_utf8_lower(tmpbuf, p, lenp); + uvchr_to_utf8(p, c); + return to_utf8_lower(p, p, lenp); } UV Perl_to_uni_fold(pTHX_ UV c, U8* p, STRLEN *lenp) { - U8 tmpbuf[UTF8_MAXLEN_FOLD+1]; - uvchr_to_utf8(tmpbuf, (UV)c); - return to_utf8_fold(tmpbuf, p, lenp); + uvchr_to_utf8(p, c); + return to_utf8_fold(p, p, lenp); } /* for now these all assume no locale info available for Unicode > 255 */ @@ -1270,58 +1266,109 @@ The "ustrp" is a pointer to the character buffer to put the conversion result to. The "lenp" is a pointer to the length of the result. -The "swash" is a pointer to the swash to use. +The "swashp" is a pointer to the swash to use. -The "normal" is a string like "ToLower" which means the swash -$utf8::ToLower, which is stored in lib/unicore/To/Lower.pl, -and loaded by SWASHGET, using lib/utf8_heavy.pl. +Both the special and normal mappings are stored lib/unicore/To/Foo.pl, +and loaded by SWASHGET, using lib/utf8_heavy.pl. The special (usually, +but not always, a multicharacter mapping), is tried first. -The "special" is a string like "utf8::ToSpecLower", which means -the hash %utf8::ToSpecLower, which is stored in the same file, -lib/unicore/To/Lower.pl, and also loaded by SWASHGET. The access -to the hash is by Perl_to_utf8_case(). +The "special" is a string like "utf8::ToSpecLower", which means the +hash %utf8::ToSpecLower. The access to the hash is through +Perl_to_utf8_case(). -=cut - */ +The "normal" is a string like "ToLower" which means the swash +%utf8::ToLower. + +=cut */ UV -Perl_to_utf8_case(pTHX_ U8 *p, U8* ustrp, STRLEN *lenp, SV **swashp,char *normal, char *special) +Perl_to_utf8_case(pTHX_ U8 *p, U8* ustrp, STRLEN *lenp, SV **swashp, char *normal, char *special) { - UV uv; + UV uv0, uv1; + U8 tmpbuf[UTF8_MAXLEN_FOLD+1]; + STRLEN len = 0; - if (!*swashp) - *swashp = swash_init("utf8", normal, &PL_sv_undef, 4, 0); - uv = swash_fetch(*swashp, p, TRUE); - if (uv) - uv = UNI_TO_NATIVE(uv); - else { + uv0 = utf8_to_uvchr(p, 0); + /* The NATIVE_TO_UNI() and UNI_TO_NATIVE() mappings + * are necessary in EBCDIC, they are redundant no-ops + * in ASCII-ish platforms, and hopefully optimized away. */ + uv1 = NATIVE_TO_UNI(uv0); + uvuni_to_utf8(tmpbuf, uv1); + + if (!*swashp) /* load on-demand */ + *swashp = swash_init("utf8", normal, &PL_sv_undef, 4, 0); + + if (special) { + /* It might be "special" (sometimes, but not always, + * a multicharacter mapping) */ HV *hv; SV *keysv; HE *he; - - uv = utf8_to_uvchr(p, 0); - + SV *val; + if ((hv = get_hv(special, FALSE)) && - (keysv = sv_2mortal(Perl_newSVpvf(aTHX_ "%04"UVXf, uv))) && - (he = hv_fetch_ent(hv, keysv, FALSE, 0))) { - SV *val = HeVAL(he); - char *s = SvPV(val, *lenp); - U8 c = *(U8*)s; - if (*lenp > 1 || UNI_IS_INVARIANT(c)) - Copy(s, ustrp, *lenp, U8); + (keysv = sv_2mortal(Perl_newSVpvf(aTHX_ "%04"UVXf, uv1))) && + (he = hv_fetch_ent(hv, keysv, FALSE, 0)) && + (val = HeVAL(he))) { + char *s; + + s = SvPV(val, len); + if (len == 1) + len = uvuni_to_utf8(ustrp, NATIVE_TO_UNI(*(U8*)s)) - ustrp; else { - /* something in the 0x80..0xFF range */ - ustrp[0] = UTF8_EIGHT_BIT_HI(c); - ustrp[1] = UTF8_EIGHT_BIT_LO(c); - *lenp = 2; +#ifdef EBCDIC + /* If we have EBCDIC we need to remap the characters + * since any characters in the low 256 are Unicode + * code points, not EBCDIC. */ + U8 *t = (U8*)s, *tend = t + len, *d; + + d = tmpbuf; + if (SvUTF8(val)) { + STRLEN tlen = 0; + + while (t < tend) { + UV c = utf8_to_uvchr(t, &tlen); + if (tlen > 0) { + d = uvchr_to_utf8(d, UNI_TO_NATIVE(c)); + t += tlen; + } + else + break; + } + } + else { + while (t < tend) { + d = uvchr_to_utf8(d, UNI_TO_NATIVE(*t)); + t++; + } + } + len = d - tmpbuf; + Copy(tmpbuf, ustrp, len, U8); +#else + Copy(s, ustrp, len, U8); +#endif } - return utf8_to_uvchr(ustrp, 0); } } + + if (!len && *swashp) { + UV uv2 = swash_fetch(*swashp, tmpbuf, TRUE); + + if (uv2) { + /* It was "normal" (a single character mapping). */ + UV uv3 = UNI_TO_NATIVE(uv2); + + len = uvchr_to_utf8(ustrp, uv3) - ustrp; + } + } + + if (!len) /* Neither: just copy. */ + len = uvchr_to_utf8(ustrp, uv0) - ustrp; + if (lenp) - *lenp = UNISKIP(uv); - uvuni_to_utf8(ustrp, uv); - return uv; + *lenp = len; + + return len ? utf8_to_uvchr(ustrp, 0) : 0; } /* @@ -1646,8 +1693,8 @@ Allows length and flags to be passed to low level routine. =cut */ -/* On ASCII machines this is normally a macro but we want a - real function in case XS code wants it +/* On ASCII machines this is normally a macro but we want + a real function in case XS code wants it */ #undef Perl_utf8n_to_uvchr UV @@ -1663,7 +1710,14 @@ Perl_utf8n_to_uvchr(pTHX_ U8 *s, STRLEN curlen, STRLEN *retlen, U32 flags) Build to the scalar dsv a displayable version of the string spv, length len, the displayable version being at most pvlim bytes long (if longer, the rest is truncated and "..." will be appended). -The flags argument is currently unused but available for future extensions. + +The flags argument can have UNI_DISPLAY_ISPRINT set to display +isPRINT()able characters as themselves, UNI_DISPLAY_BACKSLASH +to display the \\[nrfta\\] as the backslashed versions (like '\n') +(UNI_DISPLAY_BACKSLASH is preferred over UNI_DISPLAY_ISPRINT for \\). +UNI_DISPLAY_QQ (and its alias UNI_DISPLAY_REGEX) have both +UNI_DISPLAY_BACKSLASH and UNI_DISPLAY_ISPRINT turned on. + The pointer to the PV of the dsv is returned. =cut */ @@ -1676,12 +1730,39 @@ Perl_pv_uni_display(pTHX_ SV *dsv, U8 *spv, STRLEN len, STRLEN pvlim, UV flags) sv_setpvn(dsv, "", 0); for (s = (char *)spv, e = s + len; s < e; s += UTF8SKIP(s)) { UV u; + bool ok = FALSE; + if (pvlim && SvCUR(dsv) >= pvlim) { truncated++; break; } u = utf8_to_uvchr((U8*)s, 0); - Perl_sv_catpvf(aTHX_ dsv, "\\x{%"UVxf"}", u); + if (u < 256) { + if (!ok && (flags & UNI_DISPLAY_BACKSLASH)) { + switch (u & 0xFF) { + case '\n': + Perl_sv_catpvf(aTHX_ dsv, "\\n"); ok = TRUE; break; + case '\r': + Perl_sv_catpvf(aTHX_ dsv, "\\r"); ok = TRUE; break; + case '\t': + Perl_sv_catpvf(aTHX_ dsv, "\\t"); ok = TRUE; break; + case '\f': + Perl_sv_catpvf(aTHX_ dsv, "\\f"); ok = TRUE; break; + case '\a': + Perl_sv_catpvf(aTHX_ dsv, "\\a"); ok = TRUE; break; + case '\\': + Perl_sv_catpvf(aTHX_ dsv, "\\" ); ok = TRUE; break; + default: break; + } + } + /* isPRINT() is the locale-blind version. */ + if (!ok && (flags & UNI_DISPLAY_ISPRINT) && isPRINT(u & 0xFF)) { + Perl_sv_catpvf(aTHX_ dsv, "%c", (char)(u & 0xFF)); + ok = TRUE; + } + } + if (!ok) + Perl_sv_catpvf(aTHX_ dsv, "\\x{%"UVxf"}", u); } if (truncated) sv_catpvn(dsv, "...", 3); @@ -1693,9 +1774,11 @@ Perl_pv_uni_display(pTHX_ SV *dsv, U8 *spv, STRLEN len, STRLEN pvlim, UV flags) =for apidoc A|char *|sv_uni_display|SV *dsv|SV *ssv|STRLEN pvlim|UV flags Build to the scalar dsv a displayable version of the scalar sv, -he displayable version being at most pvlim bytes long +the displayable version being at most pvlim bytes long (if longer, the rest is truncated and "..." will be appended). -The flags argument is currently unused but available for future extensions. + +The flags argument is as in pv_uni_display(). + The pointer to the PV of the dsv is returned. =cut */ @@ -1757,6 +1840,9 @@ Perl_ibcmp_utf8(pTHX_ const char *s1, char **pe1, register UV l1, bool u1, const if ((e1 == 0 && f1 == 0) || (e2 == 0 && f2 == 0) || (f1 == 0 && f2 == 0)) return 1; /* mismatch; possible infinite loop or false positive */ + if (!u1 || !u2) + natbuf[1] = 0; /* Need to terminate the buffer. */ + while ((e1 == 0 || p1 < e1) && (f1 == 0 || p1 < f1) && (e2 == 0 || p2 < e2) && @@ -1765,7 +1851,7 @@ Perl_ibcmp_utf8(pTHX_ const char *s1, char **pe1, register UV l1, bool u1, const if (u1) to_utf8_fold(p1, foldbuf1, &foldlen1); else { - natbuf[0] = NATIVE_TO_UNI(*p1); + natbuf[0] = *p1; to_utf8_fold(natbuf, foldbuf1, &foldlen1); } q1 = foldbuf1; @@ -1775,7 +1861,7 @@ Perl_ibcmp_utf8(pTHX_ const char *s1, char **pe1, register UV l1, bool u1, const if (u2) to_utf8_fold(p2, foldbuf2, &foldlen2); else { - natbuf[0] = NATIVE_TO_UNI(*p2); + natbuf[0] = *p2; to_utf8_fold(natbuf, foldbuf2, &foldlen2); } q2 = foldbuf2;