{-# LANGUAGE MagicHash #-}

-- | Char8 library to be used with "Data.ByteString.Char8".
-- All functions assume that 'Char' is in the Latin-1 range (ISO-8859-1).
-- All utility functions are supposed to work like
-- those of "Data.Char". Exceptions are described in
-- the function documentations.
module Data.Char8 (
    -- * Character classification
    isControl,
    isSpace,
    isLower,
    isUpper,
    isAlpha,
    isAlphaNum,
    isPrint,
    isDigit,
    isOctDigit,
    isHexDigit,
    isLetter,
    isMark,
    isNumber,
    isPunctuation,
    isSymbol,
    isSeparator,

    -- * Subranges
    isAscii,
    isLatin1,
    isAsciiUpper,
    isAsciiLower,

    -- * Case conversion
    toUpper,
    toLower,
    toTitle,
) where

import GHC.Base

import qualified Data.Word8 as W

----------------------------------------------------------------

-- | Is it a control character
isControl :: Char -> Bool
isControl :: Char -> Bool
isControl Char
c =
    Char
c Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
<= Char
'\x1f'
        Bool -> Bool -> Bool
|| Char
_del Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
<= Char
c Bool -> Bool -> Bool
&& Char
c Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
<= Char
'\x9f'

-- | Is it white space
isSpace :: Char -> Bool
isSpace :: Char -> Bool
isSpace Char
c =
    Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
_space
        Bool -> Bool -> Bool
|| Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
_tab
        Bool -> Bool -> Bool
|| Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
_lf
        Bool -> Bool -> Bool
|| Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
_cr
        Bool -> Bool -> Bool
|| Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
_np
        Bool -> Bool -> Bool
|| Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
_vt
        Bool -> Bool -> Bool
|| Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
_nbsp

-- | Is it a lower case character
--
-- This function returns 'False' for 170 (ª) and 186 (º).
isLower :: Char -> Bool
isLower :: Char -> Bool
isLower Char
c =
    Char -> Bool
isLower' Char
c
        Bool -> Bool -> Bool
|| Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
_mu

isLowerCommon :: Char -> Bool
isLowerCommon :: Char -> Bool
isLowerCommon Char
c =
    Char -> Bool
isLower' Char
c
        Bool -> Bool -> Bool
|| Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
_mu
        Bool -> Bool -> Bool
|| Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
_ordfeminine
        Bool -> Bool -> Bool
|| Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
_ordmasculine

isLower' :: Char -> Bool
isLower' :: Char -> Bool
isLower' Char
c =
    Char -> Bool
isAsciiLower Char
c
        Bool -> Bool -> Bool
|| Char
_germandbls Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
<= Char
c Bool -> Bool -> Bool
&& Char
c Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
<= Char
_ydieresis Bool -> Bool -> Bool
&& Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
/= Char
'\xf7'

-- | Is it an upper case character
isUpper :: Char -> Bool
isUpper :: Char -> Bool
isUpper Char
c =
    Char -> Bool
isAsciiUpper Char
c
        Bool -> Bool -> Bool
|| Char
_Agrave Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
<= Char
c Bool -> Bool -> Bool
&& Char
c Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
<= Char
_Thorn Bool -> Bool -> Bool
&& Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
/= Char
'\xd7'

-- | Is it an alphabet letter
--
-- Synonym for 'isLetter'
isAlpha :: Char -> Bool
isAlpha :: Char -> Bool
isAlpha Char
c = Char -> Bool
isLowerCommon Char
c Bool -> Bool -> Bool
|| Char -> Bool
isUpper Char
c

-- | Is it an alphabet letter or a number
isAlphaNum :: Char -> Bool
isAlphaNum :: Char -> Bool
isAlphaNum Char
c = Char -> Bool
isAlpha Char
c Bool -> Bool -> Bool
|| Char -> Bool
isNumber Char
c

-- | Is the character printable
isPrint :: Char -> Bool
isPrint :: Char -> Bool
isPrint Char
c
    | Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
_softhyphen = Bool
False
isPrint Char
c =
    Char
_space Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
<= Char
c Bool -> Bool -> Bool
&& Char
c Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
<= Char
_tilde
        Bool -> Bool -> Bool
|| Char
_nbsp Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
<= Char
c Bool -> Bool -> Bool
&& Char
c Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
<= Char
_ydieresis

-- | Is the character a digit (@0-9@)
isDigit :: Char -> Bool
isDigit :: Char -> Bool
isDigit Char
c = Char
'0' Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
<= Char
c Bool -> Bool -> Bool
&& Char
c Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
<= Char
'9'

-- | Is the character an octal digit (@0-7@)
isOctDigit :: Char -> Bool
isOctDigit :: Char -> Bool
isOctDigit Char
c = Char
'0' Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
<= Char
c Bool -> Bool -> Bool
&& Char
c Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
<= Char
'7'

-- | Is the character a hexadecimal digit (@0-9a-fA-F@)
isHexDigit :: Char -> Bool
isHexDigit :: Char -> Bool
isHexDigit Char
c =
    Char -> Bool
isDigit Char
c
        Bool -> Bool -> Bool
|| Char
'A' Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
<= Char
c Bool -> Bool -> Bool
&& Char
c Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
<= Char
'F'
        Bool -> Bool -> Bool
|| Char
'a' Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
<= Char
c Bool -> Bool -> Bool
&& Char
c Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
<= Char
'f'

-- | Is it an alphabet letter
--
-- Synonym for 'isAlpha'
isLetter :: Char -> Bool
isLetter :: Char -> Bool
isLetter Char
c = Char -> Bool
isLowerCommon Char
c Bool -> Bool -> Bool
|| Char -> Bool
isUpper Char
c

-- | A Latin-1 character is never a mark
--
-- Synonymous with @const False@
isMark :: Char -> Bool
isMark :: Char -> Bool
isMark Char
_ = Bool
False

-- | Is the character a number
isNumber :: Char -> Bool
isNumber :: Char -> Bool
isNumber Char
c =
    Char -> Bool
isDigit Char
c
        Bool -> Bool -> Bool
|| Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
_s1
        Bool -> Bool -> Bool
|| Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
_s2
        Bool -> Bool -> Bool
|| Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
_s3
        Bool -> Bool -> Bool
|| Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
_1'4
        Bool -> Bool -> Bool
|| Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
_1'2
        Bool -> Bool -> Bool
|| Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
_3'4

-- | Is it a punctuation character
--
-- This function returns 'True' for 167 (§) and 182 (¶).
isPunctuation :: Char -> Bool
isPunctuation :: Char -> Bool
isPunctuation Char
c = Char -> Bool
isLatin1 Char
c Bool -> Bool -> Bool
&& Word8 -> Bool
W.isPunctuation (Int -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Char -> Int
ord Char
c))

-- | Is it a symbol character
--
-- This function returns 'False' for 167 (§) and 182 (¶).
isSymbol :: Char -> Bool
isSymbol :: Char -> Bool
isSymbol Char
c = Char -> Bool
isLatin1 Char
c Bool -> Bool -> Bool
&& Word8 -> Bool
W.isSymbol (Int -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Char -> Int
ord Char
c))

-- | Is it a (non-breaking) space
isSeparator :: Char -> Bool
isSeparator :: Char -> Bool
isSeparator Char
c =
    Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
_space
        Bool -> Bool -> Bool
|| Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
_nbsp

----------------------------------------------------------------

-- | Is the character in the ASCII range
isAscii :: Char -> Bool
isAscii :: Char -> Bool
isAscii Char
c = Char
c Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
<= Char
'\x7f'

-- | Is the character in the Latin-1 range
isLatin1 :: Char -> Bool
isLatin1 :: Char -> Bool
isLatin1 Char
c = Char
c Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
<= Char
'\xff'

-- | Is the character an upper case ASCII letter (@A-Z@)
isAsciiUpper :: Char -> Bool
isAsciiUpper :: Char -> Bool
isAsciiUpper Char
c = Char
'A' Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
<= Char
c Bool -> Bool -> Bool
&& Char
c Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
<= Char
'Z'

-- | Is the character a lower case ASCII letter (@a-z@)
isAsciiLower :: Char -> Bool
isAsciiLower :: Char -> Bool
isAsciiLower Char
c = Char
'a' Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
<= Char
c Bool -> Bool -> Bool
&& Char
c Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
<= Char
'z'

----------------------------------------------------------------

-- | Changes the character to the upper case variant, if possible.
--
-- Micro sign/mu (µ) and small letter Y with diaeresis (ÿ) remain the same.
toUpper :: Char -> Char
toUpper :: Char -> Char
toUpper c :: Char
c@(C# Char#
c#)
    | Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
_germandbls = Char
c
    | Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
_ydieresis = Char
c
    | Char -> Bool
isLower' Char
c = Char# -> Char
C# (Int# -> Char#
chr# (Char# -> Int#
ord# Char#
c# Int# -> Int# -> Int#
-# Int#
32#))
    | Bool
otherwise = Char
c

-- | Changes the character to the lower case variant, if possible.
toLower :: Char -> Char
toLower :: Char -> Char
toLower c :: Char
c@(C# Char#
c#)
    | Char -> Bool
isUpper Char
c = Char# -> Char
C# (Int# -> Char#
chr# (Char# -> Int#
ord# Char#
c# Int# -> Int# -> Int#
+# Int#
32#))
    | Bool
otherwise = Char
c

-- | Synonym for 'toUpper'
toTitle :: Char -> Char
toTitle :: Char -> Char
toTitle = Char -> Char
toUpper

----------------------------------------------------------------

_nul, _tab, _lf, _vt, _np, _cr :: Char
_nul :: Char
_nul = Char
'\x00'
_tab :: Char
_tab = Char
'\x09'
_lf :: Char
_lf = Char
'\x0a'
_vt :: Char
_vt = Char
'\x0b'
_np :: Char
_np = Char
'\x0c'
_cr :: Char
_cr = Char
'\x0d'

_space, _tilde, _del, _nbsp :: Char
_space :: Char
_space = Char
'\x20'
_tilde :: Char
_tilde = Char
'\x7e'
_del :: Char
_del = Char
'\x7f'
_nbsp :: Char
_nbsp = Char
'\xa0'

_ordfeminine, _softhyphen, _mu, _ordmasculine :: Char
_ordfeminine :: Char
_ordfeminine = Char
'\xaa'
_softhyphen :: Char
_softhyphen = Char
'\xad'
_mu :: Char
_mu = Char
'\xb5'
_ordmasculine :: Char
_ordmasculine = Char
'\xba'

_s2, _s3, _s1, _1'4, _1'2, _3'4 :: Char
_s2 :: Char
_s2 = Char
'\xb2'
_s3 :: Char
_s3 = Char
'\xb3'
_s1 :: Char
_s1 = Char
'\xb9'
_1'4 :: Char
_1'4 = Char
'\xbc'
_1'2 :: Char
_1'2 = Char
'\xbd'
_3'4 :: Char
_3'4 = Char
'\xbe'

_Agrave, _Thorn :: Char
_Agrave :: Char
_Agrave = Char
'\xc0'
_Thorn :: Char
_Thorn = Char
'\xde'

_germandbls, _ydieresis :: Char
_germandbls :: Char
_germandbls = Char
'\xdf'
_ydieresis :: Char
_ydieresis = Char
'\xff'