This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
state variables shouldn't be shared between anon subs
[perl5.git] / utf8.c
diff --git a/utf8.c b/utf8.c
index f4e62ac..a761d82 100644 (file)
--- a/utf8.c
+++ b/utf8.c
@@ -1,6 +1,6 @@
 /*    utf8.c
  *
- *    Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006,
+ *    Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
  *    by Larry Wall and others
  *
  *    You may distribute under the terms of either the GNU General Public
 #define PERL_IN_UTF8_C
 #include "perl.h"
 
+#ifndef EBCDIC
+/* Separate prototypes needed because in ASCII systems these
+ * usually macros but they still are compiled as code, too. */
+PERL_CALLCONV UV       Perl_utf8n_to_uvchr(pTHX_ const U8 *s, STRLEN curlen, STRLEN *retlen, U32 flags);
+PERL_CALLCONV U8*      Perl_uvchr_to_utf8(pTHX_ U8 *d, UV uv);
+#endif
+
 static const char unees[] =
     "Malformed UTF-8 character (unexpected end of string)";
 
@@ -186,7 +193,7 @@ five bytes or more.
 
 =cut */
 STATIC STRLEN
-S_is_utf8_char_slow(pTHX_ const U8 *s, const STRLEN len)
+S_is_utf8_char_slow(const U8 *s, const STRLEN len)
 {
     U8 u = *s;
     STRLEN slen;
@@ -238,6 +245,7 @@ STRLEN
 Perl_is_utf8_char(pTHX_ const U8 *s)
 {
     const STRLEN len = UTF8SKIP(s);
+    PERL_UNUSED_CONTEXT;
 #ifdef IS_UTF8_CHAR
     if (IS_UTF8_CHAR_FAST(len))
         return IS_UTF8_CHAR(s, len) ? len : 0;
@@ -261,12 +269,10 @@ See also is_utf8_string_loclen() and is_utf8_string_loc().
 bool
 Perl_is_utf8_string(pTHX_ const U8 *s, STRLEN len)
 {
+    const U8* const send = s + (len ? len : strlen((const char *)s));
     const U8* x = s;
-    const U8* send;
 
-    if (!len)
-       len = strlen((const char *)s);
-    send = s + len;
+    PERL_UNUSED_CONTEXT;
 
     while (x < send) {
        STRLEN c;
@@ -281,9 +287,10 @@ Perl_is_utf8_string(pTHX_ const U8 *s, STRLEN len)
             c = UTF8SKIP(x);
             if (IS_UTF8_CHAR_FAST(c)) {
                 if (!IS_UTF8_CHAR(x, c))
-                    goto out;
-            } else if (!is_utf8_char_slow(x, c))
-                goto out;
+                    c = 0;
+            }
+            else
+               c = is_utf8_char_slow(x, c);
 #else
             c = is_utf8_char(x);
 #endif /* #ifdef IS_UTF8_CHAR */
@@ -326,15 +333,11 @@ See also is_utf8_string_loc() and is_utf8_string().
 bool
 Perl_is_utf8_string_loclen(pTHX_ const U8 *s, STRLEN len, const U8 **ep, STRLEN *el)
 {
+    const U8* const send = s + (len ? len : strlen((const char *)s));
     const U8* x = s;
-    const U8* send;
     STRLEN c;
-
-    if (!len)
-        len = strlen((const char *)s);
-    send = s + len;
-    if (el)
-        *el = 0;
+    STRLEN outlen = 0;
+    PERL_UNUSED_CONTEXT;
 
     while (x < send) {
         /* Inline the easy bits of is_utf8_char() here for speed... */
@@ -358,17 +361,16 @@ Perl_is_utf8_string_loclen(pTHX_ const U8 *s, STRLEN len, const U8 **ep, STRLEN
                 goto out;
         }
          x += c;
-        if (el)
-            (*el)++;
+        outlen++;
     }
 
  out:
+    if (el)
+        *el = outlen;
+
     if (ep)
         *ep = x;
-    if (x != send)
-       return FALSE;
-
-    return TRUE;
+    return (x == send);
 }
 
 /*
@@ -376,7 +378,7 @@ Perl_is_utf8_string_loclen(pTHX_ const U8 *s, STRLEN len, const U8 **ep, STRLEN
 =for apidoc A|UV|utf8n_to_uvuni|const U8 *s|STRLEN curlen|STRLEN *retlen|U32 flags
 
 Bottom level UTF-8 decode routine.
-Returns the unicode code point value of the first character in the string C<s>
+Returns the Unicode code point value of the first character in the string C<s>
 which is assumed to be in UTF-8 encoding and no longer than C<curlen>;
 C<retlen> will be set to the length, in bytes, of that character.
 
@@ -399,7 +401,8 @@ Most code should use utf8_to_uvchr() rather than call this directly.
 UV
 Perl_utf8n_to_uvuni(pTHX_ const U8 *s, STRLEN curlen, STRLEN *retlen, U32 flags)
 {
-    const U8 *s0 = s;
+    dVAR;
+    const U8 * const s0 = s;
     UV uv = *s, ouv = 0;
     STRLEN len = 1;
     const bool dowarn = ckWARN_d(WARN_UTF8);
@@ -528,17 +531,17 @@ malformed:
 
     if (flags & UTF8_CHECK_ONLY) {
        if (retlen)
-           *retlen = -1;
+           *retlen = ((STRLEN) -1);
        return 0;
     }
 
     if (dowarn) {
-       SV* const sv = sv_2mortal(newSVpv("Malformed UTF-8 character ", 0));
+       SV* const sv = sv_2mortal(newSVpvs("Malformed UTF-8 character "));
 
        switch (warning) {
        case 0: /* Intentionally empty. */ break;
        case UTF8_WARN_EMPTY:
-           Perl_sv_catpv(aTHX_ sv, "(empty string)");
+           sv_catpvs(sv, "(empty string)");
            break;
        case UTF8_WARN_CONTINUATION:
            Perl_sv_catpvf(aTHX_ sv, "(unexpected continuation byte 0x%02"UVxf", with no preceding start byte)", uv);
@@ -577,7 +580,7 @@ malformed:
            Perl_sv_catpvf(aTHX_ sv, "(character 0x%04"UVxf")", uv);
            break;
        default:
-           Perl_sv_catpv(aTHX_ sv, "(unknown reason)");
+           sv_catpvs(sv, "(unknown reason)");
            break;
        }
        
@@ -655,7 +658,9 @@ up past C<e>, croaks.
 STRLEN
 Perl_utf8_length(pTHX_ const U8 *s, const U8 *e)
 {
+    dVAR;
     STRLEN len = 0;
+    U8 t = 0;
 
     /* Note: cannot use UTF8_IS_...() too eagerly here since e.g.
      * the bitops (especially ~) can create illegal UTF-8.
@@ -664,7 +669,7 @@ Perl_utf8_length(pTHX_ const U8 *s, const U8 *e)
     if (e < s)
        goto warn_and_return;
     while (s < e) {
-       const U8 t = UTF8SKIP(s);
+       t = UTF8SKIP(s);
        if (e - s < t) {
            warn_and_return:
            if (ckWARN_d(WARN_UTF8)) {
@@ -698,42 +703,7 @@ same UTF-8 buffer.
 IV
 Perl_utf8_distance(pTHX_ const U8 *a, const U8 *b)
 {
-    IV off = 0;
-
-    /* Note: cannot use UTF8_IS_...() too eagerly here since  e.g.
-     * the bitops (especially ~) can create illegal UTF-8.
-     * In other words: in Perl UTF-8 is not just for Unicode. */
-
-    if (a < b) {
-       while (a < b) {
-           const U8 c = UTF8SKIP(a);
-           if (b - a < c)
-               goto warn_and_return;
-           a += c;
-           off--;
-       }
-    }
-    else {
-       while (b < a) {
-           const U8 c = UTF8SKIP(b);
-
-           if (a - b < c) {
-               warn_and_return:
-               if (ckWARN_d(WARN_UTF8)) {
-                   if (PL_op)
-                       Perl_warner(aTHX_ packWARN(WARN_UTF8),
-                                   "%s in %s", unees, OP_DESC(PL_op));
-                   else
-                       Perl_warner(aTHX_ packWARN(WARN_UTF8), unees);
-               }
-               return off;
-           }
-           b += c;
-           off++;
-       }
-    }
-
-    return off;
+    return (a < b) ? -1 * (IV) utf8_length(a, b) : (IV) utf8_length(b, a);
 }
 
 /*
@@ -752,6 +722,7 @@ on the first byte of character or just after the last byte of a character.
 U8 *
 Perl_utf8_hop(pTHX_ const U8 *s, I32 off)
 {
+    PERL_UNUSED_CONTEXT;
     /* Note: cannot use UTF8_IS_...() too eagerly here since e.g
      * the bitops (especially ~) can create illegal UTF-8.
      * In other words: in Perl UTF-8 is not just for Unicode. */
@@ -778,24 +749,26 @@ Unlike C<bytes_to_utf8>, this over-writes the original string, and
 updates len to contain the new length.
 Returns zero on failure, setting C<len> to -1.
 
+If you need a copy of the string, see C<bytes_from_utf8>.
+
 =cut
 */
 
 U8 *
 Perl_utf8_to_bytes(pTHX_ U8 *s, STRLEN *len)
 {
-    U8 *send;
+    U8 * const save = s;
+    U8 * const send = s + *len;
     U8 *d;
-    U8 *save = s;
 
     /* ensure valid UTF-8 and chars < 256 before updating string */
-    for (send = s + *len; s < send; ) {
+    while (s < send) {
         U8 c = *s++;
 
         if (!UTF8_IS_INVARIANT(c) &&
             (!UTF8_IS_DOWNGRADEABLE_START(c) || (s >= send)
             || !(c = *s++) || !UTF8_IS_CONTINUATION(c))) {
-            *len = -1;
+            *len = ((STRLEN) -1);
             return 0;
         }
     }
@@ -832,6 +805,7 @@ Perl_bytes_from_utf8(pTHX_ const U8 *s, STRLEN *len, bool *is_utf8)
     const U8 *send;
     I32 count = 0;
 
+    PERL_UNUSED_CONTEXT;
     if (!*is_utf8)
         return (U8 *)start;
 
@@ -847,9 +821,9 @@ Perl_bytes_from_utf8(pTHX_ const U8 *s, STRLEN *len, bool *is_utf8)
        }
     }
 
-    *is_utf8 = 0;              
+    *is_utf8 = FALSE;
 
-    Newxz(d, (*len) - count + 1, U8);
+    Newx(d, (*len) - count + 1, U8);
     s = start; start = d;
     while (s < send) {
        U8 c = *s++;
@@ -884,8 +858,9 @@ Perl_bytes_to_utf8(pTHX_ const U8 *s, STRLEN *len)
     const U8 * const send = s + (*len);
     U8 *d;
     U8 *dst;
+    PERL_UNUSED_CONTEXT;
 
-    Newxz(d, (*len) * 2 + 1, U8);
+    Newx(d, (*len) * 2 + 1, U8);
     dst = d;
 
     while (s < send) {
@@ -921,7 +896,7 @@ Perl_utf16_to_utf8(pTHX_ U8* p, U8* d, I32 bytelen, I32 *newlen)
     }
 
     if (bytelen & 1)
-       Perl_croak(aTHX_ "panic: utf16_to_utf8: odd bytelen %"UVf, (UV)bytelen);
+       Perl_croak(aTHX_ "panic: utf16_to_utf8: odd bytelen %"UVuf, (UV)bytelen);
 
     pend = p + bytelen;
 
@@ -929,7 +904,11 @@ Perl_utf16_to_utf8(pTHX_ U8* p, U8* d, I32 bytelen, I32 *newlen)
        UV uv = (p[0] << 8) + p[1]; /* UTF-16BE */
        p += 2;
        if (uv < 0x80) {
+#ifdef EBCDIC
+           *d++ = UNI_TO_NATIVE(uv);
+#else
            *d++ = (U8)uv;
+#endif
            continue;
        }
        if (uv < 0x800) {
@@ -968,9 +947,9 @@ U8*
 Perl_utf16_to_utf8_reversed(pTHX_ U8* p, U8* d, I32 bytelen, I32 *newlen)
 {
     U8* s = (U8*)p;
-    U8* send = s + bytelen;
+    U8* const send = s + bytelen;
     while (s < send) {
-       U8 tmp = s[0];
+       const U8 tmp = s[0];
        s[0] = s[1];
        s[1] = tmp;
        s += 2;
@@ -1240,6 +1219,7 @@ static bool
 S_is_utf8_common(pTHX_ const U8 *const p, SV **swash,
                 const char *const swashname)
 {
+    dVAR;
     if (!is_utf8_char(p))
        return FALSE;
     if (!*swash)
@@ -1250,105 +1230,121 @@ S_is_utf8_common(pTHX_ const U8 *const p, SV **swash,
 bool
 Perl_is_utf8_alnum(pTHX_ const U8 *p)
 {
+    dVAR;
     /* NOTE: "IsWord", not "IsAlnum", since Alnum is a true
      * descendant of isalnum(3), in other words, it doesn't
      * contain the '_'. --jhi */
-    return S_is_utf8_common(aTHX_ p, &PL_utf8_alnum, "IsWord");
+    return is_utf8_common(p, &PL_utf8_alnum, "IsWord");
 }
 
 bool
 Perl_is_utf8_alnumc(pTHX_ const U8 *p)
 {
-    return S_is_utf8_common(aTHX_ p, &PL_utf8_alnumc, "IsAlnumC");
+    dVAR;
+    return is_utf8_common(p, &PL_utf8_alnumc, "IsAlnumC");
 }
 
 bool
 Perl_is_utf8_idfirst(pTHX_ const U8 *p) /* The naming is historical. */
 {
+    dVAR;
     if (*p == '_')
        return TRUE;
     /* is_utf8_idstart would be more logical. */
-    return S_is_utf8_common(aTHX_ p, &PL_utf8_idstart, "IdStart");
+    return is_utf8_common(p, &PL_utf8_idstart, "IdStart");
 }
 
 bool
 Perl_is_utf8_idcont(pTHX_ const U8 *p)
 {
+    dVAR;
     if (*p == '_')
        return TRUE;
-    return S_is_utf8_common(aTHX_ p, &PL_utf8_idcont, "IdContinue");
+    return is_utf8_common(p, &PL_utf8_idcont, "IdContinue");
 }
 
 bool
 Perl_is_utf8_alpha(pTHX_ const U8 *p)
 {
-    return S_is_utf8_common(aTHX_ p, &PL_utf8_alpha, "IsAlpha");
+    dVAR;
+    return is_utf8_common(p, &PL_utf8_alpha, "IsAlpha");
 }
 
 bool
 Perl_is_utf8_ascii(pTHX_ const U8 *p)
 {
-    return S_is_utf8_common(aTHX_ p, &PL_utf8_ascii, "IsAscii");
+    dVAR;
+    return is_utf8_common(p, &PL_utf8_ascii, "IsAscii");
 }
 
 bool
 Perl_is_utf8_space(pTHX_ const U8 *p)
 {
-    return S_is_utf8_common(aTHX_ p, &PL_utf8_space, "IsSpacePerl");
+    dVAR;
+    return is_utf8_common(p, &PL_utf8_space, "IsSpacePerl");
 }
 
 bool
 Perl_is_utf8_digit(pTHX_ const U8 *p)
 {
-    return S_is_utf8_common(aTHX_ p, &PL_utf8_digit, "IsDigit");
+    dVAR;
+    return is_utf8_common(p, &PL_utf8_digit, "IsDigit");
 }
 
 bool
 Perl_is_utf8_upper(pTHX_ const U8 *p)
 {
-    return S_is_utf8_common(aTHX_ p, &PL_utf8_upper, "IsUppercase");
+    dVAR;
+    return is_utf8_common(p, &PL_utf8_upper, "IsUppercase");
 }
 
 bool
 Perl_is_utf8_lower(pTHX_ const U8 *p)
 {
-    return S_is_utf8_common(aTHX_ p, &PL_utf8_lower, "IsLowercase");
+    dVAR;
+    return is_utf8_common(p, &PL_utf8_lower, "IsLowercase");
 }
 
 bool
 Perl_is_utf8_cntrl(pTHX_ const U8 *p)
 {
-    return S_is_utf8_common(aTHX_ p, &PL_utf8_cntrl, "IsCntrl");
+    dVAR;
+    return is_utf8_common(p, &PL_utf8_cntrl, "IsCntrl");
 }
 
 bool
 Perl_is_utf8_graph(pTHX_ const U8 *p)
 {
-    return S_is_utf8_common(aTHX_ p, &PL_utf8_graph, "IsGraph");
+    dVAR;
+    return is_utf8_common(p, &PL_utf8_graph, "IsGraph");
 }
 
 bool
 Perl_is_utf8_print(pTHX_ const U8 *p)
 {
-    return S_is_utf8_common(aTHX_ p, &PL_utf8_print, "IsPrint");
+    dVAR;
+    return is_utf8_common(p, &PL_utf8_print, "IsPrint");
 }
 
 bool
 Perl_is_utf8_punct(pTHX_ const U8 *p)
 {
-    return S_is_utf8_common(aTHX_ p, &PL_utf8_punct, "IsPunct");
+    dVAR;
+    return is_utf8_common(p, &PL_utf8_punct, "IsPunct");
 }
 
 bool
 Perl_is_utf8_xdigit(pTHX_ const U8 *p)
 {
-    return S_is_utf8_common(aTHX_ p, &PL_utf8_xdigit, "Isxdigit");
+    dVAR;
+    return is_utf8_common(p, &PL_utf8_xdigit, "Isxdigit");
 }
 
 bool
 Perl_is_utf8_mark(pTHX_ const U8 *p)
 {
-    return S_is_utf8_common(aTHX_ p, &PL_utf8_mark, "IsM");
+    dVAR;
+    return is_utf8_common(p, &PL_utf8_mark, "IsM");
 }
 
 /*
@@ -1380,6 +1376,7 @@ UV
 Perl_to_utf8_case(pTHX_ const U8 *p, U8* ustrp, STRLEN *lenp,
                        SV **swashp, const char *normal, const char *special)
 {
+    dVAR;
     U8 tmpbuf[UTF8_MAXBYTES_CASE+1];
     STRLEN len = 0;
 
@@ -1397,10 +1394,10 @@ Perl_to_utf8_case(pTHX_ const U8 *p, U8* ustrp, STRLEN *lenp,
     if (special && (uv1 == 0xDF || uv1 > 0xFF)) {
          /* It might be "special" (sometimes, but not always,
          * a multicharacter mapping) */
-        HV *hv;
+        HV * const hv = get_hv(special, FALSE);
         SV **svp;
 
-        if ((hv  = get_hv(special, FALSE)) &&
+        if (hv &&
             (svp = hv_fetch(hv, (const char*)tmpbuf, UNISKIP(uv1), FALSE)) &&
             (*svp)) {
             const char *s;
@@ -1420,7 +1417,7 @@ Perl_to_utf8_case(pTHX_ const U8 *p, U8* ustrp, STRLEN *lenp,
                        STRLEN tlen = 0;
                        
                        while (t < tend) {
-                            UV c = utf8_to_uvchr(t, &tlen);
+                            const UV c = utf8_to_uvchr(t, &tlen);
                             if (tlen > 0) {
                                  d = uvchr_to_utf8(d, UNI_TO_NATIVE(c));
                                  t += tlen;
@@ -1445,12 +1442,11 @@ Perl_to_utf8_case(pTHX_ const U8 *p, U8* ustrp, STRLEN *lenp,
     }
 
     if (!len && *swashp) {
-        UV uv2 = swash_fetch(*swashp, tmpbuf, TRUE);
-        
+       const UV uv2 = swash_fetch(*swashp, tmpbuf, TRUE);
+
         if (uv2) {
              /* It was "normal" (a single character mapping). */
-             UV uv3 = UNI_TO_NATIVE(uv2);
-             
+             const UV uv3 = UNI_TO_NATIVE(uv2);
              len = uvchr_to_utf8(ustrp, uv3) - ustrp;
         }
     }
@@ -1480,6 +1476,7 @@ The first character of the uppercased version is returned
 UV
 Perl_to_utf8_upper(pTHX_ const U8 *p, U8* ustrp, STRLEN *lenp)
 {
+    dVAR;
     return Perl_to_utf8_case(aTHX_ p, ustrp, lenp,
                              &PL_utf8_toupper, "ToUpper", "utf8::ToSpecUpper");
 }
@@ -1500,6 +1497,7 @@ The first character of the titlecased version is returned
 UV
 Perl_to_utf8_title(pTHX_ const U8 *p, U8* ustrp, STRLEN *lenp)
 {
+    dVAR;
     return Perl_to_utf8_case(aTHX_ p, ustrp, lenp,
                              &PL_utf8_totitle, "ToTitle", "utf8::ToSpecTitle");
 }
@@ -1520,6 +1518,7 @@ The first character of the lowercased version is returned
 UV
 Perl_to_utf8_lower(pTHX_ const U8 *p, U8* ustrp, STRLEN *lenp)
 {
+    dVAR;
     return Perl_to_utf8_case(aTHX_ p, ustrp, lenp,
                              &PL_utf8_tolower, "ToLower", "utf8::ToSpecLower");
 }
@@ -1541,6 +1540,7 @@ The first character of the foldcased version is returned
 UV
 Perl_to_utf8_fold(pTHX_ const U8 *p, U8* ustrp, STRLEN *lenp)
 {
+    dVAR;
     return Perl_to_utf8_case(aTHX_ p, ustrp, lenp,
                              &PL_utf8_tofold, "ToFold", "utf8::ToSpecFold");
 }
@@ -1556,11 +1556,10 @@ Perl_swash_init(pTHX_ const char* pkg, const char* name, SV *listsv, I32 minbits
 {
     dVAR;
     SV* retval;
-    SV* const tokenbufsv = sv_newmortal();
     dSP;
     const size_t pkg_len = strlen(pkg);
     const size_t name_len = strlen(name);
-    HV * const stash = gv_stashpvn(pkg, pkg_len, FALSE);
+    HV * const stash = gv_stashpvn(pkg, pkg_len, 0);
     SV* errsv_save;
 
     PUSHSTACKi(PERLSI_MAGIC);
@@ -1571,8 +1570,15 @@ Perl_swash_init(pTHX_ const char* pkg, const char* name, SV *listsv, I32 minbits
     if (!gv_fetchmeth(stash, "SWASHNEW", 8, -1)) {     /* demand load utf8 */
        ENTER;
        errsv_save = newSVsv(ERRSV);
+       /* It is assumed that callers of this routine are not passing in any
+          user derived data.  */
+       /* Need to do this after save_re_context() as it will set PL_tainted to
+          1 while saving $1 etc (see the code after getrx: in Perl_magic_get).
+          Even line to create errsv_save can turn on PL_tainted.  */
+       SAVEBOOL(PL_tainted);
+       PL_tainted = 0;
        Perl_load_module(aTHX_ PERL_LOADMOD_NOIMPORT, newSVpvn(pkg,pkg_len),
-                        Nullsv);
+                        NULL);
        if (!SvTRUE(ERRSV))
            sv_setsv(ERRSV, errsv_save);
        SvREFCNT_dec(errsv_save);
@@ -1587,12 +1593,6 @@ Perl_swash_init(pTHX_ const char* pkg, const char* name, SV *listsv, I32 minbits
     PUSHs(sv_2mortal(newSViv(minbits)));
     PUSHs(sv_2mortal(newSViv(none)));
     PUTBACK;
-    if (IN_PERL_COMPILETIME) {
-       /* XXX ought to be handled by lex_start */
-       SAVEI32(PL_in_my);
-       PL_in_my = 0;
-       sv_setpv(tokenbufsv, PL_tokenbuf);
-    }
     errsv_save = newSVsv(ERRSV);
     if (call_method("SWASHNEW", G_SCALAR))
        retval = newSVsv(*PL_stack_sp--);
@@ -1604,16 +1604,12 @@ Perl_swash_init(pTHX_ const char* pkg, const char* name, SV *listsv, I32 minbits
     LEAVE;
     POPSTACK;
     if (IN_PERL_COMPILETIME) {
-       STRLEN len;
-       const char* const pv = SvPV_const(tokenbufsv, len);
-
-       Copy(pv, PL_tokenbuf, len+1, char);
-       PL_curcop->op_private = (U8)(PL_hints & HINT_PRIVATE_MASK);
+       CopHINTS_set(PL_curcop, PL_hints);
     }
     if (!SvROK(retval) || SvTYPE(SvRV(retval)) != SVt_PVHV) {
         if (SvPOK(retval))
            Perl_croak(aTHX_ "Can't find Unicode property definition \"%"SVf"\"",
-                      retval);
+                      SVfARG(retval));
        Perl_croak(aTHX_ "SWASHNEW didn't return an HV ref");
     }
     return retval;
@@ -1646,7 +1642,7 @@ Perl_swash_fetch(pTHX_ SV *swash, const U8 *ptr, bool do_utf8)
     U32 bit;
     SV *swatch;
     U8 tmputf8[2];
-    UV c = NATIVE_TO_ASCII(*ptr);
+    const UV c = NATIVE_TO_ASCII(*ptr);
 
     if (!do_utf8 && !UNI_IS_INVARIANT(c)) {
        tmputf8[0] = (U8)UTF8_EIGHT_BIT_HI(c);
@@ -1709,7 +1705,7 @@ Perl_swash_fetch(pTHX_ SV *swash, const U8 *ptr, bool do_utf8)
                                needents);
 
            if (IN_PERL_COMPILETIME)
-               PL_curcop->op_private = (U8)(PL_hints & HINT_PRIVATE_MASK);
+               CopHINTS_set(PL_curcop, PL_hints);
 
            svp = hv_store(hv, (const char *)ptr, klen, swatch, 0);
 
@@ -1719,7 +1715,8 @@ Perl_swash_fetch(pTHX_ SV *swash, const U8 *ptr, bool do_utf8)
        }
 
        PL_last_swash_hv = hv;
-       PL_last_swash_klen = klen;
+       assert(klen <= sizeof(PL_last_swash_key));
+       PL_last_swash_klen = (U8)klen;
        /* FIXME change interpvar.h?  */
        PL_last_swash_tmps = (U8 *) tmps;
        PL_last_swash_slen = slen;
@@ -1742,7 +1739,7 @@ Perl_swash_fetch(pTHX_ SV *swash, const U8 *ptr, bool do_utf8)
        return (tmps[off] << 24) + (tmps[off+1] << 16) + (tmps[off+2] << 8) + tmps[off + 3] ;
     }
     Perl_croak(aTHX_ "panic: swash_fetch got swatch of unexpected bit width");
-    return 0;
+    NORETURN_FUNCTION_END;
 }
 
 /* Note:
@@ -1759,11 +1756,11 @@ S_swash_get(pTHX_ SV* swash, UV start, UV span)
     STRLEN lcur, xcur, scur;
 
     HV* const hv = (HV*)SvRV(swash);
-    SV** const listsvp = hv_fetch(hv, "LIST", 4, FALSE);
-    SV** const typesvp = hv_fetch(hv, "TYPE", 4, FALSE);
-    SV** const bitssvp = hv_fetch(hv, "BITS", 4, FALSE);
-    SV** const nonesvp = hv_fetch(hv, "NONE", 4, FALSE);
-    SV** const extssvp = hv_fetch(hv, "EXTRAS", 6, FALSE);
+    SV** const listsvp = hv_fetchs(hv, "LIST", FALSE);
+    SV** const typesvp = hv_fetchs(hv, "TYPE", FALSE);
+    SV** const bitssvp = hv_fetchs(hv, "BITS", FALSE);
+    SV** const nonesvp = hv_fetchs(hv, "NONE", FALSE);
+    SV** const extssvp = hv_fetchs(hv, "EXTRAS", FALSE);
     const U8* const typestr = (U8*)SvPV_nolen(*typesvp);
     const int  typeto  = typestr[0] == 'T' && typestr[1] == 'o';
     const STRLEN bits  = SvUV(*bitssvp);
@@ -1777,7 +1774,7 @@ S_swash_get(pTHX_ SV* swash, UV start, UV span)
     }
 
     /* create and initialize $swatch */
-    swatch = newSVpvn("",0);
+    swatch = newSVpvs("");
     scur   = octets ? (span * octets) : (span + 7) / 8;
     SvGROW(swatch, scur + 1);
     s = (U8*)SvPVX(swatch);
@@ -1809,7 +1806,7 @@ S_swash_get(pTHX_ SV* swash, UV start, UV span)
     l = (U8*)SvPV(*listsvp, lcur);
     lend = l + lcur;
     while (l < lend) {
-       UV min, max, val, key;
+       UV min, max, val;
        STRLEN numlen;
        I32 flags = PERL_SCAN_SILENT_ILLDIGIT | PERL_SCAN_DISALLOW_PREFIX;
 
@@ -1882,6 +1879,7 @@ S_swash_get(pTHX_ SV* swash, UV start, UV span)
            continue;
 
        if (octets) {
+           UV key;
            if (min < start) {
                if (!none || val < none) {
                    val += start - min;
@@ -1912,6 +1910,7 @@ S_swash_get(pTHX_ SV* swash, UV start, UV span)
            }
        }
        else { /* bits == 1, then val should be ignored */
+           UV key;
            if (min < start)
                min = start;
            for (key = min; key <= max; key++) {
@@ -1937,7 +1936,7 @@ S_swash_get(pTHX_ SV* swash, UV start, UV span)
        U8 *s, *o, *nl;
        STRLEN slen, olen;
 
-       U8 opc = *x++;
+       const U8 opc = *x++;
        if (opc == '\n')
            continue;
 
@@ -1966,7 +1965,7 @@ S_swash_get(pTHX_ SV* swash, UV start, UV span)
 
        othersvp = hv_fetch(hv, (char *)namestr, namelen, FALSE);
        otherhv = (HV*)SvRV(*othersvp);
-       otherbitssvp = hv_fetch(otherhv, "BITS", 4, FALSE);
+       otherbitssvp = hv_fetchs(otherhv, "BITS", FALSE);
        otherbits = (STRLEN)SvUV(*otherbitssvp);
        if (bits < otherbits)
            Perl_croak(aTHX_ "panic: swash_get found swatch size mismatch");
@@ -2007,7 +2006,7 @@ S_swash_get(pTHX_ SV* swash, UV start, UV span)
        else {
            STRLEN otheroctets = otherbits >> 3;
            STRLEN offset = 0;
-           U8* send = s + slen;
+           U8* const send = s + slen;
 
            while (s < send) {
                UV otherval = 0;
@@ -2026,7 +2025,7 @@ S_swash_get(pTHX_ SV* swash, UV start, UV span)
                }
 
                if (opc == '+' && otherval)
-                   ; /* replace with otherval */
+                   NOOP;   /* replace with otherval */
                else if (opc == '!' && !otherval)
                    otherval = 1;
                else if (opc == '-' && otherval)
@@ -2181,7 +2180,7 @@ Perl_pv_uni_display(pTHX_ SV *dsv, const U8 *spv, STRLEN len, STRLEN pvlim, UV f
             Perl_sv_catpvf(aTHX_ dsv, "\\x{%"UVxf"}", u);
     }
     if (truncated)
-        sv_catpvn(dsv, "...", 3);
+        sv_catpvs(dsv, "...");
     
     return SvPVX(dsv);
 }
@@ -2197,7 +2196,8 @@ The flags argument is as in pv_uni_display().
 
 The pointer to the PV of the dsv is returned.
 
-=cut */
+=cut
+*/
 char *
 Perl_sv_uni_display(pTHX_ SV *dsv, SV *ssv, STRLEN pvlim, UV flags)
 {
@@ -2233,10 +2233,11 @@ http://www.unicode.org/unicode/reports/tr21/ (Case Mappings).
 I32
 Perl_ibcmp_utf8(pTHX_ const char *s1, char **pe1, register UV l1, bool u1, const char *s2, char **pe2, register UV l2, bool u2)
 {
+     dVAR;
      register const U8 *p1  = (const U8*)s1;
      register const U8 *p2  = (const U8*)s2;
      register const U8 *f1 = NULL;
-     register U8 *f2 = NULL;
+     register const U8 *f2 = NULL;
      register U8 *e1 = NULL;
      register U8 *q1 = NULL;
      register U8 *e2 = NULL;