{-# LINE 1 "System/Locale/SetLocale.hsc" #-}
{-# LANGUAGE ForeignFunctionInterface #-}
{-# LINE 2 "System/Locale/SetLocale.hsc" #-}

module System.Locale.SetLocale (
    Category(..),
    categoryToCInt,
    setLocale
) where

import Foreign.Ptr
import Foreign.C.Types
import Foreign.C.String

import Data.Typeable

-- | A type representing the various locale categories. See @man 7 locale@.
data Category
    = LC_ALL
    | LC_COLLATE
    | LC_CTYPE
    | LC_MESSAGES
    | LC_MONETARY
    | LC_NUMERIC
    | LC_TIME
    deriving (Eq, Ord, Read, Show, Enum, Bounded)

instance Typeable Category where
    typeOf _ = mkTyConApp (mkTyCon "System.Locale.SetLocale.Category") []


{-# LINE 30 "System/Locale/SetLocale.hsc" #-}

-- | Convert a 'Category' to the corresponding system-specific @LC_*@ code.
-- You probably don't need this function.
categoryToCInt :: Category -> CInt
categoryToCInt LC_ALL = 6
{-# LINE 35 "System/Locale/SetLocale.hsc" #-}
categoryToCInt LC_COLLATE = 3
{-# LINE 36 "System/Locale/SetLocale.hsc" #-}
categoryToCInt LC_CTYPE = 0
{-# LINE 37 "System/Locale/SetLocale.hsc" #-}
categoryToCInt LC_MESSAGES = 5
{-# LINE 38 "System/Locale/SetLocale.hsc" #-}
categoryToCInt LC_MONETARY = 4
{-# LINE 39 "System/Locale/SetLocale.hsc" #-}
categoryToCInt LC_NUMERIC = 1
{-# LINE 40 "System/Locale/SetLocale.hsc" #-}
categoryToCInt LC_TIME = 2
{-# LINE 41 "System/Locale/SetLocale.hsc" #-}

ptr2str :: Ptr CChar -> IO (Maybe String)
ptr2str p
    | p == nullPtr = return Nothing
    | otherwise = fmap Just $ peekCString p

str2ptr :: Maybe String -> (Ptr CChar -> IO a) -> IO a
str2ptr Nothing  f = f nullPtr
str2ptr (Just s) f = withCString s f

foreign import ccall unsafe "locale.h setlocale" c_setlocale :: CInt -> Ptr CChar -> IO (Ptr CChar)

-- | A Haskell version of @setlocale()@. See @man 3 setlocale@.
setLocale :: Category -> Maybe String -> IO (Maybe String)
setLocale cat str =
    str2ptr str $ \p -> c_setlocale (categoryToCInt cat) p >>= ptr2str