handy.h: Express locale macros using common base macros
authorKarl Williamson <public@khwilliamson.com>
Thu, 9 Jan 2014 06:10:06 +0000 (23:10 -0700)
committerKarl Williamson <public@khwilliamson.com>
Wed, 22 Jan 2014 18:45:56 +0000 (11:45 -0700)
This extracts out the code of looking up POSIX classes in locales to use
base macros common to all of them.  It does this for the NeXT only code
as well as the typical compilations.

This is in preparation for changing the behavior.  Certain things look
weird as they are aligned, etc as part of that preparation.

handy.h

diff --git a/handy.h b/handy.h
index 2d9d51b..f98c8fb 100644 (file)
--- a/handy.h
+++ b/handy.h
@@ -1222,7 +1222,6 @@ EXTCONST U32 PL_charclass[];
  * 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)
@@ -1243,6 +1242,49 @@ EXTCONST U32 PL_charclass[];
                                ? (c)                                       \
                                : PL_mod_latin1_uc[ (U8) (c) ])
 
+/* Use foo_LC_uvchr() instead  of these for beyond the Latin1 range */
+
+/* For internal core Perl use only: the base macro for defining macros like
+ * isALPHA_LC, which uses the current LC_CTYPE locale.  'c' is the code point
+ * (0-255) to check.  'utf8_locale_classnum' is currently unused.  The code to
+ * actually do the test this is passed in 'non_utf8'.  If 'c' is above 255, 0
+ * is returned.  For accessing the full range of possible code points under
+ * locale rules, use the macros based on _generic_LC_uvchr instead of this. */
+#define _generic_LC_base(c, utf8_locale_classnum, non_utf8)                    \
+           (! FITS_IN_8_BITS(c)                                                \
+           ? 0                                                                 \
+             : cBOOL(non_utf8))
+
+/* For internal core Perl use only: a helper macro for defining macros like
+ * isALPHA_LC.  'c' is the code point (0-255) to check.  The function name to
+ * actually do this test is passed in 'non_utf8_func', which is called on 'c',
+ * casting 'c' to the macro _LC_CAST, which should not be parenthesized.  See
+ * _generic_LC_base for more info */
+#define _generic_LC(c, utf8_locale_classnum, non_utf8_func)                    \
+                        _generic_LC_base(c,utf8_locale_classnum,               \
+                                         non_utf8_func( (_LC_CAST) (c)))
+
+/* For internal core Perl use only: like _generic_LC, but also returns TRUE if
+ * 'c' is the platform's native underscore character */
+#define _generic_LC_underscore(c,utf8_locale_classnum,non_utf8_func)           \
+                        _generic_LC_base(c, utf8_locale_classnum,              \
+                                         (non_utf8_func( (_LC_CAST) (c))       \
+                                          || (char)(c) == '_'))
+
+/* These next three are also for internal core Perl use only: case-change
+ * helper macros */
+#define _generic_toLOWER_LC(c, function, cast)  (! FITS_IN_8_BITS(c)           \
+                                                ? (c)                          \
+                                                : function((cast)(c)))
+
+#define _generic_toUPPER_LC(c, function, cast)                                 \
+                    (! FITS_IN_8_BITS(c)                                       \
+                    ? (c)                                                      \
+                      : function((cast)(c)))
+
+#define _generic_toFOLD_LC(c, function, cast)                                  \
+                      _generic_toLOWER_LC(c, function, cast)
+
 /* Use the libc versions for these if available. */
 #if defined(HAS_ISASCII) && ! defined(USE_NEXT_CTYPE)
 #   define isASCII_LC(c) (FITS_IN_8_BITS(c) && isascii( (U8) (c)))
@@ -1258,44 +1300,52 @@ EXTCONST U32 PL_charclass[];
 
 #ifdef USE_NEXT_CTYPE   /* NeXT computers */
 
-#  define isALPHANUMERIC_LC(c) NXIsAlNum((unsigned int)(c))
-#  define isALPHA_LC(c)                NXIsAlpha((unsigned int)(c))
-#  define isCNTRL_LC(c)                NXIsCntrl((unsigned int)(c))
-#  define isDIGIT_LC(c)                NXIsDigit((unsigned int)(c))
-#  define isGRAPH_LC(c)                NXIsGraph((unsigned int)(c))
-#  define isIDFIRST_LC(c) (NXIsAlpha((unsigned int)(c)) || (char)(c) == '_')
-#  define isLOWER_LC(c)                NXIsLower((unsigned int)(c))
-#  define isPRINT_LC(c)                NXIsPrint((unsigned int)(c))
-#  define isPUNCT_LC(c)                NXIsPunct((unsigned int)(c))
-#  define isSPACE_LC(c)                NXIsSpace((unsigned int)(c))
-#  define isUPPER_LC(c)                NXIsUpper((unsigned int)(c))
-#  define isWORDCHAR_LC(c) (NXIsAlNum((unsigned int)(c)) || (char)(c) == '_')
-#  define isXDIGIT_LC(c)        NXIsXDigit((unsigned int)(c))
-#  define toLOWER_LC(c)                NXToLower((unsigned int)(c))
-#  define toUPPER_LC(c)                NXToUpper((unsigned int)(c))
+#    define _LC_CAST unsigned int   /* Needed by _generic_LC.  NeXT functions
+                                       use this as their input type */
+
+#    define isALPHA_LC(c)   _generic_LC(c, _CC_ALPHA, NXIsAlpha)
+#    define isALPHANUMERIC_LC(c)  _generic_LC(c, _CC_ALPHANUMERIC, NXIsAlNum)
+#    define isCNTRL_LC(c)    _generic_LC(c, _CC_CNTRL, NXIsCntrl)
+#    define isDIGIT_LC(c)    _generic_LC(c, _CC_DIGIT, NXIsDigit)
+#    define isGRAPH_LC(c)    _generic_LC(c, _CC_GRAPH, NXIsGraph)
+#    define isIDFIRST_LC(c)  _generic_LC_underscore(c, _CC_IDFIRST, NXIsAlpha)
+#    define isLOWER_LC(c)    _generic_LC(c, _CC_LOWER, NXIsLower)
+#    define isPRINT_LC(c)    _generic_LC(c, _CC_PRINT, NXIsPrint)
+#    define isPUNCT_LC(c)    _generic_LC(c, _CC_PUNCT, NXIsPunct)
+#    define isSPACE_LC(c)    _generic_LC(c, _CC_SPACE, NXIsSpace)
+#    define isUPPER_LC(c)    _generic_LC(c, _CC_UPPER, NXIsUpper)
+#    define isWORDCHAR_LC(c) _generic_LC_underscore(c, _CC_WORDCHAR, NXIsAlNum)
+#    define isXDIGIT_LC(c)   _generic_LC(c, _CC_XDIGIT, NXIsXdigit)
+
+#    define toLOWER_LC(c) _generic_toLOWER_LC((c), NXToLower, unsigned int)
+#    define toUPPER_LC(c) _generic_toUPPER_LC((c), NXToUpper, unsigned int)
+#    define toFOLD_LC(c)  _generic_toFOLD_LC((c), NXToLower, unsigned int)
 
 #else /* !USE_NEXT_CTYPE */
 
 #  if defined(CTYPE256) || (!defined(isascii) && !defined(HAS_ISASCII))
     /* For most other platforms */
-#    define isALPHA_LC(c)   (FITS_IN_8_BITS(c) && isalpha((unsigned char)(c)))
-#    define isALPHANUMERIC_LC(c)   (FITS_IN_8_BITS(c)                          \
-                                               && isalnum((unsigned char)(c)))
-#    define isCNTRL_LC(c)    (FITS_IN_8_BITS(c) && iscntrl((unsigned char)(c)))
-#    define isDIGIT_LC(c)    (FITS_IN_8_BITS(c) && isdigit((unsigned char)(c)))
-#    define isGRAPH_LC(c)    (FITS_IN_8_BITS(c) && isgraph((unsigned char)(c)))
-#    define isIDFIRST_LC(c) (FITS_IN_8_BITS(c)                                 \
-                            && (isalpha((unsigned char)(c)) || (char)(c) == '_'))
-#    define isLOWER_LC(c)    (FITS_IN_8_BITS(c) && islower((unsigned char)(c)))
-#    define isPRINT_LC(c)    (FITS_IN_8_BITS(c) && isprint((unsigned char)(c)))
-#    define isPUNCT_LC(c)    (FITS_IN_8_BITS(c) && ispunct((unsigned char)(c)))
-#    define isSPACE_LC(c)    (FITS_IN_8_BITS(c) && isspace((unsigned char)(c)))
-#    define isUPPER_LC(c)    (FITS_IN_8_BITS(c) && isupper((unsigned char)(c)))
-#    define isWORDCHAR_LC(c) (FITS_IN_8_BITS(c)                                \
-                            && (isalnum((unsigned char)(c)) || (char)(c) == '_'))
-#    define isXDIGIT_LC(c)   (FITS_IN_8_BITS(c) && isxdigit((unsigned char)(c)))
-#    define toLOWER_LC(c) (FITS_IN_8_BITS(c) ? (UV)tolower((unsigned char)(c)) : (c))
-#    define toUPPER_LC(c) (FITS_IN_8_BITS(c) ? (UV)toupper((unsigned char)(c)) : (c))
+
+#    define _LC_CAST U8
+
+#    define isALPHA_LC(c)   _generic_LC(c, _CC_ALPHA, isalpha)
+#    define isALPHANUMERIC_LC(c)  _generic_LC(c, _CC_ALPHANUMERIC, isalnum)
+#    define isCNTRL_LC(c)    _generic_LC(c, _CC_CNTRL, iscntrl)
+#    define isDIGIT_LC(c)    _generic_LC(c, _CC_DIGIT, isdigit)
+#    define isGRAPH_LC(c)    _generic_LC(c, _CC_GRAPH, isgraph)
+#    define isIDFIRST_LC(c)  _generic_LC_underscore(c, _CC_IDFIRST, isalpha)
+#    define isLOWER_LC(c)    _generic_LC(c, _CC_LOWER, islower)
+#    define isPRINT_LC(c)    _generic_LC(c, _CC_PRINT, isprint)
+#    define isPUNCT_LC(c)    _generic_LC(c, _CC_PUNCT, ispunct)
+#    define isSPACE_LC(c)    _generic_LC(c, _CC_SPACE, isspace)
+#    define isUPPER_LC(c)    _generic_LC(c, _CC_UPPER, isupper)
+#    define isWORDCHAR_LC(c) _generic_LC_underscore(c, _CC_WORDCHAR, isalnum)
+#    define isXDIGIT_LC(c)   _generic_LC(c, _CC_XDIGIT, isxdigit)
+
+
+#    define toLOWER_LC(c) _generic_toLOWER_LC((c), tolower, U8)
+#    define toUPPER_LC(c) _generic_toUPPER_LC((c), toupper, U8)
+#    define toFOLD_LC(c)  _generic_toFOLD_LC((c), tolower, U8)
 
 #  else  /* The final fallback position */
 
@@ -1315,6 +1365,7 @@ EXTCONST U32 PL_charclass[];
 
 #    define toLOWER_LC(c)      (isascii(c) ? tolower(c) : (c))
 #    define toUPPER_LC(c)      (isascii(c) ? toupper(c) : (c))
+#    define toFOLD_LC(c)       (isascii(c) ? tolower(c) : (c))
 
 #  endif
 #endif /* USE_NEXT_CTYPE */