This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
utf8.c: Change variable types so compiles on Solaris
[perl5.git] / utf8.c
diff --git a/utf8.c b/utf8.c
index 6b98473..a1f6632 100644 (file)
--- a/utf8.c
+++ b/utf8.c
@@ -1286,6 +1286,20 @@ All other code points corresponding to Unicode characters, including private
 use and those yet to be assigned, are never considered malformed and never
 warn.
 
+=for apidoc Amnh||UTF8_CHECK_ONLY
+=for apidoc Amnh||UTF8_DISALLOW_ILLEGAL_INTERCHANGE
+=for apidoc Amnh||UTF8_DISALLOW_ILLEGAL_C9_INTERCHANGE
+=for apidoc Amnh||UTF8_DISALLOW_SURROGATE
+=for apidoc Amnh||UTF8_DISALLOW_NONCHAR
+=for apidoc Amnh||UTF8_DISALLOW_SUPER
+=for apidoc Amnh||UTF8_WARN_ILLEGAL_INTERCHANGE
+=for apidoc Amnh||UTF8_WARN_ILLEGAL_C9_INTERCHANGE
+=for apidoc Amnh||UTF8_WARN_SURROGATE
+=for apidoc Amnh||UTF8_WARN_NONCHAR
+=for apidoc Amnh||UTF8_WARN_SUPER
+=for apidoc Amnh||UTF8_WARN_PERL_EXTENDED
+=for apidoc Amnh||UTF8_DISALLOW_PERL_EXTENDED
+
 =cut
 
 Also implemented as a macro in utf8.h
@@ -1860,7 +1874,7 @@ Perl__utf8n_to_uvchr_msgs_helper(const U8 *s,
         }
 
         while (possible_problems) { /* Handle each possible problem */
-            UV pack_warn = 0;
+            U32 pack_warn = 0;
             char * message = NULL;
             U32 this_flag_bit = 0;
 
@@ -1999,8 +2013,8 @@ Perl__utf8n_to_uvchr_msgs_helper(const U8 *s,
                          * valid, avoid as much as possible reading past the
                          * end of the buffer */
                         int printlen = (flags & _UTF8_NO_CONFIDENCE_IN_CURLEN)
-                                       ? s - s0
-                                       : send - s0;
+                                       ? (int) (s - s0)
+                                       : (int) (send - s0);
                         pack_warn = packWARN(WARN_UTF8);
                         message = Perl_form(aTHX_ "%s",
                             unexpected_non_continuation_text(s0,
@@ -2532,8 +2546,12 @@ Perl_bytes_from_utf8(pTHX_ const U8 *s, STRLEN *lenp, bool *is_utf8p)
 }
 
 /*
-No = here because currently externally undocumented
-for apidoc bytes_from_utf8_loc
+=for comment
+skip apidoc
+This is not currently externally documented because we don't want people to use
+it for now.  XXX Perhaps that is too paranoid, and it should be documented?
+
+=for apidoc bytes_from_utf8_loc
 
 Like C<L</bytes_from_utf8>()>, but takes an extra parameter, a pointer to where
 to store the location of the first character in C<"s"> that cannot be
@@ -2698,7 +2716,7 @@ Perl_bytes_to_utf8(pTHX_ const U8 *s, STRLEN *lenp)
  * Do not use in-place.  We optimize for native, for obvious reasons. */
 
 U8*
-Perl_utf16_to_utf8(pTHX_ U8* p, U8* d, I32 bytelen, I32 *newlen)
+Perl_utf16_to_utf8(pTHX_ U8* p, U8* d, Size_t bytelen, Size_t *newlen)
 {
     U8* pend;
     U8* dstart = d;
@@ -2732,16 +2750,16 @@ Perl_utf16_to_utf8(pTHX_ U8* p, U8* d, I32 bytelen, I32 *newlen)
 
         /* This assumes that most uses will be in the first Unicode plane, not
          * needing surrogates */
-       if (UNLIKELY(uv >= UNICODE_SURROGATE_FIRST
-                  && uv <= UNICODE_SURROGATE_LAST))
+       if (UNLIKELY(inRANGE(uv, UNICODE_SURROGATE_FIRST,
+                                 UNICODE_SURROGATE_LAST)))
         {
             if (UNLIKELY(p >= pend) || UNLIKELY(uv > LAST_HIGH_SURROGATE)) {
                 Perl_croak(aTHX_ "Malformed UTF-16 surrogate");
             }
            else {
                UV low = (p[0] << 8) + p[1];
-               if (   UNLIKELY(low < FIRST_LOW_SURROGATE)
-                    || UNLIKELY(low > LAST_LOW_SURROGATE))
+               if (UNLIKELY(! inRANGE(low, FIRST_LOW_SURROGATE,
+                                            LAST_LOW_SURROGATE)))
                 {
                    Perl_croak(aTHX_ "Malformed UTF-16 surrogate");
                 }
@@ -2775,7 +2793,7 @@ Perl_utf16_to_utf8(pTHX_ U8* p, U8* d, I32 bytelen, I32 *newlen)
 /* Note: this one is slightly destructive of the source. */
 
 U8*
-Perl_utf16_to_utf8_reversed(pTHX_ U8* p, U8* d, I32 bytelen, I32 *newlen)
+Perl_utf16_to_utf8_reversed(pTHX_ U8* p, U8* d, Size_t bytelen, Size_t *newlen)
 {
     U8* s = (U8*)p;
     U8* const send = s + bytelen;
@@ -3192,6 +3210,7 @@ S_warn_on_first_deprecated_use(pTHX_ const char * const name,
 bool
 Perl__is_utf8_FOO(pTHX_ const U8 classnum, const U8 *p, const U8 * const e)
 {
+    dVAR;
     PERL_ARGS_ASSERT__IS_UTF8_FOO;
 
     return is_utf8_common(p, e, PL_XPosix_ptrs[classnum]);
@@ -3200,6 +3219,7 @@ Perl__is_utf8_FOO(pTHX_ const U8 classnum, const U8 *p, const U8 * const e)
 bool
 Perl__is_utf8_perl_idstart(pTHX_ const U8 *p, const U8 * const e)
 {
+    dVAR;
     PERL_ARGS_ASSERT__IS_UTF8_PERL_IDSTART;
 
     return is_utf8_common(p, e, PL_utf8_perl_idstart);
@@ -3208,6 +3228,7 @@ Perl__is_utf8_perl_idstart(pTHX_ const U8 *p, const U8 * const e)
 bool
 Perl__is_utf8_perl_idcont(pTHX_ const U8 *p, const U8 * const e)
 {
+    dVAR;
     PERL_ARGS_ASSERT__IS_UTF8_PERL_IDCONT;
 
     return is_utf8_common(p, e, PL_utf8_perl_idcont);
@@ -3216,8 +3237,8 @@ Perl__is_utf8_perl_idcont(pTHX_ const U8 *p, const U8 * const e)
 STATIC UV
 S__to_utf8_case(pTHX_ const UV uv1, const U8 *p,
                       U8* ustrp, STRLEN *lenp,
-                      SV *invlist, const int * const invmap,
-                      const unsigned int * const * const aux_tables,
+                      SV *invlist, const I32 * const invmap,
+                      const U32 * const * const aux_tables,
                       const U8 * const aux_table_lengths,
                       const char * const normal)
 {
@@ -3317,8 +3338,6 @@ S__to_utf8_case(pTHX_ const UV uv1, const U8 *p,
                     > HIGHEST_CASE_CHANGING_CP_FOR_USE_ONLY_BY_UTF8_DOT_C))
                 {
 
-                    /* As of Unicode 10.0, this means we avoid swash creation
-                     * for anything beyond high Plane 1 (below emojis)  */
                     goto cases_to_self;
                 }
 #endif
@@ -3331,13 +3350,13 @@ S__to_utf8_case(pTHX_ const UV uv1, const U8 *p,
 
     {
         unsigned int i;
-        const unsigned int * cp_list;
+        const U32 * cp_list;
         U8 * d;
 
         /* 'index' is guaranteed to be non-negative, as this is an inversion
          * map that covers all possible inputs.  See [perl #133365] */
         SSize_t index = _invlist_search(invlist, uv1);
-        IV base = invmap[index];
+        I32 base = invmap[index];
 
         /* The data structures are set up so that if 'base' is non-negative,
          * the case change is 1-to-1; and if 0, the change is to itself */
@@ -3390,8 +3409,8 @@ S__to_utf8_case(pTHX_ const UV uv1, const U8 *p,
 }
 
 Size_t
-Perl__inverse_folds(pTHX_ const UV cp, unsigned int * first_folds_to,
-                          const unsigned int ** remaining_folds_to)
+Perl__inverse_folds(pTHX_ const UV cp, U32 * first_folds_to,
+                          const U32 ** remaining_folds_to)
 {
     /* Returns the count of the number of code points that fold to the input
      * 'cp' (besides itself).
@@ -3409,13 +3428,18 @@ Perl__inverse_folds(pTHX_ const UV cp, unsigned int * first_folds_to,
      * The reason for this convolution is to avoid having to deal with
      * allocating and freeing memory.  The lists are already constructed, so
      * the return can point to them, but single code points aren't, so would
-     * need to be constructed if we didn't employ something like this API */
+     * need to be constructed if we didn't employ something like this API
+     *
+     * The code points returned by this function are all legal Unicode, which
+     * occupy at most 21 bits, and so a U32 is sufficient, and the lists are
+     * constructed with this size (to save space and memory), and we return
+     * pointers, so they must be this size */
 
     dVAR;
     /* 'index' is guaranteed to be non-negative, as this is an inversion map
      * that covers all possible inputs.  See [perl #133365] */
     SSize_t index = _invlist_search(PL_utf8_foldclosures, cp);
-    int base = _Perl_IVCF_invmap[index];
+    I32 base = _Perl_IVCF_invmap[index];
 
     PERL_ARGS_ASSERT__INVERSE_FOLDS;
 
@@ -3439,16 +3463,16 @@ Perl__inverse_folds(pTHX_ const UV cp, unsigned int * first_folds_to,
          * to 'cp', and the parallel array containing the length of the list
          * array */
         *first_folds_to = IVCF_AUX_TABLE_ptrs[-base][0];
-        *remaining_folds_to = IVCF_AUX_TABLE_ptrs[-base] + 1; /* +1 excludes
-                                                                 *first_folds_to
-                                                                */
+        *remaining_folds_to = IVCF_AUX_TABLE_ptrs[-base] + 1;
+                                                /* +1 excludes first_folds_to */
         return IVCF_AUX_TABLE_lengths[-base];
     }
 
 #endif
 
     /* Only the single code point.  This works like 'fc(G) = G - A + a' */
-    *first_folds_to = base + cp - invlist_array(PL_utf8_foldclosures)[index];
+    *first_folds_to = (U32) (base + cp
+                                  - invlist_array(PL_utf8_foldclosures)[index]);
     *remaining_folds_to = NULL;
     return 1;
 }
@@ -3883,8 +3907,8 @@ Perl__to_utf8_fold_flags(pTHX_ const U8 *p,
            /* Look at every character in the result; if any cross the
            * boundary, the whole thing is disallowed */
            U8* s = ustrp;
-           U8* e = ustrp + *lenp;
-           while (s < e) {
+           U8* send = ustrp + *lenp;
+           while (s < send) {
                if (isASCII(*s)) {
                    /* Crossed, have to return the original */
                    original = valid_utf8_to_uvchr(p, lenp);
@@ -3966,694 +3990,6 @@ Perl__to_utf8_fold_flags(pTHX_ const U8 *p,
 
 }
 
-/* Note:
- * Returns a "swash" which is a hash described in utf8.c:Perl_swash_fetch().
- * C<pkg> is a pointer to a package name for SWASHNEW, should be "utf8".
- * For other parameters, see utf8::SWASHNEW in lib/utf8_heavy.pl.
- */
-
-SV*
-Perl_swash_init(pTHX_ const char* pkg, const char* name, SV *listsv,
-                      I32 minbits, I32 none)
-{
-    /* Returns a copy of a swash initiated by the called function.  This is the
-     * public interface, and returning a copy prevents others from doing
-     * mischief on the original.  The only remaining use of this is in tr/// */
-
-    /*NOTE NOTE NOTE - If you want to use "return" in this routine you MUST
-     * use the following define */
-
-#define SWASH_INIT_RETURN(x)   \
-    PL_curpm= old_PL_curpm;         \
-    return newSVsv(x)
-
-    /* Initialize and return a swash, creating it if necessary.  It does this
-     * by calling utf8_heavy.pl in the general case.
-     *
-     * pkg  is the name of the package that <name> should be in.
-     * name is the name of the swash to find.
-     * listsv is a string to initialize the swash with.  It must be of the form
-     *     documented as the subroutine return value in
-     *     L<perlunicode/User-Defined Character Properties>
-     * minbits is the number of bits required to represent each data element.
-     * none I (khw) do not understand this one, but it is used only in tr///.
-     *
-     * Thus there are two possible inputs to find the swash: <name> and
-     * <listsv>.  At least one must be specified.  The result
-     * will be the union of the specified ones, although <listsv>'s various
-     * actions can intersect, etc. what <name> gives.  To avoid going out to
-     * disk at all, <invlist> should specify completely what the swash should
-     * have, and <listsv> should be &PL_sv_undef and <name> should be "".
-     */
-
-    PMOP *old_PL_curpm= PL_curpm; /* save away the old PL_curpm */
-
-    SV* retval = &PL_sv_undef;
-
-    PERL_ARGS_ASSERT_SWASH_INIT;
-
-    assert(listsv != &PL_sv_undef || strNE(name, ""));
-
-    PL_curpm= NULL; /* reset PL_curpm so that we dont get confused between the
-                       regex that triggered the swash init and the swash init
-                       perl logic itself.  See perl #122747 */
-
-    /* If data was passed in to go out to utf8_heavy to find the swash of, do
-     * so */
-    if (listsv != &PL_sv_undef || strNE(name, "")) {
-       dSP;
-       const size_t pkg_len = strlen(pkg);
-       const size_t name_len = strlen(name);
-       HV * const stash = gv_stashpvn(pkg, pkg_len, 0);
-       SV* errsv_save;
-       GV *method;
-
-
-       PUSHSTACKi(PERLSI_MAGIC);
-       ENTER;
-       SAVEHINTS();
-       save_re_context();
-       /* We might get here via a subroutine signature which uses a utf8
-        * parameter name, at which point PL_subname will have been set
-        * but not yet used. */
-       save_item(PL_subname);
-       if (PL_parser && PL_parser->error_count)
-           SAVEI8(PL_parser->error_count), PL_parser->error_count = 0;
-       method = gv_fetchmeth(stash, "SWASHNEW", 8, -1);
-       if (!method) {  /* demand load UTF-8 */
-           ENTER;
-           if ((errsv_save = GvSV(PL_errgv))) SAVEFREESV(errsv_save);
-           GvSV(PL_errgv) = NULL;
-#ifndef NO_TAINT_SUPPORT
-           /* 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(TAINT_get);
-           TAINT_NOT;
-#endif
-            require_pv("utf8_heavy.pl");
-           {
-               /* Not ERRSV, as there is no need to vivify a scalar we are
-                  about to discard. */
-               SV * const errsv = GvSV(PL_errgv);
-               if (!SvTRUE(errsv)) {
-                   GvSV(PL_errgv) = SvREFCNT_inc_simple(errsv_save);
-                   SvREFCNT_dec(errsv);
-               }
-           }
-           LEAVE;
-       }
-       SPAGAIN;
-       PUSHMARK(SP);
-       EXTEND(SP,5);
-       mPUSHp(pkg, pkg_len);
-       mPUSHp(name, name_len);
-       PUSHs(listsv);
-       mPUSHi(minbits);
-       mPUSHi(none);
-       PUTBACK;
-       if ((errsv_save = GvSV(PL_errgv))) SAVEFREESV(errsv_save);
-       GvSV(PL_errgv) = NULL;
-       /* If we already have a pointer to the method, no need to use
-        * call_method() to repeat the lookup.  */
-       if (method
-            ? call_sv(MUTABLE_SV(method), G_SCALAR)
-           : call_sv(newSVpvs_flags("SWASHNEW", SVs_TEMP), G_SCALAR | G_METHOD))
-       {
-           retval = *PL_stack_sp--;
-           SvREFCNT_inc(retval);
-       }
-       {
-           /* Not ERRSV.  See above. */
-           SV * const errsv = GvSV(PL_errgv);
-           if (!SvTRUE(errsv)) {
-               GvSV(PL_errgv) = SvREFCNT_inc_simple(errsv_save);
-               SvREFCNT_dec(errsv);
-           }
-       }
-       LEAVE;
-       POPSTACK;
-       if (IN_PERL_COMPILETIME) {
-           CopHINTS_set(PL_curcop, PL_hints);
-       }
-    } /* End of calling the module to find the swash */
-
-    SWASH_INIT_RETURN(retval);
-#undef SWASH_INIT_RETURN
-}
-
-
-/* This API is wrong for special case conversions since we may need to
- * return several Unicode characters for a single Unicode character
- * (see lib/unicore/SpecCase.txt) The SWASHGET in lib/utf8_heavy.pl is
- * the lower-level routine, and it is similarly broken for returning
- * multiple values.  --jhi
- * For those, you should use S__to_utf8_case() instead */
-/* Now SWASHGET is recasted into S_swatch_get in this file. */
-
-/* Note:
- * Returns the value of property/mapping C<swash> for the first character
- * of the string C<ptr>. If C<do_utf8> is true, the string C<ptr> is
- * assumed to be in well-formed UTF-8. If C<do_utf8> is false, the string C<ptr>
- * is assumed to be in native 8-bit encoding. Caches the swatch in C<swash>.
- *
- * A "swash" is a hash which contains initially the keys/values set up by
- * SWASHNEW.  The purpose is to be able to completely represent a Unicode
- * property for all possible code points.  Things are stored in a compact form
- * (see utf8_heavy.pl) so that calculation is required to find the actual
- * property value for a given code point.  As code points are looked up, new
- * key/value pairs are added to the hash, so that the calculation doesn't have
- * to ever be re-done.  Further, each calculation is done, not just for the
- * desired one, but for a whole block of code points adjacent to that one.
- * For binary properties on ASCII machines, the block is usually for 64 code
- * points, starting with a code point evenly divisible by 64.  Thus if the
- * property value for code point 257 is requested, the code goes out and
- * calculates the property values for all 64 code points between 256 and 319,
- * and stores these as a single 64-bit long bit vector, called a "swatch",
- * under the key for code point 256.  The key is the UTF-8 encoding for code
- * point 256, minus the final byte.  Thus, if the length of the UTF-8 encoding
- * for a code point is 13 bytes, the key will be 12 bytes long.  If the value
- * for code point 258 is then requested, this code realizes that it would be
- * stored under the key for 256, and would find that value and extract the
- * relevant bit, offset from 256.
- *
- * Non-binary properties are stored in as many bits as necessary to represent
- * their values (32 currently, though the code is more general than that), not
- * as single bits, but the principle is the same: the value for each key is a
- * vector that encompasses the property values for all code points whose UTF-8
- * representations are represented by the key.  That is, for all code points
- * whose UTF-8 representations are length N bytes, and the key is the first N-1
- * bytes of that.
- */
-UV
-Perl_swash_fetch(pTHX_ SV *swash, const U8 *ptr, bool do_utf8)
-{
-    HV *const hv = MUTABLE_HV(SvRV(swash));
-    U32 klen;
-    U32 off;
-    STRLEN slen = 0;
-    STRLEN needents;
-    const U8 *tmps = NULL;
-    SV *swatch;
-    const U8 c = *ptr;
-
-    PERL_ARGS_ASSERT_SWASH_FETCH;
-
-    /* If it really isn't a hash, it isn't really swash; must be an inversion
-     * list */
-    if (SvTYPE(hv) != SVt_PVHV) {
-        return _invlist_contains_cp((SV*)hv,
-                                    (do_utf8)
-                                     ? valid_utf8_to_uvchr(ptr, NULL)
-                                     : c);
-    }
-
-    /* We store the values in a "swatch" which is a vec() value in a swash
-     * hash.  Code points 0-255 are a single vec() stored with key length
-     * (klen) 0.  All other code points have a UTF-8 representation
-     * 0xAA..0xYY,0xZZ.  A vec() is constructed containing all of them which
-     * share 0xAA..0xYY, which is the key in the hash to that vec.  So the key
-     * length for them is the length of the encoded char - 1.  ptr[klen] is the
-     * final byte in the sequence representing the character */
-    if (!do_utf8 || UTF8_IS_INVARIANT(c)) {
-        klen = 0;
-       needents = 256;
-        off = c;
-    }
-    else if (UTF8_IS_DOWNGRADEABLE_START(c)) {
-        klen = 0;
-       needents = 256;
-        off = EIGHT_BIT_UTF8_TO_NATIVE(c, *(ptr + 1));
-    }
-    else {
-        klen = UTF8SKIP(ptr) - 1;
-
-        /* Each vec() stores 2**UTF_ACCUMULATION_SHIFT values.  The offset into
-         * the vec is the final byte in the sequence.  (In EBCDIC this is
-         * converted to I8 to get consecutive values.)  To help you visualize
-         * all this:
-         *                       Straight 1047   After final byte
-         *             UTF-8      UTF-EBCDIC     I8 transform
-         *  U+0400:  \xD0\x80    \xB8\x41\x41    \xB8\x41\xA0
-         *  U+0401:  \xD0\x81    \xB8\x41\x42    \xB8\x41\xA1
-         *    ...
-         *  U+0409:  \xD0\x89    \xB8\x41\x4A    \xB8\x41\xA9
-         *  U+040A:  \xD0\x8A    \xB8\x41\x51    \xB8\x41\xAA
-         *    ...
-         *  U+0412:  \xD0\x92    \xB8\x41\x59    \xB8\x41\xB2
-         *  U+0413:  \xD0\x93    \xB8\x41\x62    \xB8\x41\xB3
-         *    ...
-         *  U+041B:  \xD0\x9B    \xB8\x41\x6A    \xB8\x41\xBB
-         *  U+041C:  \xD0\x9C    \xB8\x41\x70    \xB8\x41\xBC
-         *    ...
-         *  U+041F:  \xD0\x9F    \xB8\x41\x73    \xB8\x41\xBF
-         *  U+0420:  \xD0\xA0    \xB8\x42\x41    \xB8\x42\x41
-         *
-         * (There are no discontinuities in the elided (...) entries.)
-         * The UTF-8 key for these 33 code points is '\xD0' (which also is the
-         * key for the next 31, up through U+043F, whose UTF-8 final byte is
-         * \xBF).  Thus in UTF-8, each key is for a vec() for 64 code points.
-         * The final UTF-8 byte, which ranges between \x80 and \xBF, is an
-         * index into the vec() swatch (after subtracting 0x80, which we
-         * actually do with an '&').
-         * In UTF-EBCDIC, each key is for a 32 code point vec().  The first 32
-         * code points above have key '\xB8\x41'. The final UTF-EBCDIC byte has
-         * dicontinuities which go away by transforming it into I8, and we
-         * effectively subtract 0xA0 to get the index. */
-       needents = (1 << UTF_ACCUMULATION_SHIFT);
-       off      = NATIVE_UTF8_TO_I8(ptr[klen]) & UTF_CONTINUATION_MASK;
-    }
-
-    /*
-     * This single-entry cache saves about 1/3 of the UTF-8 overhead in test
-     * suite.  (That is, only 7-8% overall over just a hash cache.  Still,
-     * it's nothing to sniff at.)  Pity we usually come through at least
-     * two function calls to get here...
-     *
-     * NB: this code assumes that swatches are never modified, once generated!
-     */
-
-    if (hv   == PL_last_swash_hv &&
-       klen == PL_last_swash_klen &&
-       (!klen || memEQ((char *)ptr, (char *)PL_last_swash_key, klen)) )
-    {
-       tmps = PL_last_swash_tmps;
-       slen = PL_last_swash_slen;
-    }
-    else {
-       /* Try our second-level swatch cache, kept in a hash. */
-       SV** svp = hv_fetch(hv, (const char*)ptr, klen, FALSE);
-
-       /* If not cached, generate it via swatch_get */
-       if (!svp || !SvPOK(*svp)
-                || !(tmps = (const U8*)SvPV_const(*svp, slen)))
-        {
-            if (klen) {
-                const UV code_point = valid_utf8_to_uvchr(ptr, NULL);
-                swatch = swatch_get(swash,
-                                    code_point & ~((UV)needents - 1),
-                                   needents);
-            }
-            else {  /* For the first 256 code points, the swatch has a key of
-                       length 0 */
-                swatch = swatch_get(swash, 0, needents);
-            }
-
-           if (IN_PERL_COMPILETIME)
-               CopHINTS_set(PL_curcop, PL_hints);
-
-           svp = hv_store(hv, (const char *)ptr, klen, swatch, 0);
-
-           if (!svp || !(tmps = (U8*)SvPV(*svp, slen))
-                    || (slen << 3) < needents)
-               Perl_croak(aTHX_ "panic: swash_fetch got improper swatch, "
-                          "svp=%p, tmps=%p, slen=%" UVuf ", needents=%" UVuf,
-                          svp, tmps, (UV)slen, (UV)needents);
-       }
-
-       PL_last_swash_hv = hv;
-       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;
-       if (klen)
-           Copy(ptr, PL_last_swash_key, klen, U8);
-    }
-
-    switch ((int)((slen << 3) / needents)) {
-    case 1:
-       return ((UV) tmps[off >> 3] & (1 << (off & 7))) != 0;
-    case 8:
-       return ((UV) tmps[off]);
-    case 16:
-       off <<= 1;
-       return
-            ((UV) tmps[off    ] << 8) +
-            ((UV) tmps[off + 1]);
-    case 32:
-       off <<= 2;
-       return
-            ((UV) tmps[off    ] << 24) +
-            ((UV) tmps[off + 1] << 16) +
-            ((UV) tmps[off + 2] <<  8) +
-            ((UV) tmps[off + 3]);
-    }
-    Perl_croak(aTHX_ "panic: swash_fetch got swatch of unexpected bit width, "
-              "slen=%" UVuf ", needents=%" UVuf, (UV)slen, (UV)needents);
-    NORETURN_FUNCTION_END;
-}
-
-/* Read a single line of the main body of the swash input text.  These are of
- * the form:
- * 0053        0056    0073
- * where each number is hex.  The first two numbers form the minimum and
- * maximum of a range, and the third is the value associated with the range.
- * Not all swashes should have a third number
- *
- * On input: l   points to the beginning of the line to be examined; it points
- *               to somewhere in the string of the whole input text, and is
- *               terminated by a \n or the null string terminator.
- *          lend   points to the null terminator of that string
- *          wants_value    is non-zero if the swash expects a third number
- *          typestr is the name of the swash's mapping, like 'ToLower'
- * On output: *min, *max, and *val are set to the values read from the line.
- *           returns a pointer just beyond the line examined.  If there was no
- *           valid min number on the line, returns lend+1
- */
-
-STATIC U8*
-S_swash_scan_list_line(pTHX_ U8* l, U8* const lend, UV* min, UV* max, UV* val,
-                            const bool wants_value, const U8* const typestr)
-{
-    const int  typeto  = typestr[0] == 'T' && typestr[1] == 'o';
-    STRLEN numlen;         /* Length of the number */
-    I32 flags = PERL_SCAN_SILENT_ILLDIGIT
-               | PERL_SCAN_DISALLOW_PREFIX
-               | PERL_SCAN_SILENT_NON_PORTABLE;
-
-    /* nl points to the next \n in the scan */
-    U8* const nl = (U8*)memchr(l, '\n', lend - l);
-
-    PERL_ARGS_ASSERT_SWASH_SCAN_LIST_LINE;
-
-    /* Get the first number on the line: the range minimum */
-    numlen = lend - l;
-    *min = grok_hex((char *)l, &numlen, &flags, NULL);
-    *max = *min;    /* So can never return without setting max */
-    if (numlen)            /* If found a hex number, position past it */
-       l += numlen;
-    else if (nl) {         /* Else, go handle next line, if any */
-       return nl + 1;  /* 1 is length of "\n" */
-    }
-    else {             /* Else, no next line */
-       return lend + 1;        /* to LIST's end at which \n is not found */
-    }
-
-    /* The max range value follows, separated by a BLANK */
-    if (isBLANK(*l)) {
-       ++l;
-       flags = PERL_SCAN_SILENT_ILLDIGIT
-               | PERL_SCAN_DISALLOW_PREFIX
-               | PERL_SCAN_SILENT_NON_PORTABLE;
-       numlen = lend - l;
-       *max = grok_hex((char *)l, &numlen, &flags, NULL);
-       if (numlen)
-           l += numlen;
-       else    /* If no value here, it is a single element range */
-           *max = *min;
-
-       /* Non-binary tables have a third entry: what the first element of the
-        * range maps to.  The map for those currently read here is in hex */
-       if (wants_value) {
-           if (isBLANK(*l)) {
-               ++l;
-                flags = PERL_SCAN_SILENT_ILLDIGIT
-                    | PERL_SCAN_DISALLOW_PREFIX
-                    | PERL_SCAN_SILENT_NON_PORTABLE;
-                numlen = lend - l;
-                *val = grok_hex((char *)l, &numlen, &flags, NULL);
-                if (numlen)
-                    l += numlen;
-                else
-                    *val = 0;
-           }
-           else {
-               *val = 0;
-               if (typeto) {
-                   /* diag_listed_as: To%s: illegal mapping '%s' */
-                   Perl_croak(aTHX_ "%s: illegal mapping '%s'",
-                                    typestr, l);
-               }
-           }
-       }
-       else
-           *val = 0; /* bits == 1, then any val should be ignored */
-    }
-    else { /* Nothing following range min, should be single element with no
-             mapping expected */
-       if (wants_value) {
-           *val = 0;
-           if (typeto) {
-               /* diag_listed_as: To%s: illegal mapping '%s' */
-               Perl_croak(aTHX_ "%s: illegal mapping '%s'", typestr, l);
-           }
-       }
-       else
-           *val = 0; /* bits == 1, then val should be ignored */
-    }
-
-    /* Position to next line if any, or EOF */
-    if (nl)
-       l = nl + 1;
-    else
-       l = lend;
-
-    return l;
-}
-
-/* Note:
- * Returns a swatch (a bit vector string) for a code point sequence
- * that starts from the value C<start> and comprises the number C<span>.
- * A C<swash> must be an object created by SWASHNEW (see lib/utf8_heavy.pl).
- * Should be used via swash_fetch, which will cache the swatch in C<swash>.
- */
-STATIC SV*
-S_swatch_get(pTHX_ SV* swash, UV start, UV span)
-{
-    SV *swatch;
-    U8 *l, *lend, *x, *xend, *s;
-    STRLEN lcur, xcur, scur;
-    HV *const hv = MUTABLE_HV(SvRV(swash));
-
-    SV** listsvp = NULL; /* The string containing the main body of the table */
-    SV** extssvp = NULL;
-    U8* typestr = NULL;
-    STRLEN bits = 0;
-    STRLEN octets; /* if bits == 1, then octets == 0 */
-    UV  none;
-    UV  end = start + span;
-
-        SV** const bitssvp = hv_fetchs(hv, "BITS", FALSE);
-        SV** const nonesvp = hv_fetchs(hv, "NONE", FALSE);
-        SV** const typesvp = hv_fetchs(hv, "TYPE", FALSE);
-        extssvp = hv_fetchs(hv, "EXTRAS", FALSE);
-        listsvp = hv_fetchs(hv, "LIST", FALSE);
-
-       bits  = SvUV(*bitssvp);
-       none  = SvUV(*nonesvp);
-       typestr = (U8*)SvPV_nolen(*typesvp);
-    octets = bits >> 3; /* if bits == 1, then octets == 0 */
-
-    PERL_ARGS_ASSERT_SWATCH_GET;
-
-    if (bits != 8 && bits != 16 && bits != 32) {
-       Perl_croak(aTHX_ "panic: swatch_get doesn't expect bits %" UVuf,
-                                                (UV)bits);
-    }
-
-    /* If overflowed, use the max possible */
-    if (end < start) {
-       end = UV_MAX;
-       span = end - start;
-    }
-
-    /* create and initialize $swatch */
-    scur   = octets ? (span * octets) : (span + 7) / 8;
-    swatch = newSV(scur);
-    SvPOK_on(swatch);
-    s = (U8*)SvPVX(swatch);
-    if (octets && none) {
-       const U8* const e = s + scur;
-       while (s < e) {
-           if (bits == 8)
-               *s++ = (U8)(none & 0xff);
-           else if (bits == 16) {
-               *s++ = (U8)((none >>  8) & 0xff);
-               *s++ = (U8)( none        & 0xff);
-           }
-           else if (bits == 32) {
-               *s++ = (U8)((none >> 24) & 0xff);
-               *s++ = (U8)((none >> 16) & 0xff);
-               *s++ = (U8)((none >>  8) & 0xff);
-               *s++ = (U8)( none        & 0xff);
-           }
-       }
-       *s = '\0';
-    }
-    else {
-       (void)memzero((U8*)s, scur + 1);
-    }
-    SvCUR_set(swatch, scur);
-    s = (U8*)SvPVX(swatch);
-
-    /* read $swash->{LIST} */
-    l = (U8*)SvPV(*listsvp, lcur);
-    lend = l + lcur;
-    while (l < lend) {
-       UV min = 0, max = 0, val = 0, upper;
-       l = swash_scan_list_line(l, lend, &min, &max, &val,
-                                                        cBOOL(octets), typestr);
-       if (l > lend) {
-           break;
-       }
-
-       /* If looking for something beyond this range, go try the next one */
-       if (max < start)
-           continue;
-
-       /* <end> is generally 1 beyond where we want to set things, but at the
-        * platform's infinity, where we can't go any higher, we want to
-        * include the code point at <end> */
-        upper = (max < end)
-                ? max
-                : (max != UV_MAX || end != UV_MAX)
-                  ? end - 1
-                  : end;
-
-       if (octets) {
-           UV key;
-           if (min < start) {
-               if (!none || val < none) {
-                   val += start - min;
-               }
-               min = start;
-           }
-           for (key = min; key <= upper; key++) {
-               STRLEN offset;
-               /* offset must be non-negative (start <= min <= key < end) */
-               offset = octets * (key - start);
-               if (bits == 8)
-                   s[offset] = (U8)(val & 0xff);
-               else if (bits == 16) {
-                   s[offset    ] = (U8)((val >>  8) & 0xff);
-                   s[offset + 1] = (U8)( val        & 0xff);
-               }
-               else if (bits == 32) {
-                   s[offset    ] = (U8)((val >> 24) & 0xff);
-                   s[offset + 1] = (U8)((val >> 16) & 0xff);
-                   s[offset + 2] = (U8)((val >>  8) & 0xff);
-                   s[offset + 3] = (U8)( val        & 0xff);
-               }
-
-               if (!none || val < none)
-                   ++val;
-           }
-       }
-    } /* while */
-
-    /* read $swash->{EXTRAS} */
-    x = (U8*)SvPV(*extssvp, xcur);
-    xend = x + xcur;
-    while (x < xend) {
-       STRLEN namelen;
-       U8 *namestr;
-       SV** othersvp;
-       HV* otherhv;
-       STRLEN otherbits;
-       SV **otherbitssvp, *other;
-       U8 *s, *o, *nl;
-       STRLEN slen, olen;
-
-       const U8 opc = *x++;
-       if (opc == '\n')
-           continue;
-
-       nl = (U8*)memchr(x, '\n', xend - x);
-
-       if (opc != '-' && opc != '+' && opc != '!' && opc != '&') {
-           if (nl) {
-               x = nl + 1; /* 1 is length of "\n" */
-               continue;
-           }
-           else {
-               x = xend; /* to EXTRAS' end at which \n is not found */
-               break;
-           }
-       }
-
-       namestr = x;
-       if (nl) {
-           namelen = nl - namestr;
-           x = nl + 1;
-       }
-       else {
-           namelen = xend - namestr;
-           x = xend;
-       }
-
-       othersvp = hv_fetch(hv, (char *)namestr, namelen, FALSE);
-       otherhv = MUTABLE_HV(SvRV(*othersvp));
-       otherbitssvp = hv_fetchs(otherhv, "BITS", FALSE);
-       otherbits = (STRLEN)SvUV(*otherbitssvp);
-       if (bits < otherbits)
-           Perl_croak(aTHX_ "panic: swatch_get found swatch size mismatch, "
-                      "bits=%" UVuf ", otherbits=%" UVuf, (UV)bits, (UV)otherbits);
-
-       /* The "other" swatch must be destroyed after. */
-       other = swatch_get(*othersvp, start, span);
-       o = (U8*)SvPV(other, olen);
-
-       if (!olen)
-           Perl_croak(aTHX_ "panic: swatch_get got improper swatch");
-
-       s = (U8*)SvPV(swatch, slen);
-        {
-           STRLEN otheroctets = otherbits >> 3;
-           STRLEN offset = 0;
-           U8* const send = s + slen;
-
-           while (s < send) {
-               UV otherval = 0;
-
-               if (otherbits == 1) {
-                   otherval = (o[offset >> 3] >> (offset & 7)) & 1;
-                   ++offset;
-               }
-               else {
-                   STRLEN vlen = otheroctets;
-                   otherval = *o++;
-                   while (--vlen) {
-                       otherval <<= 8;
-                       otherval |= *o++;
-                   }
-               }
-
-               if (opc == '+' && otherval)
-                   NOOP;   /* replace with otherval */
-               else if (opc == '!' && !otherval)
-                   otherval = 1;
-               else if (opc == '-' && otherval)
-                   otherval = 0;
-               else if (opc == '&' && !otherval)
-                   otherval = 0;
-               else {
-                   s += octets; /* no replacement */
-                   continue;
-               }
-
-               if (bits == 8)
-                   *s++ = (U8)( otherval & 0xff);
-               else if (bits == 16) {
-                   *s++ = (U8)((otherval >>  8) & 0xff);
-                   *s++ = (U8)( otherval        & 0xff);
-               }
-               else if (bits == 32) {
-                   *s++ = (U8)((otherval >> 24) & 0xff);
-                   *s++ = (U8)((otherval >> 16) & 0xff);
-                   *s++ = (U8)((otherval >>  8) & 0xff);
-                   *s++ = (U8)( otherval        & 0xff);
-               }
-            }
-       }
-       sv_free(other); /* through with it! */
-    } /* while */
-    return swatch;
-}
-
 bool
 Perl_check_utf8_print(pTHX_ const U8* s, const STRLEN len)
 {