This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
handy.h: Remove extraneous parens
[perl5.git] / handy.h
diff --git a/handy.h b/handy.h
index 10f483a..6d9f858 100644 (file)
--- a/handy.h
+++ b/handy.h
@@ -112,11 +112,10 @@ Null SV pointer. (No longer available when C<PERL_CORE> is defined.)
 # define HAS_BOOL 1
 #endif
 
-/* a simple (bool) cast may not do the right thing: if bool is defined
- * as char for example, then the cast from int is implementation-defined
- * (bool)!!(cbool) in a ternary triggers a bug in xlc on AIX
- */
-
+/* cast-to-bool.  A simple (bool) cast may not do the right thing: if bool is
+ * defined as char for example, then the cast from int is
+ * implementation-defined (bool)!!(cbool) in a ternary triggers a bug in xlc on
+ * AIX */
 #define cBOOL(cbool) ((cbool) ? (bool)1 : (bool)0)
 
 /* Try to figure out __func__ or __FUNCTION__ equivalent, if any.
@@ -484,34 +483,30 @@ with C<LC> in the name are affected by the current locale.
 
 The base function, e.g., C<isALPHA()>, takes an octet (either a C<char> or a
 C<U8>) as input and returns a boolean as to whether or not the character
-represented by that octet is in the named class based on platform, Unicode, and
-Perl rules.  If the input is a number that doesn't fit in an octet, FALSE is
-always returned.
-
-Variant C<isFOO_A> (e.g., C<isALPHA_A()>) will return TRUE only if the input is
-also in the ASCII character set.  For ASCII platforms, the base function with
-no suffix and the one with the C<_A> suffix are identical.  On EBCDIC
-platforms, the C<_A> suffix function will not return true unless the specified
-character also has an ASCII equivalent.
-
-Variant C<isFOO_L1> operates on the full Latin1 character set.  For EBCDIC
-platforms, the base function with no suffix and the one with the C<_L1> suffix
-are identical.  For ASCII platforms, the C<_L1> suffix imposes the Latin-1
-character set onto the platform.  That is, the code points that are ASCII are
-unaffected, since ASCII is a subset of Latin-1.  But the non-ASCII code points
-are treated as if they are Latin-1 characters.  For example, C<isSPACE_L1()>
-will return true when called with the code point 0xA0, which is the Latin-1
-NO-BREAK SPACE.
+represented by that octet is (or on non-ASCII platforms, corresponds to) an
+ASCII character in the named class based on platform, Unicode, and Perl rules.
+If the input is a number that doesn't fit in an octet, FALSE is returned.
+
+Variant C<isFOO_A> (e.g., C<isALPHA_A()>) is identical to the base function
+with no suffix C<"_A">.
+
+Variant C<isFOO_L1> imposes the Latin-1 (or EBCDIC equivlalent) character set
+onto the platform.  That is, the code points that are ASCII are unaffected,
+since ASCII is a subset of Latin-1.  But the non-ASCII code points are treated
+as if they are Latin-1 characters.  For example, C<isWORDCHAR_L1()> will return
+true when called with the code point 0xDF, which is a word character in both
+ASCII and EBCDIC (though it represent different characters in each).
 
 Variant C<isFOO_uni> is like the C<isFOO_L1> variant, but accepts any UV code
 point as input.  If the code point is larger than 255, Unicode rules are used
 to determine if it is in the character class.  For example,
-C<isWORDCHAR(0x100)> returns TRUE, since 0x100 is LATIN CAPITAL LETTER A WITH
-MACRON in Unicode, and is a word character.
+C<isWORDCHAR_uni(0x100)> returns TRUE, since 0x100 is LATIN CAPITAL LETTER A
+WITH MACRON in Unicode, and is a word character.
 
 Variant C<isFOO_utf8> is like C<isFOO_uni>, but the input is a pointer to a
 (known to be well-formed) UTF-8 encoded string (C<U8*> or C<char*>).  The
-classification of just the first character in the string is tested.
+classification of just the first (possibly multi-byte) character in the string
+is tested.
 
 Variant C<isFOO_LC> is like the C<isFOO_A> and C<isFOO_L1> variants, but uses
 the C library function that gives the named classification instead of
@@ -526,29 +521,28 @@ returns the hard-coded, not-affected-by-locale, Unicode results for larger ones.
 
 Variant C<isFOO_LC_utf8> is like C<isFOO_LC_uvchr>, but the input is a pointer to a
 (known to be well-formed) UTF-8 encoded string (C<U8*> or C<char*>).  The
-classification of just the first character in the string is tested.
+classification of just the first (possibly multi-byte) character in the string
+is tested.
 
 =for apidoc Am|bool|isALPHA|char ch
 Returns a boolean indicating whether the specified character is an
-alphabetic character in the platform's native character set, analogous to
-C<m/[[:alpha:]]/>.
+alphabetic character, analogous to C<m/[[:alpha:]]/>.
 See the L<top of this section|/Character classes> for an explanation of variants
-C<isALPHA_A>, C<isALPHA_L1>, C<isALPHA_uni>, C<isALPHA_utf8>, C<isALPHA_LC>
+C<isALPHA_A>, C<isALPHA_L1>, C<isALPHA_uni>, C<isALPHA_utf8>, C<isALPHA_LC>,
 C<isALPHA_LC_uvchr>, and C<isALPHA_LC_utf8>.
 
 =for apidoc Am|bool|isALPHANUMERIC|char ch
 Returns a boolean indicating whether the specified character is a either an
-alphabetic character or decimal digit in the platform's native character set,
-analogous to C<m/[[:alnum:]]/>.
+alphabetic character or decimal digit, analogous to C<m/[[:alnum:]]/>.
 See the L<top of this section|/Character classes> for an explanation of variants
 C<isALPHANUMERIC_A>, C<isALPHANUMERIC_L1>, C<isALPHANUMERIC_uni>,
-C<isALPHANUMERIC_utf8>, C<isALPHANUMERIC_LC> C<isALPHANUMERIC_LC_uvchr>, and
+C<isALPHANUMERIC_utf8>, C<isALPHANUMERIC_LC>, C<isALPHANUMERIC_LC_uvchr>, and
 C<isALPHANUMERIC_LC_utf8>.
 
 =for apidoc Am|bool|isASCII|char ch
 Returns a boolean indicating whether the specified character is one of the 128
 characters in the ASCII character set, analogous to C<m/[[:ascii:]]/>.
-On non-ASCII platforms, it is if this
+On non-ASCII platforms, it returns TRUE iff this
 character corresponds to an ASCII character.  Variants C<isASCII_A()> and
 C<isASCII_L1()> are identical to C<isASCII()>.
 See the L<top of this section|/Character classes> for an explanation of variants
@@ -557,12 +551,17 @@ C<isASCII_LC_utf8>.  Note, however, that some platforms do not have the C
 library routine C<isascii()>.  In these cases, the variants whose names contain
 C<LC> are the same as the corresponding ones without.
 
+Also note, that because all ASCII characters are UTF-8 invariant (meaning they
+have the exact same representation (always a single byte) whether encoded in
+UTF-8 or not), C<isASCII> will give the correct results when called with any
+byte in any string encoded or not in UTF-8.  And similarly C<isASCII_utf8> will
+work properly on any string encoded or not in UTF-8.
+
 =for apidoc Am|bool|isBLANK|char ch
 Returns a boolean indicating whether the specified character is a
-character considered to be a blank in the platform's native character set,
-analogous to C<m/[[:blank:]]/>.
+character considered to be a blank, analogous to C<m/[[:blank:]]/>.
 See the L<top of this section|/Character classes> for an explanation of variants
-C<isBLANK_A>, C<isBLANK_L1>, C<isBLANK_uni>, C<isBLANK_utf8>, C<isBLANK_LC>
+C<isBLANK_A>, C<isBLANK_L1>, C<isBLANK_uni>, C<isBLANK_utf8>, C<isBLANK_LC>,
 C<isBLANK_LC_uvchr>, and C<isBLANK_LC_utf8>.  Note, however, that some
 platforms do not have the C library routine C<isblank()>.  In these cases, the
 variants whose names contain C<LC> are the same as the corresponding ones
@@ -570,74 +569,93 @@ without.
 
 =for apidoc Am|bool|isCNTRL|char ch
 Returns a boolean indicating whether the specified character is a
-control character in the platform's native character set,
-analogous to C<m/[[:cntrl:]]/>.
+control character, analogous to C<m/[[:cntrl:]]/>.
 See the L<top of this section|/Character classes> for an explanation of variants
-C<isCNTRL_A>, C<isCNTRL_L1>, C<isCNTRL_uni>, C<isCNTRL_utf8>, C<isCNTRL_LC>
-C<isCNTRL_LC_uvchr>, and C<isCNTRL_LC_utf8>.
+C<isCNTRL_A>, C<isCNTRL_L1>, C<isCNTRL_uni>, C<isCNTRL_utf8>, C<isCNTRL_LC>,
+C<isCNTRL_LC_uvchr>, and C<isCNTRL_LC_utf8>
+On EBCDIC platforms, you almost always want to use the C<isCNTRL_L1> variant.
 
 =for apidoc Am|bool|isDIGIT|char ch
 Returns a boolean indicating whether the specified character is a
-digit in the platform's native character set, analogous to C<m/[[:digit:]]/>.
+digit, analogous to C<m/[[:digit:]]/>.
 Variants C<isDIGIT_A> and C<isDIGIT_L1> are identical to C<isDIGIT>.
 See the L<top of this section|/Character classes> for an explanation of variants
-C<isDIGIT_uni>, C<isDIGIT_utf8>, C<isDIGIT_LC> C<isDIGIT_LC_uvchr>, and
+C<isDIGIT_uni>, C<isDIGIT_utf8>, C<isDIGIT_LC>, C<isDIGIT_LC_uvchr>, and
 C<isDIGIT_LC_utf8>.
 
 =for apidoc Am|bool|isGRAPH|char ch
 Returns a boolean indicating whether the specified character is a
-graphic character in the platform's native character set, analogous to
-C<m/[[:graph:]]/>.
+graphic character, analogous to C<m/[[:graph:]]/>.
 See the L<top of this section|/Character classes> for an explanation of variants
-C<isGRAPH_A>, C<isGRAPH_L1>, C<isGRAPH_uni>, C<isGRAPH_utf8>, C<isGRAPH_LC>
+C<isGRAPH_A>, C<isGRAPH_L1>, C<isGRAPH_uni>, C<isGRAPH_utf8>, C<isGRAPH_LC>,
 C<isGRAPH_LC_uvchr>, and C<isGRAPH_LC_utf8>.
 
 =for apidoc Am|bool|isLOWER|char ch
 Returns a boolean indicating whether the specified character is a
-lowercase character in the platform's native character set, analogous to
-C<m/[[:lower:]]/>.
+lowercase character, analogous to C<m/[[:lower:]]/>.
 See the L<top of this section|/Character classes> for an explanation of variants
-C<isLOWER_A>, C<isLOWER_L1>, C<isLOWER_uni>, C<isLOWER_utf8>, C<isLOWER_LC>
+C<isLOWER_A>, C<isLOWER_L1>, C<isLOWER_uni>, C<isLOWER_utf8>, C<isLOWER_LC>,
 C<isLOWER_LC_uvchr>, and C<isLOWER_LC_utf8>.
 
 =for apidoc Am|bool|isOCTAL|char ch
 Returns a boolean indicating whether the specified character is an
-octal digit, [0-7] in the platform's native character set.
+octal digit, [0-7].
 The only two variants are C<isOCTAL_A> and C<isOCTAL_L1>; each is identical to
 C<isOCTAL>.
 
 =for apidoc Am|bool|isPUNCT|char ch
 Returns a boolean indicating whether the specified character is a
-punctuation character in the platform's native character set, analogous to
-C<m/[[:punct:]]/>.  Note that the definition of what is punctuation isn't as
+punctuation character, analogous to C<m/[[:punct:]]/>.
+Note that the definition of what is punctuation isn't as
 straightforward as one might desire.  See L<perlrecharclass/POSIX Character
 Classes> for details.
 See the L<top of this section|/Character classes> for an explanation of variants
-C<isPUNCT_A>, C<isPUNCT_L1>, C<isPUNCT_uni>, C<isPUNCT_utf8>, C<isPUNCT_LC>
+C<isPUNCT_A>, C<isPUNCT_L1>, C<isPUNCT_uni>, C<isPUNCT_utf8>, C<isPUNCT_LC>,
 C<isPUNCT_LC_uvchr>, and C<isPUNCT_LC_utf8>.
 
 =for apidoc Am|bool|isSPACE|char ch
 Returns a boolean indicating whether the specified character is a
-whitespace character in the platform's native character set.  This is analogous
-to what C<m/\s/> and C<m/[[:space:]]/> match in a regular expression.
+whitespace character.  This is analogous
+to what C<m/\s/> matches in a regular expression.  Starting in Perl 5.18
+(experimentally), this also matches what C<m/[[:space:]]/> does.
+("Experimentally" means that this change may be backed out in 5.20 or 5.22 if
+field experience indicates that it was unwise.)  Prior to 5.18, only the
+locale forms of this macro (the ones with C<LC> in their names) matched
+precisely what C<m/[[:space:]]/> does.  In those releases, the only difference,
+in the non-locale variants, was that C<isSPACE()> did not match a vertical tab.
+(See L</isPSXSPC> for a macro that matches a vertical tab in all releases.)
 See the L<top of this section|/Character classes> for an explanation of variants
-C<isSPACE_A>, C<isSPACE_L1>, C<isSPACE_uni>, C<isSPACE_utf8>, C<isSPACE_LC>
+C<isSPACE_A>, C<isSPACE_L1>, C<isSPACE_uni>, C<isSPACE_utf8>, C<isSPACE_LC>,
 C<isSPACE_LC_uvchr>, and C<isSPACE_LC_utf8>.
 
+=for apidoc Am|bool|isPSXSPC|char ch
+(short for Posix Space)
+Starting in 5.18, this is identical (experimentally) in all its forms to the
+corresponding C<isSPACE()> macros.  ("Experimentally" means that this change
+may be backed out in 5.20 or 5.22 if field experience indicates that it
+was unwise.)
+The locale forms of this macro are identical to their corresponding
+C<isSPACE()> forms in all Perl releases.  In releases prior to 5.18, the
+non-locale forms differ from their C<isSPACE()> forms only in that the
+C<isSPACE()> forms don't match a Vertical Tab, and the C<isPSXSPC()> forms do.
+Otherwise they are identical.  Thus this macro is analogous to what
+C<m/[[:space:]]/> matches in a regular expression.
+See the L<top of this section|/Character classes> for an explanation of variants
+C<isPSXSPC_A>, C<isPSXSPC_L1>, C<isPSXSPC_uni>, C<isPSXSPC_utf8>, C<isPSXSPC_LC>,
+C<isPSXSPC_LC_uvchr>, and C<isPSXSPC_LC_utf8>.
+
 =for apidoc Am|bool|isUPPER|char ch
 Returns a boolean indicating whether the specified character is an
-uppercase character in the platform's native character set, analogous to
-C<m/[[:upper:]]/>.
+uppercase character, analogous to C<m/[[:upper:]]/>.
 See the L<top of this section|/Character classes> for an explanation of variants
-C<isUPPER_A>, C<isUPPER_L1>, C<isUPPER_uni>, C<isUPPER_utf8>, C<isUPPER_LC>
+C<isUPPER_A>, C<isUPPER_L1>, C<isUPPER_uni>, C<isUPPER_utf8>, C<isUPPER_LC>,
 C<isUPPER_LC_uvchr>, and C<isUPPER_LC_utf8>.
 
 =for apidoc Am|bool|isPRINT|char ch
 Returns a boolean indicating whether the specified character is a
-printable character in the platform's native character set, analogous to
-C<m/[[:print:]]/>.
+printable character, analogous to C<m/[[:print:]]/>.
 See the L<top of this section|/Character classes> for an explanation of variants
-C<isPRINT_A>, C<isPRINT_L1>, C<isPRINT_uni>, C<isPRINT_utf8>, C<isPRINT_LC>
+C<isPRINT_A>, C<isPRINT_L1>, C<isPRINT_uni>, C<isPRINT_utf8>, C<isPRINT_LC>,
 C<isPRINT_LC_uvchr>, and C<isPRINT_LC_utf8>.
 
 =for apidoc Am|bool|isWORDCHAR|char ch
@@ -661,6 +679,25 @@ See the L<top of this section|/Character classes> for an explanation of variants
 C<isXDIGIT_uni>, C<isXDIGIT_utf8>, C<isXDIGIT_LC>, C<isXDIGIT_LC_uvchr>, and
 C<isXDIGIT_LC_utf8>.
 
+=for apidoc Am|bool|isIDFIRST|char ch
+Returns a boolean indicating whether the specified character can be the first
+character of an identifier.  This is very close to, but not quite the same as
+the official Unicode property C<XID_Start>.  The difference is that this
+returns true only if the input character also matches L</isWORDCHAR>.
+See the L<top of this section|/Character classes> for an explanation of variants
+C<isIDFIRST_A>, C<isIDFIRST_L1>, C<isIDFIRST_uni>, C<isIDFIRST_utf8>,
+C<isIDFIRST_LC>, C<isIDFIRST_LC_uvchr>, and C<isIDFIRST_LC_utf8>.
+
+=for apidoc Am|bool|isIDCONT|char ch
+Returns a boolean indicating whether the specified character can be the
+second or succeeding character of an identifier.  This is very close to, but
+not quite the same as the official Unicode property C<XID_Continue>.  The
+difference is that this returns true only if the input character also matches
+L</isWORDCHAR>.  See the L<top of this section|/Character classes> for an
+explanation of variants C<isIDCONT_A>, C<isIDCONT_L1>, C<isIDCONT_uni>,
+C<isIDCONT_utf8>, C<isIDCONT_LC>, C<isIDCONT_LC_uvchr>, and
+C<isIDCONT_LC_utf8>.
+
 =head1 Miscellaneous Functions
 
 =for apidoc Am|U8|READ_XDIGIT|char str*
@@ -669,18 +706,125 @@ Behaviour is only well defined when isXDIGIT(*str) is true.
 
 =head1 Character case changing
 
-=for apidoc Am|char|toUPPER|char ch
-Converts the specified character to uppercase in the platform's native
-character set, if possible; otherwise returns the input character itself.
+=for apidoc Am|U8|toUPPER|U8 ch
+Converts the specified character to uppercase.  If the input is anything but an
+ASCII lowercase character, that input character itself is returned.  Variant
+C<toUPPER_A> is equivalent.
+
+=for apidoc Am|UV|toUPPER_uni|UV cp|U8* s|STRLEN* lenp
+Converts the Unicode code point C<cp> to its uppercase version, and
+stores that in UTF-8 in C<s>, and its length in bytes in C<lenp>.  Note
+that the buffer pointed to by C<s> needs to be at least C<UTF8_MAXBYTES_CASE+1>
+bytes since the uppercase version may be longer than the original character.
+
+The first code point of the uppercased version is returned
+(but note, as explained just above, that there may be more.)
+
+=for apidoc Am|UV|toUPPER_utf8|U8* p|U8* s|STRLEN* lenp
+Converts the UTF-8 encoded character at C<p> to its uppercase version, and
+stores that in UTF-8 in C<s>, and its length in bytes in C<lenp>.  Note
+that the buffer pointed to by C<s> needs to be at least C<UTF8_MAXBYTES_CASE+1>
+bytes since the uppercase version may be longer than the original character.
+
+The first code point of the uppercased version is returned
+(but note, as explained just above, that there may be more.)
+
+The input character at C<p> is assumed to be well-formed.
+
+=for apidoc Am|U8|toFOLD|U8 ch
+Converts the specified character to foldcase.  If the input is anything but an
+ASCII uppercase character, that input character itself is returned.  Variant
+C<toFOLD_A> is equivalent.  (There is no equivalent C<to_FOLD_L1> for the full
+Latin1 range, as the full generality of L</toFOLD_uni> is needed there.)
+
+=for apidoc Am|UV|toFOLD_uni|UV cp|U8* s|STRLEN* lenp
+Converts the Unicode code point C<cp> to its foldcase version, and
+stores that in UTF-8 in C<s>, and its length in bytes in C<lenp>.  Note
+that the buffer pointed to by C<s> needs to be at least C<UTF8_MAXBYTES_CASE+1>
+bytes since the foldcase version may be longer than the original character.
+
+The first code point of the foldcased version is returned
+(but note, as explained just above, that there may be more.)
+
+=for apidoc Am|UV|toFOLD_utf8|U8* p|U8* s|STRLEN* lenp
+Converts the UTF-8 encoded character at C<p> to its foldcase version, and
+stores that in UTF-8 in C<s>, and its length in bytes in C<lenp>.  Note
+that the buffer pointed to by C<s> needs to be at least C<UTF8_MAXBYTES_CASE+1>
+bytes since the foldcase version may be longer than the original character.
+
+The first code point of the foldcased version is returned
+(but note, as explained just above, that there may be more.)
+
+The input character at C<p> is assumed to be well-formed.
+
+=for apidoc Am|U8|toLOWER|U8 ch
+Converts the specified character to lowercase.  If the input is anything but an
+ASCII uppercase character, that input character itself is returned.  Variant
+C<toLOWER_A> is equivalent.
+
+=for apidoc Am|U8|toLOWER_L1|U8 ch
+Converts the specified Latin1 character to lowercase.  The results are undefined if
+the input doesn't fit in a byte.
+
+=for apidoc Am|U8|toLOWER_LC|U8 ch
+Converts the specified character to lowercase using the current locale's rules,
+if possible; otherwise returns the input character itself.
+
+=for apidoc Am|UV|toLOWER_uni|UV cp|U8* s|STRLEN* lenp
+Converts the Unicode code point C<cp> to its lowercase version, and
+stores that in UTF-8 in C<s>, and its length in bytes in C<lenp>.  Note
+that the buffer pointed to by C<s> needs to be at least C<UTF8_MAXBYTES_CASE+1>
+bytes since the lowercase version may be longer than the original character.
+
+The first code point of the lowercased version is returned
+(but note, as explained just above, that there may be more.)
+
+=for apidoc Am|UV|toLOWER_utf8|U8* p|U8* s|STRLEN* lenp
+Converts the UTF-8 encoded character at C<p> to its lowercase version, and
+stores that in UTF-8 in C<s>, and its length in bytes in C<lenp>.  Note
+that the buffer pointed to by C<s> needs to be at least C<UTF8_MAXBYTES_CASE+1>
+bytes since the lowercase version may be longer than the original character.
+
+The first code point of the lowercased version is returned
+(but note, as explained just above, that there may be more.)
+
+The input character at C<p> is assumed to be well-formed.
+
+=for apidoc Am|U8|toLOWER_LC|U8 ch
+Converts the specified character to lowercase using the current locale's rules,
+if possible; otherwise returns the input character itself.
+
+=for apidoc Am|U8|toTITLE|U8 ch
+Converts the specified character to titlecase.  If the input is anything but an
+ASCII lowercase character, that input character itself is returned.  Variant
+C<toTITLE_A> is equivalent.  (There is no C<toTITLE_L1> for the full Latin1 range,
+as the full generality of L</toTITLE_uni> is needed there.  Titlecase is not a
+concept used in locale handling, so there is no functionality for that.)
+
+=for apidoc Am|UV|toTITLE_uni|UV cp|U8* s|STRLEN* lenp
+Converts the Unicode code point C<cp> to its titlecase version, and
+stores that in UTF-8 in C<s>, and its length in bytes in C<lenp>.  Note
+that the buffer pointed to by C<s> needs to be at least C<UTF8_MAXBYTES_CASE+1>
+bytes since the titlecase version may be longer than the original character.
+
+The first code point of the titlecased version is returned
+(but note, as explained just above, that there may be more.)
+
+=for apidoc Am|UV|toTITLE_utf8|U8* p|U8* s|STRLEN* lenp
+Converts the UTF-8 encoded character at C<p> to its titlecase version, and
+stores that in UTF-8 in C<s>, and its length in bytes in C<lenp>.  Note
+that the buffer pointed to by C<s> needs to be at least C<UTF8_MAXBYTES_CASE+1>
+bytes since the titlecase version may be longer than the original character.
 
-=for apidoc Am|char|toLOWER|char ch
-Converts the specified character to lowercase in the platform's native
-character set, if possible; otherwise returns the input character itself.
+The first code point of the titlecased version is returned
+(but note, as explained just above, that there may be more.)
+
+The input character at C<p> is assumed to be well-formed.
 
 =cut
 
-Still undocumented are , PSXSPC, VERTSPACE, and IDFIRST, and the other
-toUPPER etc functions
+XXX Still undocumented isVERTWS_uni and _utf8; it's unclear what their names
+really should be.  Also toUPPER_LC and toFOLD_LC, which are subject to change.
 
 Note that these macros are repeated in Devel::PPPort, so should also be
 patched there.  The file as of this writing is cpan/Devel-PPPort/parts/inc/misc
@@ -706,7 +850,15 @@ patched there.  The file as of this writing is cpan/Devel-PPPort/parts/inc/misc
 #define FITS_IN_8_BITS(c) ((sizeof(c) == 1) || !(((WIDEST_UTYPE)(c)) & ~0xFF))
 
 #ifdef EBCDIC
-#   define isASCII(c)    (FITS_IN_8_BITS(c) && (NATIVE_TO_UNI((U8) (c)) < 128))
+#   ifndef _ALL_SOURCE
+        /* This returns the wrong results on at least z/OS unless this is
+         * defined. */
+#       error   _ALL_SOURCE should probably be defined
+#   endif
+
+    /* We could be called without perl.h, in which case NATIVE_TO_ASCII() is
+     * likely not defined, and so we use the native function */
+#   define isASCII(c)    isascii(c)
 #else
 #   define isASCII(c)    ((WIDEST_UTYPE)(c) < 128)
 #endif
@@ -722,11 +874,12 @@ patched there.  The file as of this writing is cpan/Devel-PPPort/parts/inc/misc
 /* ASCII range only */
 #ifdef H_PERL       /* If have access to perl.h, lookup in its table */
 
-/* Character class numbers.  For internal core Perl use only.  These are used
- * in PL_charclass[] and the ones up through the one that corresponds to
- * <_HIGHEST_REGCOMP_DOT_H_SYNC> are used by regcomp.h.  These use names used
- * in l1_char_class_tab.h but their actual definitions are here.  If that file
- * has a name not used here, it won't compile.
+/* Character class numbers.  For internal core Perl use only.  The ones less
+ * than 32 are used in PL_charclass[] and the ones up through the one that
+ * corresponds to <_HIGHEST_REGCOMP_DOT_H_SYNC> are used by regcomp.h and
+ * related files.  PL_charclass ones use names used in l1_char_class_tab.h but
+ * their actual definitions are here.  If that file has a name not used here,
+ * it won't compile.
  *
  * The first group of these is ordered in what I (khw) estimate to be the
  * frequency of their use.  This gives a slight edge to exiting a loop earlier
@@ -740,8 +893,9 @@ patched there.  The file as of this writing is cpan/Devel-PPPort/parts/inc/misc
 #  define _CC_PRINT              6      /* [:print:] */
 #  define _CC_ALPHANUMERIC       7      /* [:alnum:] */
 #  define _CC_GRAPH              8      /* [:graph:] */
+#  define _CC_CASED              9      /* [:lower:] and [:upper:] under /i */
 
-#define _FIRST_NON_SWASH_CC      9
+#define _FIRST_NON_SWASH_CC     10
 /* The character classes above are implemented with swashes.  The second group
  * (just below) contains the ones implemented without.  These are also sorted
  * in rough order of the frequency of their use, except that \v should be last,
@@ -751,62 +905,65 @@ patched there.  The file as of this writing is cpan/Devel-PPPort/parts/inc/misc
  * useful to group these which have no members that match above Latin1, (or
  * above ASCII in the latter case) */
 
-#  define _CC_SPACE              9      /* \s */
-#  define _CC_BLANK             10      /* [:blank:] */
-#  define _CC_XDIGIT            11      /* [:xdigit:] */
-#  define _CC_PSXSPC            12      /* [:space:] */
-#  define _CC_CNTRL             13      /* [:cntrl:] */
-#  define _CC_ASCII             14      /* [:ascii:] */
-#  define _CC_VERTSPACE         15      /* \v */
+#  define _CC_SPACE             10      /* \s */
+#  define _CC_BLANK             11      /* [:blank:] */
+#  define _CC_XDIGIT            12      /* [:xdigit:] */
+#  define _CC_PSXSPC            13      /* [:space:] */
+#  define _CC_CNTRL             14      /* [:cntrl:] */
+#  define _CC_ASCII             15      /* [:ascii:] */
+#  define _CC_VERTSPACE         16      /* \v */
 
 #  define _HIGHEST_REGCOMP_DOT_H_SYNC _CC_VERTSPACE
 
 /* The members of the third group below do not need to be coordinated with data
  * structures in regcomp.[ch] and regexec.c */
-#  define _CC_IDFIRST           16
-#  define _CC_CHARNAME_CONT     17
-#  define _CC_NONLATIN1_FOLD    18
-#  define _CC_QUOTEMETA         19
-#  define _CC_NON_FINAL_FOLD    20
-#  define _CC_IS_IN_SOME_FOLD   21
-/* Unused: 22-31
+#  define _CC_IDFIRST           17
+#  define _CC_CHARNAME_CONT     18
+#  define _CC_NONLATIN1_FOLD    19
+#  define _CC_QUOTEMETA         20
+#  define _CC_NON_FINAL_FOLD    21
+#  define _CC_IS_IN_SOME_FOLD   22
+#  define _CC_BACKSLASH_FOO_LBRACE_IS_META 31 /* temp, see mk_PL_charclass.pl */
+/* Unused: 23-30
  * If more bits are needed, one could add a second word for non-64bit
  * QUAD_IS_INT systems, using some #ifdefs to distinguish between having a 2nd
  * word or not.  The IS_IN_SOME_FOLD bit is the most easily expendable, as it
  * is used only for optimization (as of this writing), and differs in the
  * Latin1 range from the ALPHA bit only in two relatively unimportant
- * characters: the masculine and feminine ordinal indicators */
+ * characters: the masculine and feminine ordinal indicators, so removing it
+ * would just cause /i regexes which match them to run less efficiently */
 
 #if defined(PERL_CORE) || defined(PERL_EXT)
 /* An enum version of the character class numbers, to help compilers
  * optimize */
 typedef enum {
-    _CC_ENUM_ALPHANUMERIC   = _CC_ALPHANUMERIC,
     _CC_ENUM_ALPHA          = _CC_ALPHA,
+    _CC_ENUM_ALPHANUMERIC   = _CC_ALPHANUMERIC,
+    _CC_ENUM_ASCII          = _CC_ASCII,
+    _CC_ENUM_BLANK          = _CC_BLANK,
+    _CC_ENUM_CASED          = _CC_CASED,
+    _CC_ENUM_CNTRL          = _CC_CNTRL,
     _CC_ENUM_DIGIT          = _CC_DIGIT,
     _CC_ENUM_GRAPH          = _CC_GRAPH,
     _CC_ENUM_LOWER          = _CC_LOWER,
     _CC_ENUM_PRINT          = _CC_PRINT,
+    _CC_ENUM_PSXSPC         = _CC_PSXSPC,
     _CC_ENUM_PUNCT          = _CC_PUNCT,
+    _CC_ENUM_SPACE          = _CC_SPACE,
     _CC_ENUM_UPPER          = _CC_UPPER,
+    _CC_ENUM_VERTSPACE      = _CC_VERTSPACE,
     _CC_ENUM_WORDCHAR       = _CC_WORDCHAR,
-    _CC_ENUM_SPACE          = _CC_SPACE,
-    _CC_ENUM_BLANK          = _CC_BLANK,
-    _CC_ENUM_XDIGIT         = _CC_XDIGIT,
-    _CC_ENUM_CNTRL          = _CC_CNTRL,
-    _CC_ENUM_PSXSPC         = _CC_PSXSPC,
-    _CC_ENUM_ASCII          = _CC_ASCII,
-    _CC_ENUM_VERTSPACE      = _CC_VERTSPACE
+    _CC_ENUM_XDIGIT         = _CC_XDIGIT
 } _char_class_number;
 #endif
 
 #define POSIX_SWASH_COUNT _FIRST_NON_SWASH_CC
 #define POSIX_CC_COUNT    (_HIGHEST_REGCOMP_DOT_H_SYNC + 1)
 
-#if defined(PERL_IN_UTF8_C) || defined(PERL_IN_REGCOMP_C)
+#if defined(PERL_IN_UTF8_C) || defined(PERL_IN_REGCOMP_C) || defined(PERL_IN_REGEXEC_C)
 #   if _CC_WORDCHAR != 0 || _CC_DIGIT != 1 || _CC_ALPHA != 2 || _CC_LOWER != 3 \
-       || _CC_UPPER != 4 || _CC_PUNCT != 5 || _CC_PRINT != 6 \
-       || _CC_ALPHANUMERIC != 7 || _CC_GRAPH != 8
+       || _CC_UPPER != 4 || _CC_PUNCT != 5 || _CC_PRINT != 6                   \
+       || _CC_ALPHANUMERIC != 7 || _CC_GRAPH != 8 || _CC_CASED != 9
       #error Need to adjust order of swash_property_names[]
 #   endif
 
@@ -823,20 +980,11 @@ static const char* const swash_property_names[] = {
     "XPosixPunct",
     "XPosixPrint",
     "XPosixAlnum",
-    "XPosixGraph"
+    "XPosixGraph",
+    "Cased"
 };
 #endif
 
-#define PL_utf8_alnum   PL_utf8_swash_ptrs[_CC_WORDCHAR]
-#define PL_utf8_alnumc PL_utf8_swash_ptrs[_CC_ALPHANUMERIC]
-#define PL_utf8_alpha  PL_utf8_swash_ptrs[_CC_ALPHA]
-#define PL_utf8_graph  PL_utf8_swash_ptrs[_CC_GRAPH]
-#define PL_utf8_digit  PL_utf8_swash_ptrs[_CC_DIGIT]
-#define PL_utf8_upper  PL_utf8_swash_ptrs[_CC_UPPER]
-#define PL_utf8_lower  PL_utf8_swash_ptrs[_CC_LOWER]
-#define PL_utf8_print  PL_utf8_swash_ptrs[_CC_PRINT]
-#define PL_utf8_punct  PL_utf8_swash_ptrs[_CC_PUNCT]
-
 #  ifdef DOINIT
 EXTCONST  U32 PL_charclass[] = {
 #    include "l1_char_class_tab.h"
@@ -849,7 +997,7 @@ EXTCONST U32 PL_charclass[];
     /* The 1U keeps Solaris from griping when shifting sets the uppermost bit */
 #   define _CC_mask(classnum) (1U << (classnum))
 #   define _generic_isCC(c, classnum) cBOOL(FITS_IN_8_BITS(c) \
-                && (PL_charclass[(U8) NATIVE_TO_UNI(c)] & _CC_mask(classnum)))
+                && (PL_charclass[(U8) (c)] & _CC_mask(classnum)))
 
     /* The mask for the _A versions of the macros; it just adds in the bit for
      * ASCII. */
@@ -858,7 +1006,7 @@ EXTCONST U32 PL_charclass[];
     /* The _A version makes sure that both the desired bit and the ASCII bit
      * are present */
 #   define _generic_isCC_A(c, classnum) (FITS_IN_8_BITS(c) \
-        && ((PL_charclass[(U8) NATIVE_TO_UNI(c)] & _CC_mask_A(classnum)) \
+        && ((PL_charclass[(U8) (c)] & _CC_mask_A(classnum)) \
                                 == _CC_mask_A(classnum)))
 
 #   define isALPHA_A(c)  _generic_isCC_A(c, _CC_ALPHA)
@@ -875,11 +1023,11 @@ EXTCONST U32 PL_charclass[];
 #   define isUPPER_A(c)  _generic_isCC_A(c, _CC_UPPER)
 #   define isWORDCHAR_A(c) _generic_isCC_A(c, _CC_WORDCHAR)
 #   define isXDIGIT_A(c)  _generic_isCC(c, _CC_XDIGIT)
-#   define isIDFIRST_A(c) _generic_isCC_A(c, ( _CC_IDFIRST))
+#   define isIDFIRST_A(c) _generic_isCC_A(c, _CC_IDFIRST)
 
     /* Either participates in a fold with a character above 255, or is a
      * multi-char fold */
-#   define _HAS_NONLATIN1_FOLD_CLOSURE_ONLY_FOR_USE_BY_REGCOMP_DOT_C_AND_REGEXEC_DOT_C(c) ((! cBOOL(FITS_IN_8_BITS(c))) || (PL_charclass[(U8) NATIVE_TO_UNI(c)] & _CC_mask(_CC_NONLATIN1_FOLD)))
+#   define _HAS_NONLATIN1_FOLD_CLOSURE_ONLY_FOR_USE_BY_REGCOMP_DOT_C_AND_REGEXEC_DOT_C(c) ((! cBOOL(FITS_IN_8_BITS(c))) || (PL_charclass[(U8) (c)] & _CC_mask(_CC_NONLATIN1_FOLD)))
 
 #   define _isQUOTEMETA(c) _generic_isCC(c, _CC_QUOTEMETA)
 #   define _IS_NON_FINAL_FOLD_ONLY_FOR_USE_BY_REGCOMP_DOT_C(c) \
@@ -887,44 +1035,40 @@ EXTCONST U32 PL_charclass[];
 #   define _IS_IN_SOME_FOLD_ONLY_FOR_USE_BY_REGCOMP_DOT_C(c) \
                                             _generic_isCC(c, _CC_IS_IN_SOME_FOLD)
 #else   /* No perl.h. */
+#   define isBLANK_A(c)  ((c) == ' ' || (c) == '\t')
+#   define isIDFIRST_A(c) (isALPHA_A(c) || (c) == '_')
+#   define isWORDCHAR_A(c) (isALPHANUMERIC_A(c) || (c) == '_')
+#   define isPSXSPC_A(c) (isSPACE_A(c) || (c) == '\v')
 #   ifdef EBCDIC
-#       define isALPHA_A(c)    (isASCII(c) && isALPHA(c))
-#       define isALPHANUMERIC_A(c) (isASCII(c) && isALPHANUMERIC(c))
-#       define isBLANK_A(c)    (isASCII(c) && isBLANK(c))
-#       define isCNTRL_A(c)    (isASCII(c) && isCNTRL(c))
-#       define isDIGIT_A(c)    (isASCII(c) && isDIGIT(c))
-#       define isGRAPH_A(c)    (isASCII(c) && isGRAPH(c))
-#       define isIDFIRST_A(c)  (isASCII(c) && isIDFIRST(c))
-#       define isLOWER_A(c)    (isASCII(c) && isLOWER(c))
-#       define isPRINT_A(c)    (isASCII(c) && isPRINT(c))
-#       define isPSXSPC_A(c)   (isASCII(c) && isPSXSPC(c))
-#       define isPUNCT_A(c)    (isASCII(c) && isPUNCT(c))
-#       define isSPACE_A(c)    (isASCII(c) && isSPACE(c))
-#       define isUPPER_A(c)    (isASCII(c) && isUPPER(c))
-#       define isWORDCHAR_A(c) (isASCII(c) && isWORDCHAR(c))
-#       define isXDIGIT_A(c)   (isASCII(c) && isXDIGIT(c))
+        /* We could be called without perl.h, so the native functions are the
+         * easiest to code these in.  They likely will return false for all
+         * non-ASCII values, but this makes sure */
+#       define isALPHA_A(c)    (isASCII(c) && isalpha(c))
+#       define isALPHANUMERIC_A(c) (isASCII(c) && isalnum(c))
+#       define isCNTRL_A(c)    (isASCII(c) && iscntrl(c))
+#       define isDIGIT_A(c)    (isASCII(c) && isdigit(c))
+#       define isGRAPH_A(c)    (isASCII(c) && isgraph(c))
+#       define isLOWER_A(c)    (isASCII(c) && islower(c))
+#       define isPRINT_A(c)    (isASCII(c) && isprint(c))
+#       define isPUNCT_A(c)    (isASCII(c) && ispunct(c))
+#       define isSPACE_A(c)    (isASCII(c) && isspace(c))
+#       define isUPPER_A(c)    (isASCII(c) && isupper(c))
+#       define isXDIGIT_A(c)   (isASCII(c) && isxdigit(c))
 #   else   /* ASCII platform, no perl.h */
 #       define isALPHA_A(c)  (isUPPER_A(c) || isLOWER_A(c))
 #       define isALPHANUMERIC_A(c) (isALPHA_A(c) || isDIGIT_A(c))
-#       define isBLANK_A(c)  ((c) == ' ' || (c) == '\t')
-#       define isCNTRL_A(c) (FITS_IN_8_BITS(c) && ((U8) (c) < ' ' || (c) == 127))
+#       define isCNTRL_A(c)  (isASCII(c) && ! isPRINT_A(c))
 #       define isDIGIT_A(c)  ((c) <= '9' && (c) >= '0')
-#       define isGRAPH_A(c)  (isWORDCHAR_A(c) || isPUNCT_A(c))
-#       define isIDFIRST_A(c) (isALPHA_A(c) || (c) == '_')
+#       define isGRAPH_A(c)  (isPRINT_A(c) && (c) ! = ' ')
 #       define isLOWER_A(c)  ((c) >= 'a' && (c) <= 'z')
 #       define isPRINT_A(c)  (((c) >= 32 && (c) < 127))
-#       define isPSXSPC_A(c) (isSPACE_A(c) || (c) == '\v')
-#       define isPUNCT_A(c)  (((c) >= 33 && (c) <= 47)              \
-                              || ((c) >= 58 && (c) <= 64)           \
-                              || ((c) >= 91 && (c) <= 96)           \
-                              || ((c) >= 123 && (c) <= 126))
+#       define isPUNCT_A(c)  (isGRAPH_A(c) && ! isALPHANUMERIC(c))
 #       define isSPACE_A(c)  ((c) == ' '                            \
                               || (c) == '\t'                        \
                               || (c) == '\n'                        \
                               || (c) =='\r'                         \
                               || (c) == '\f')
 #       define isUPPER_A(c)  ((c) <= 'Z' && (c) >= 'A')
-#       define isWORDCHAR_A(c) (isALPHA_A(c) || isDIGIT_A(c) || (c) == '_')
 #       define isXDIGIT_A(c)   (isDIGIT_A(c)                        \
                                 || ((c) >= 'a' && (c) <= 'f')       \
                                 || ((c) <= 'F' && (c) >= 'A'))
@@ -954,87 +1098,70 @@ EXTCONST U32 PL_charclass[];
        * for backwards compatibility */
     /* ALPHAU includes Unicode semantics for latin1 characters.  It has an extra
      * >= AA test to speed up ASCII-only tests at the expense of the others */
-#   define isALPHA_L1(c) (isALPHA(c) || (NATIVE_TO_UNI((U8) c) >= 0xAA \
-       && ((NATIVE_TO_UNI((U8) c) >= 0xC0 \
-             && NATIVE_TO_UNI((U8) c) != 0xD7 && NATIVE_TO_UNI((U8) c) != 0xF7) \
-           || NATIVE_TO_UNI((U8) c) == 0xAA \
-           || NATIVE_TO_UNI((U8) c) == 0xB5 \
-           || NATIVE_TO_UNI((U8) c) == 0xBA)))
+#   define isALPHA_L1(c) (isALPHA(c) || (NATIVE_TO_LATIN1((U8) c) >= 0xAA \
+       && ((NATIVE_TO_LATIN1((U8) c) >= 0xC0 \
+             && NATIVE_TO_LATIN1((U8) c) != 0xD7 && NATIVE_TO_LATIN1((U8) c) != 0xF7) \
+           || NATIVE_TO_LATIN1((U8) c) == 0xAA \
+           || NATIVE_TO_LATIN1((U8) c) == 0xB5 \
+           || NATIVE_TO_LATIN1((U8) c) == 0xBA)))
 #   define isCHARNAME_CONT(c) (isWORDCHAR_L1(c)                         \
                                || (c) == ' '                            \
                                || (c) == '-'                            \
                                || (c) == '('                            \
                                || (c) == ')'                            \
                                || (c) == ':'                            \
-                               || NATIVE_TO_UNI((U8) c) == 0xA0)
-#endif
-
-/* Macros that differ between EBCDIC and ASCII.  Where C89 defines a function,
- * that is used in the EBCDIC form, because in EBCDIC we do not do locales:
- * therefore can use native functions.  For those where C89 doesn't define a
- * function, use our function, assuming that the EBCDIC code page is isomorphic
- * with Latin1, which the three currently recognized by Perl are.  Some libc's
- * have an isblank(), but it's not guaranteed. */
-#ifdef EBCDIC
-#   define isALPHA(c)  isalpha(c)
-#   define isALPHANUMERIC(c)   isalnum(c)
-#   define isBLANK(c)  ((c) == ' ' || (c) == '\t' || NATIVE_TO_UNI(c) == 0xA0)
-#   define isCNTRL(c)  iscntrl(c)
-#   define isDIGIT(c)  isdigit(c)
-#   define isGRAPH(c)  isgraph(c)
-#   define isIDFIRST(c) (isALPHA(c) || (c) == '_')
-#   define isLOWER(c)  islower(c)
-#   define isPRINT(c)  isprint(c)
-#   define isPSXSPC(c) isspace(c)
-#   define isPUNCT(c)  ispunct(c)
-#   define isSPACE(c)   (isPSXSPC(c) /* && (c) != '\v' (Experimentally making
-                                        these macros identical) */)
-#   define isUPPER(c)  isupper(c)
-#   define isXDIGIT(c) isxdigit(c)
-#   define isWORDCHAR(c) (isalnum(c) || (c) == '_')
-#   define toLOWER(c)  tolower(c)
-#   define toUPPER(c)  toupper(c)
-#else /* Not EBCDIC: ASCII-only matching */
-#   define isALPHANUMERIC(c)  isALPHANUMERIC_A(c)
-#   define isALPHA(c)   isALPHA_A(c)
-#   define isBLANK(c)   isBLANK_A(c)
-#   define isCNTRL(c)   isCNTRL_A(c)
-#   define isDIGIT(c)   isDIGIT_A(c)
-#   define isGRAPH(c)   isGRAPH_A(c)
-#   define isIDFIRST(c) isIDFIRST_A(c)
-#   define isLOWER(c)   isLOWER_A(c)
-#   define isPRINT(c)   isPRINT_A(c)
-#   define isPSXSPC(c) isPSXSPC_A(c)
-#   define isPUNCT(c)   isPUNCT_A(c)
-#   define isSPACE(c)   isSPACE_A(c)
-#   define isUPPER(c)   isUPPER_A(c)
-#   define isWORDCHAR(c) isWORDCHAR_A(c)
-#   define isXDIGIT(c)  isXDIGIT_A(c)
-
-    /* ASCII casing.  These could also be written as
-       #define toLOWER(c) (isASCII(c) ? toLOWER_LATIN1(c) : (c))
-       #define toUPPER(c) (isASCII(c) ? toUPPER_LATIN1_MOD(c) : (c))
-       which uses table lookup and mask instead of subtraction.  (This would
-       work because the _MOD does not apply in the ASCII range) */
-#   define toLOWER(c)  (isUPPER(c) ? (c) + ('a' - 'A') : (c))
-#   define toUPPER(c)  (isLOWER(c) ? (c) - ('a' - 'A') : (c))
+                               || NATIVE_TO_LATIN1((U8) c) == 0xA0)
 #endif
 
+#define isALPHANUMERIC(c)  isALPHANUMERIC_A(c)
+#define isALPHA(c)   isALPHA_A(c)
+#define isBLANK(c)   isBLANK_A(c)
+#define isCNTRL(c)   isCNTRL_A(c)
+#define isDIGIT(c)   isDIGIT_A(c)
+#define isGRAPH(c)   isGRAPH_A(c)
+#define isIDFIRST(c) isIDFIRST_A(c)
+#define isLOWER(c)   isLOWER_A(c)
+#define isPRINT(c)   isPRINT_A(c)
+#define isPSXSPC(c)  isPSXSPC_A(c)
+#define isPUNCT(c)   isPUNCT_A(c)
+#define isSPACE(c)   isSPACE_A(c)
+#define isUPPER(c)   isUPPER_A(c)
+#define isWORDCHAR(c) isWORDCHAR_A(c)
+#define isXDIGIT(c)  isXDIGIT_A(c)
+
+/* ASCII casing.  These could also be written as
+    #define toLOWER(c) (isASCII(c) ? toLOWER_LATIN1(c) : (c))
+    #define toUPPER(c) (isASCII(c) ? toUPPER_LATIN1_MOD(c) : (c))
+   which uses table lookup and mask instead of subtraction.  (This would
+   work because the _MOD does not apply in the ASCII range) */
+#define toLOWER(c)  (isUPPER(c) ? (c) + ('a' - 'A') : (c))
+#define toUPPER(c)  (isLOWER(c) ? (c) - ('a' - 'A') : (c))
+
+/* In the ASCII range, these are equivalent to what they're here defined to be.
+ * But by creating these definitions, other code doesn't have to be aware of
+ * this detail */
+#define toFOLD(c)    toLOWER(c)
+#define toFOLD_LC(c) toLOWER_LC(c)
+#define toTITLE(c)   toUPPER(c)
+
+#define toLOWER_A(c) toLOWER(c)
+#define toUPPER_A(c) toUPPER(c)
+#define toFOLD_A(c)  toFOLD(c)
+#define toTITLE_A(c) toTITLE(c)
 
 /* Use table lookup for speed; return error character for input
  * out-of-range */
-#define toLOWER_LATIN1(c)    (FITS_IN_8_BITS(c)                            \
-                             ? UNI_TO_NATIVE(PL_latin1_lc[                 \
-                                               NATIVE_TO_UNI( (U8) (c)) ]) \
-                             : UNICODE_REPLACEMENT)
+#define toLOWER_LATIN1(c)    ((! FITS_IN_8_BITS(c))                        \
+                             ? (c)                                         \
+                             : PL_latin1_lc[ (U8) (c) ])
+#define toLOWER_L1(c)    toLOWER_LATIN1(c)  /* Synonym for consistency */
+
 /* Modified uc.  Is correct uc except for three non-ascii chars which are
  * all mapped to one of them, and these need special handling; error
  * character for input out-of-range */
-#define toUPPER_LATIN1_MOD(c) (FITS_IN_8_BITS(c)                           \
-                              ? UNI_TO_NATIVE(PL_mod_latin1_uc[            \
-                                               NATIVE_TO_UNI( (U8) (c)) ]) \
-                              : UNICODE_REPLACEMENT)
-
+#define toUPPER_LATIN1_MOD(c) ((! FITS_IN_8_BITS(c))                       \
+                               ? (c)                                       \
+                               : PL_mod_latin1_uc[ (U8) (c) ])
 #ifdef USE_NEXT_CTYPE
 
 #  define isALPHANUMERIC_LC(c) NXIsAlNum((unsigned int)(c))
@@ -1117,40 +1244,45 @@ EXTCONST U32 PL_charclass[];
 #  endif
 #endif /* USE_NEXT_CTYPE */
 
+#define isIDCONT(c)             isWORDCHAR(c)
+#define isIDCONT_A(c)           isWORDCHAR_A(c)
+#define isIDCONT_L1(c)         isWORDCHAR_L1(c)
+#define isIDCONT_LC(c)         isWORDCHAR_LC(c)
 #define isPSXSPC_LC(c)         isSPACE_LC(c)
 
 /* For internal core Perl use only.  If the input is Latin1, use the Latin1
- * macro; otherwise use the function.  Won't compile if 'c' isn't unsigned, as
- * won't match function prototype. The macros do bounds checking, so have
+ * macro; otherwise use the function 'above_latin1'.  Won't compile if 'c' isn't unsigned, as
+ * won't match above_latin1 prototype. The macros do bounds checking, so have
  * duplicate checks here, so could create versions of the macros that don't,
  * but experiments show that gcc optimizes them out anyway. */
 
 /* Note that all ignore 'use bytes' */
-#define _generic_uni(classnum, function, c) ((c) < 256                    \
-                                             ? _generic_isCC(c, classnum) \
-                                             : function(c))
-#define _generic_uni_swash(classnum, c) ((c) < 256                        \
-                                             ? _generic_isCC(c, classnum) \
+#define _generic_uni(classnum, above_latin1, c) ((c) < 256                    \
+                                             ? _generic_isCC(c, classnum)     \
+                                             : above_latin1(c))
+#define _generic_swash_uni(classnum, c) ((c) < 256                            \
+                                             ? _generic_isCC(c, classnum)     \
                                              : _is_uni_FOO(classnum, c))
-#define isALPHA_uni(c)      _generic_uni_swash(_CC_ALPHA, c)
-#define isALPHANUMERIC_uni(c) _generic_uni_swash(_CC_ALPHANUMERIC, c)
+#define isALPHA_uni(c)      _generic_swash_uni(_CC_ALPHA, c)
+#define isALPHANUMERIC_uni(c) _generic_swash_uni(_CC_ALPHANUMERIC, c)
 #define isASCII_uni(c)      isASCII(c)
 #define isBLANK_uni(c)      _generic_uni(_CC_BLANK, is_HORIZWS_cp_high, c)
 #define isCNTRL_uni(c)      isCNTRL_L1(c) /* All controls are in Latin1 */
-#define isDIGIT_uni(c)      _generic_uni_swash(_CC_DIGIT, c)
-#define isGRAPH_uni(c)      _generic_uni_swash(_CC_GRAPH, c)
+#define isDIGIT_uni(c)      _generic_swash_uni(_CC_DIGIT, c)
+#define isGRAPH_uni(c)      _generic_swash_uni(_CC_GRAPH, c)
+#define isIDCONT_uni(c)     _generic_uni(_CC_WORDCHAR, _is_uni_perl_idcont, c)
 #define isIDFIRST_uni(c)    _generic_uni(_CC_IDFIRST, _is_uni_perl_idstart, c)
-#define isLOWER_uni(c)      _generic_uni_swash(_CC_LOWER, c)
-#define isPRINT_uni(c)      _generic_uni_swash(_CC_PRINT, c)
+#define isLOWER_uni(c)      _generic_swash_uni(_CC_LOWER, c)
+#define isPRINT_uni(c)      _generic_swash_uni(_CC_PRINT, c)
 
 /* Posix and regular space are identical above Latin1 */
 #define isPSXSPC_uni(c)     _generic_uni(_CC_PSXSPC, is_XPERLSPACE_cp_high, c)
 
-#define isPUNCT_uni(c)      _generic_uni_swash(_CC_PUNCT, c)
+#define isPUNCT_uni(c)      _generic_swash_uni(_CC_PUNCT, c)
 #define isSPACE_uni(c)      _generic_uni(_CC_SPACE, is_XPERLSPACE_cp_high, c)
-#define isUPPER_uni(c)      _generic_uni_swash(_CC_UPPER, c)
+#define isUPPER_uni(c)      _generic_swash_uni(_CC_UPPER, c)
 #define isVERTWS_uni(c)     _generic_uni(_CC_VERTSPACE, is_VERTWS_cp_high, c)
-#define isWORDCHAR_uni(c)   _generic_uni_swash(_CC_WORDCHAR, c)
+#define isWORDCHAR_uni(c)   _generic_swash_uni(_CC_WORDCHAR, c)
 #define isXDIGIT_uni(c)     _generic_uni(_CC_XDIGIT, is_XDIGIT_cp_high, c)
 
 #define toFOLD_uni(c,s,l)      to_uni_fold(c,s,l)
@@ -1158,64 +1290,72 @@ EXTCONST U32 PL_charclass[];
 #define toTITLE_uni(c,s,l)     to_uni_title(c,s,l)
 #define toUPPER_uni(c,s,l)     to_uni_upper(c,s,l)
 
-#define _gnrc_is_LC_uvchr(latin1, above_latin1, c)                            \
-                        (c < 256 ? latin1(c) : above_latin1(NATIVE_TO_UNI(c)))
-#define isALPHA_LC_uvchr(c)  _gnrc_is_LC_uvchr(isALPHA_LC, is_uni_alpha_lc, c)
-#define isALPHANUMERIC_LC_uvchr(c)  _gnrc_is_LC_uvchr(isALPHANUMERIC_LC,      \
-                                                         is_uni_alnumc_lc, c)
+#define _generic_LC_uvchr(latin1, above_latin1, c)                            \
+                                    (c < 256 ? latin1(c) : above_latin1(c))
+#define _generic_LC_swash_uvchr(latin1, classnum, c)                          \
+                            (c < 256 ? latin1(c) : _is_uni_FOO(classnum, c))
+
+#define isALPHA_LC_uvchr(c)  _generic_LC_swash_uvchr(isALPHA_LC, _CC_ALPHA, c)
+#define isALPHANUMERIC_LC_uvchr(c)  _generic_LC_swash_uvchr(isALPHANUMERIC_LC, \
+                                                         _CC_ALPHANUMERIC, c)
 #define isASCII_LC_uvchr(c)  isASCII_LC(c)
-#define isBLANK_LC_uvchr(c)  _gnrc_is_LC_uvchr(isBLANK_LC, is_HORIZWS_cp_high, c)
+#define isBLANK_LC_uvchr(c)  _generic_LC_uvchr(isBLANK_LC, is_HORIZWS_cp_high, c)
 #define isCNTRL_LC_uvchr(c)  (c < 256 ? isCNTRL_LC(c) : 0)
-#define isDIGIT_LC_uvchr(c)  _gnrc_is_LC_uvchr(isDIGIT_LC, is_uni_digit_lc, c)
-#define isGRAPH_LC_uvchr(c)  _gnrc_is_LC_uvchr(isGRAPH_LC, is_uni_graph_lc, c)
-#define isIDFIRST_LC_uvchr(c)  _gnrc_is_LC_uvchr(isIDFIRST_LC,                 \
-                                                          is_uni_idfirst_lc, c)
-#define isLOWER_LC_uvchr(c)  _gnrc_is_LC_uvchr(isLOWER_LC, is_uni_lower_lc, c)
-#define isPRINT_LC_uvchr(c)  _gnrc_is_LC_uvchr(isPRINT_LC, is_uni_print_lc, c)
+#define isDIGIT_LC_uvchr(c)  _generic_LC_swash_uvchr(isDIGIT_LC, _CC_DIGIT, c)
+#define isGRAPH_LC_uvchr(c)  _generic_LC_swash_uvchr(isGRAPH_LC, _CC_GRAPH, c)
+#define isIDCONT_LC_uvchr(c)  _generic_LC_uvchr(isIDCONT_LC,                  \
+                                                  _is_uni_perl_idcont, c)
+#define isIDFIRST_LC_uvchr(c)  _generic_LC_uvchr(isIDFIRST_LC,                 \
+                                                  _is_uni_perl_idstart, c)
+#define isLOWER_LC_uvchr(c)  _generic_LC_swash_uvchr(isLOWER_LC, _CC_LOWER, c)
+#define isPRINT_LC_uvchr(c)  _generic_LC_swash_uvchr(isPRINT_LC, _CC_PRINT, c)
 #define isPSXSPC_LC_uvchr(c) isSPACE_LC_uvchr(c) /* space is identical to posix
                                                     space under locale */
-#define isPUNCT_LC_uvchr(c)  _gnrc_is_LC_uvchr(isPUNCT_LC, is_uni_punct_lc, c)
-#define isSPACE_LC_uvchr(c)  _gnrc_is_LC_uvchr(isSPACE_LC,                     \
+#define isPUNCT_LC_uvchr(c)  _generic_LC_swash_uvchr(isPUNCT_LC, _CC_PUNCT, c)
+#define isSPACE_LC_uvchr(c)  _generic_LC_uvchr(isSPACE_LC,                     \
                                                     is_XPERLSPACE_cp_high, c)
-#define isUPPER_LC_uvchr(c)  _gnrc_is_LC_uvchr(isUPPER_LC, is_uni_upper_lc, c)
-#define isWORDCHAR_LC_uvchr(c)  _gnrc_is_LC_uvchr(isWORDCHAR_LC,              \
-                                                           is_uni_alnum_lc, c)
-#define isXDIGIT_LC_uvchr(c) _gnrc_is_LC_uvchr(isXDIGIT_LC, is_XDIGIT_cp_high, c)
+#define isUPPER_LC_uvchr(c)  _generic_LC_swash_uvchr(isUPPER_LC, _CC_UPPER, c)
+#define isWORDCHAR_LC_uvchr(c)  _generic_LC_swash_uvchr(isWORDCHAR_LC,              \
+                                                           _CC_WORDCHAR, c)
+#define isXDIGIT_LC_uvchr(c) _generic_LC_uvchr(isXDIGIT_LC, is_XDIGIT_cp_high, c)
 
 
 #define isBLANK_LC_uni(c)      isBLANK_LC_uvchr(UNI_TO_NATIVE(c))
 
-/* For internal core Perl use only.  If the input is in the Latin1 range, use
+/* Everything whose name begins with an underscore is for internal core Perl
+ * use only. */
+
+/* If the input is in the Latin1 range, use
  * the Latin1 macro 'classnum' on 'p' which is a pointer to a UTF-8 string.
  * Otherwise use the value given by the 'utf8' parameter.  This relies on the
  * fact that ASCII characters have the same representation whether utf8 or not.
  * Note that it assumes that the utf8 has been validated, and ignores 'use
  * bytes' */
-#define _generic_utf8_utf8(classnum, p, utf8) (UTF8_IS_INVARIANT(*(p))         \
+#define _generic_utf8(classnum, p, utf8) (UTF8_IS_INVARIANT(*(p))              \
                                          ? _generic_isCC(*(p), classnum)       \
                                          : (UTF8_IS_DOWNGRADEABLE_START(*(p))) \
                                            ? _generic_isCC(                    \
-                                                   TWO_BYTE_UTF8_TO_UNI(*(p),  \
+                                                TWO_BYTE_UTF8_TO_NATIVE(*(p),  \
                                                                    *((p)+1 )), \
-                                                   classnum)                   \
+                                                classnum)                      \
                                            : utf8)
-/* Like the above, but calls 'function(p)' to get the utf8 value */
-#define _generic_utf8(classnum, function, p)  \
-                                    _generic_utf8_utf8(classnum, p, function(p))
-
-/* Like the above, but passes classnum to _isFOO_utf8() */
+/* Like the above, but calls 'above_latin1(p)' to get the utf8 value.  'above_latin1'
+ * can be a macro */
+#define _generic_func_utf8(classnum, above_latin1, p)  \
+                                    _generic_utf8(classnum, p, above_latin1(p))
+/* Like the above, but passes classnum to _isFOO_utf8(), instead of having a
+ * 'above_latin1' parameter */
 #define _generic_swash_utf8(classnum, p)  \
-                      _generic_utf8_utf8(classnum, p, _is_utf8_FOO(classnum, p))
-
+                      _generic_utf8(classnum, p, _is_utf8_FOO(classnum, p))
 
 /* Like the above, but should be used only when it is known that there are no
  * characters in the range 128-255 which the class is TRUE for.  Hence it can
- * skip the tests for this range */
-#define _generic_utf8_no_upper_latin1(classnum, function, p)                   \
+ * skip the tests for this range.  'above_latin1' should include its arguments */
+#define _generic_utf8_no_upper_latin1(classnum, p, above_latin1)                   \
                                          (UTF8_IS_INVARIANT(*(p))              \
                                          ? _generic_isCC(*(p), classnum)       \
                                          : (UTF8_IS_ABOVE_LATIN1(*(p)))        \
-                                           ? function(p)                       \
+                                           ? above_latin1                          \
                                            : 0)
 
 /* NOTE that some of these macros have very similar ones in regcharclass.h.
@@ -1231,12 +1371,13 @@ EXTCONST U32 PL_charclass[];
 #define isASCII_utf8(p)         isASCII(*p) /* Because ASCII is invariant under
                                                utf8, the non-utf8 macro works
                                              */
-#define isBLANK_utf8(p)         _generic_utf8(_CC_BLANK, is_HORIZWS_high, p)
-#define isCNTRL_utf8(p)         _generic_utf8_utf8(_CC_CNTRL, p, 0)
-#define isDIGIT_utf8(p)         _generic_utf8_no_upper_latin1(_CC_DIGIT,      \
-                                                              is_utf8_digit, p)
+#define isBLANK_utf8(p)         _generic_func_utf8(_CC_BLANK, is_HORIZWS_high, p)
+#define isCNTRL_utf8(p)         _generic_utf8(_CC_CNTRL, p, 0)
+#define isDIGIT_utf8(p)         _generic_utf8_no_upper_latin1(_CC_DIGIT, p,   \
+                                                  _is_utf8_FOO(_CC_DIGIT, p))
 #define isGRAPH_utf8(p)         _generic_swash_utf8(_CC_GRAPH, p)
-#define isIDCONT_utf8(p)        _generic_utf8(_CC_WORDCHAR, is_utf8_xidcont, p)
+#define isIDCONT_utf8(p)        _generic_func_utf8(_CC_WORDCHAR,              \
+                                                  _is_utf8_perl_idcont, p)
 
 /* To prevent S_scan_word in toke.c from hanging, we have to make sure that
  * IDFIRST is an alnum.  See
@@ -1244,23 +1385,24 @@ EXTCONST U32 PL_charclass[];
  * ever wanted to know about.  (In the ASCII range, there isn't a difference.)
  * This used to be not the XID version, but we decided to go with the more
  * modern Unicode definition */
-#define isIDFIRST_utf8(p)       _generic_utf8(_CC_IDFIRST,               \
+#define isIDFIRST_utf8(p)       _generic_func_utf8(_CC_IDFIRST,               \
                                                 _is_utf8_perl_idstart, p)
 
 #define isLOWER_utf8(p)         _generic_swash_utf8(_CC_LOWER, p)
 #define isPRINT_utf8(p)         _generic_swash_utf8(_CC_PRINT, p)
 
 /* Posix and regular space are identical above Latin1 */
-#define isPSXSPC_utf8(p)        _generic_utf8(_CC_PSXSPC, is_XPERLSPACE_high, p)
+#define isPSXSPC_utf8(p)        _generic_func_utf8(_CC_PSXSPC, is_XPERLSPACE_high, p)
 
 #define isPUNCT_utf8(p)         _generic_swash_utf8(_CC_PUNCT, p)
-#define isSPACE_utf8(p)         _generic_utf8(_CC_SPACE, is_XPERLSPACE_high, p)
+#define isSPACE_utf8(p)         _generic_func_utf8(_CC_SPACE, is_XPERLSPACE_high, p)
 #define isUPPER_utf8(p)         _generic_swash_utf8(_CC_UPPER, p)
-#define isVERTWS_utf8(p)        _generic_utf8(_CC_VERTSPACE, is_VERTWS_high, p)
+#define isVERTWS_utf8(p)        _generic_func_utf8(_CC_VERTSPACE, is_VERTWS_high, p)
 #define isWORDCHAR_utf8(p)      _generic_swash_utf8(_CC_WORDCHAR, p)
-#define isXDIGIT_utf8(p)        _generic_utf8_no_upper_latin1(_CC_XDIGIT,      \
-                                                              is_XDIGIT_high, p)
+#define isXDIGIT_utf8(p)        _generic_utf8_no_upper_latin1(_CC_XDIGIT, p,   \
+                                                          is_XDIGIT_high(p))
 
+#define toFOLD_utf8(p,s,l)     to_utf8_fold(p,s,l)
 #define toLOWER_utf8(p,s,l)    to_utf8_lower(p,s,l)
 #define toTITLE_utf8(p,s,l)    to_utf8_title(p,s,l)
 #define toUPPER_utf8(p,s,l)    to_utf8_upper(p,s,l)
@@ -1270,35 +1412,38 @@ EXTCONST U32 PL_charclass[];
  * use the value given by the 'utf8' parameter.  This relies on the fact that
  * ASCII characters have the same representation whether utf8 or not.  Note
  * that it assumes that the utf8 has been validated, and ignores 'use bytes' */
-#define _generic_LC_utf8_utf8(macro, p, utf8) \
-                         (UTF8_IS_INVARIANT(*(p))                          \
-                         ? macro(*(p))                                     \
-                         : (UTF8_IS_DOWNGRADEABLE_START(*(p)))             \
-                           ? macro(TWO_BYTE_UTF8_TO_UNI(*(p), *((p)+1)))   \
+#define _generic_LC_utf8(macro, p, utf8)                                    \
+                         (UTF8_IS_INVARIANT(*(p))                           \
+                         ? macro(*(p))                                      \
+                         : (UTF8_IS_DOWNGRADEABLE_START(*(p)))              \
+                           ? macro(TWO_BYTE_UTF8_TO_NATIVE(*(p), *((p)+1))) \
                            : utf8)
 
-#define _generic_LC_utf8(macro, utf8_func, p)                              \
-                            _generic_LC_utf8_utf8(macro, p, utf8_func(p))
+#define _generic_LC_swash_utf8(macro, classnum, p)                         \
+                    _generic_LC_utf8(macro, p, _is_utf8_FOO(classnum, p))
+#define _generic_LC_func_utf8(macro, above_latin1, p)                         \
+                    _generic_LC_utf8(macro, p, above_latin1(p))
 
-#define isALPHANUMERIC_LC_utf8(p)  _generic_LC_utf8(isALPHANUMERIC_LC,       \
-                                                          is_utf8_alnumc, p)
-#define isALPHA_LC_utf8(p)   _generic_LC_utf8(isALPHA_LC, is_utf8_alpha, p)
+#define isALPHANUMERIC_LC_utf8(p)  _generic_LC_swash_utf8(isALPHANUMERIC_LC,  \
+                                                      _CC_ALPHANUMERIC, p)
+#define isALPHA_LC_utf8(p)   _generic_LC_swash_utf8(isALPHA_LC, _CC_ALPHA, p)
 #define isASCII_LC_utf8(p)   isASCII_LC(*p)
-#define isBLANK_LC_utf8(p)   _generic_LC_utf8(isBLANK_LC, is_HORIZWS_high, p)
-#define isCNTRL_LC_utf8(p)   _generic_LC_utf8_utf8(isCNTRL_LC, p, 0)
-#define isDIGIT_LC_utf8(p)   _generic_LC_utf8(isDIGIT_LC, is_utf8_digit, p)
-#define isGRAPH_LC_utf8(p)   _generic_LC_utf8(isGRAPH_LC, is_utf8_graph, p)
-#define isIDFIRST_LC_utf8(p) _generic_LC_utf8(isIDFIRST_LC,                \
-                                                 _is_utf8_perl_idstart, p)
-#define isLOWER_LC_utf8(p)   _generic_LC_utf8(isLOWER_LC, is_utf8_lower, p)
-#define isPRINT_LC_utf8(p)   _generic_LC_utf8(isPRINT_LC, is_utf8_print, p)
+#define isBLANK_LC_utf8(p)   _generic_LC_func_utf8(isBLANK_LC, is_HORIZWS_high, p)
+#define isCNTRL_LC_utf8(p)   _generic_LC_utf8(isCNTRL_LC, p, 0)
+#define isDIGIT_LC_utf8(p)   _generic_LC_swash_utf8(isDIGIT_LC, _CC_DIGIT, p)
+#define isGRAPH_LC_utf8(p)   _generic_LC_swash_utf8(isGRAPH_LC, _CC_GRAPH, p)
+#define isIDCONT_LC_utf8(p) _generic_LC_func_utf8(isIDCONT_LC, _is_utf8_perl_idcont, p)
+#define isIDFIRST_LC_utf8(p) _generic_LC_func_utf8(isIDFIRST_LC, _is_utf8_perl_idstart, p)
+#define isLOWER_LC_utf8(p)   _generic_LC_swash_utf8(isLOWER_LC, _CC_LOWER, p)
+#define isPRINT_LC_utf8(p)   _generic_LC_swash_utf8(isPRINT_LC, _CC_PRINT, p)
 #define isPSXSPC_LC_utf8(p)  isSPACE_LC_utf8(p) /* space is identical to posix
                                                    space under locale */
-#define isPUNCT_LC_utf8(p)   _generic_LC_utf8(isPUNCT_LC, is_utf8_punct, p)
-#define isSPACE_LC_utf8(p)   _generic_LC_utf8(isSPACE_LC, is_XPERLSPACE_high, p)
-#define isUPPER_LC_utf8(p)   _generic_LC_utf8(isUPPER_LC, is_utf8_upper, p)
-#define isWORDCHAR_LC_utf8(p) _generic_LC_utf8(isWORDCHAR_LC, is_utf8_alnum, p)
-#define isXDIGIT_LC_utf8(p)  _generic_LC_utf8(isXDIGIT_LC, is_XDIGIT_high, p)
+#define isPUNCT_LC_utf8(p)   _generic_LC_swash_utf8(isPUNCT_LC, _CC_PUNCT, p)
+#define isSPACE_LC_utf8(p)   _generic_LC_func_utf8(isSPACE_LC, is_XPERLSPACE_high, p)
+#define isUPPER_LC_utf8(p)   _generic_LC_swash_utf8(isUPPER_LC, _CC_UPPER, p)
+#define isWORDCHAR_LC_utf8(p) _generic_LC_swash_utf8(isWORDCHAR_LC,           \
+                                                            _CC_WORDCHAR, p)
+#define isXDIGIT_LC_utf8(p)  _generic_LC_func_utf8(isXDIGIT_LC, is_XDIGIT_high, p)
 
 /* Macros for backwards compatibility and for completeness when the ASCII and
  * Latin1 values are identical */
@@ -1327,7 +1472,7 @@ EXTCONST U32 PL_charclass[];
  * CTRL-@ is 0, CTRL-A is 1, etc, just like on ASCII, except that they don't
  * necessarily mean the same characters, e.g. CTRL-D is 4 on both systems, but
  * that is EOT on ASCII;  ST on EBCDIC */
-#  define toCTRL(c)    (toUPPER(NATIVE_TO_UNI(c)) ^ 64)
+#  define toCTRL(c)    (toUPPER(NATIVE_TO_LATIN1(c)) ^ 64)
 
 /* Line numbers are unsigned, 32 bits. */
 typedef U32 line_t;
@@ -1617,6 +1762,37 @@ void Perl_mem_log_del_sv(const SV *sv, const char *filename, const int linenumbe
 #  define deprecate(s) Perl_ck_warner_d(aTHX_ packWARN(WARN_DEPRECATED), "Use of " s " is deprecated")
 #endif
 
+/* Internal macros to deal with gids and uids */
+#ifdef PERL_CORE
+
+#  if Uid_t_size > IVSIZE
+#    define sv_setuid(sv, uid)       sv_setnv((sv), (NV)(uid))
+#    define SvUID(sv)                SvNV(sv)
+#  else
+#    if Uid_t_sign <= 0
+#      define sv_setuid(sv, uid)       sv_setiv((sv), (IV)(uid))
+#      define SvUID(sv)                SvIV(sv)
+#    else
+#      define sv_setuid(sv, uid)       sv_setuv((sv), (UV)(uid))
+#      define SvUID(sv)                SvUV(sv)
+#    endif
+#  endif /* Uid_t_size */
+
+#  if Gid_t_size > IVSIZE
+#    define sv_setgid(sv, gid)       sv_setnv((sv), (NV)(gid))
+#    define SvGID(sv)                SvNV(sv)
+#  else
+#    if Gid_t_sign <= 0
+#      define sv_setgid(sv, gid)       sv_setiv((sv), (IV)(gid))
+#      define SvGID(sv)                SvIV(sv)
+#    else
+#      define sv_setgid(sv, gid)       sv_setuv((sv), (UV)(gid))
+#      define SvGID(sv)                SvUV(sv)
+#    endif
+#  endif /* Gid_t_size */
+
+#endif
+
 #endif  /* HANDY_H */
 
 /*