    {-# LANGUAGE CPP #-}

    module System.Environment.XDG.BaseDir
        ( getUserDataDir
        , getUserDataFile
        , getUserConfigDir
        , getUserConfigFile
        , getUserCacheDir
        , getUserCacheFile
        , getSystemDataDirs
        , getSystemDataFiles
        , getSystemConfigDirs
        , getSystemConfigFiles
        , getAllDataDirs
        , getAllDataFiles
        , getAllConfigDirs
        , getAllConfigFiles
        ) where

    import Data.Maybe         ( fromMaybe )
    import System.FilePath    ( (</>), splitSearchPath )
    import System.Environment ( getEnvironment, getEnv )
    import Control.Exception    ( try )
    import System.Directory   ( getHomeDirectory )
    import Control.Monad      ( liftM2 )

    #if defined(mingw32_HOST_OS) || defined(__MINGW32__)

    getDefault "XDG_DATA_HOME"   = getEnv "AppData"
    getDefault "XDG_CONFIG_HOME" = userRelative $ "Local Settings"
    getDefault "XDG_CACHE_HOME"  = userRelative $ "Local Settings" </> "Cache"
    getDefault "XDG_DATA_DIRS"   = getEnv "ProgramFiles"
    getDefault "XDG_CONFIG_DIRS" = getEnv "ProgramFiles"
    getDefault _                 = return ""

    #else

    getDefault :: [Char] -> IO [Char]
    getDefault "XDG_DATA_HOME"   = [Char] -> IO [Char]
    userRelative ([Char] -> IO [Char]) -> [Char] -> IO [Char]
    forall a b. (a -> b) -> a -> b
    $ ".local" [Char] -> [Char] -> [Char]
    </> "share"
    getDefault "XDG_CONFIG_HOME" = [Char] -> IO [Char]
    userRelative ([Char] -> IO [Char]) -> [Char] -> IO [Char]
    forall a b. (a -> b) -> a -> b
    $ ".config"
    getDefault "XDG_CACHE_HOME"  = [Char] -> IO [Char]
    userRelative ([Char] -> IO [Char]) -> [Char] -> IO [Char]
    forall a b. (a -> b) -> a -> b
    $ ".cache"
    getDefault "XDG_DATA_DIRS"   = [Char] -> IO [Char]
    forall (m :: * -> *) a. Monad m => a -> m a
    return ([Char] -> IO [Char]) -> [Char] -> IO [Char]
    forall a b. (a -> b) -> a -> b
    $ "/usr/local/share:/usr/share"
    getDefault "XDG_CONFIG_DIRS" = [Char] -> IO [Char]
    forall (m :: * -> *) a. Monad m => a -> m a
    return ([Char] -> IO [Char]) -> [Char] -> IO [Char]
    forall a b. (a -> b) -> a -> b
    $ "/etc/xdg"
    getDefault _                 = [Char] -> IO [Char]
    forall (m :: * -> *) a. Monad m => a -> m a
    return ([Char] -> IO [Char]) -> [Char] -> IO [Char]
    forall a b. (a -> b) -> a -> b
    $ ""

    #endif

    -- | Get the directory for user-specific data files.
    getUserDataDir      :: String -> IO FilePath
    getUserDataDir :: [Char] -> IO [Char]
    getUserDataDir      = [Char] -> [Char] -> IO [Char]
    singleDir "XDG_DATA_HOME"
    -- | Get the directory for user-specific configuration files.
    getUserConfigDir    :: String -> IO FilePath
    getUserConfigDir :: [Char] -> IO [Char]
    getUserConfigDir    = [Char] -> [Char] -> IO [Char]
    singleDir "XDG_CONFIG_HOME"
    -- | Get the directory for user-specific cache files.
    getUserCacheDir     :: String -> IO FilePath
    getUserCacheDir :: [Char] -> IO [Char]
    getUserCacheDir     = [Char] -> [Char] -> IO [Char]
    singleDir "XDG_CACHE_HOME"
    -- | Get a list of the system-wide data directories.
    getSystemDataDirs   :: String -> IO [FilePath]
    getSystemDataDirs :: [Char] -> IO [[Char]]
    getSystemDataDirs   = [Char] -> [Char] -> IO [[Char]]
    multiDirs "XDG_DATA_DIRS"
    -- | Get a list of the system-wide configuration directories.
    getSystemConfigDirs :: String -> IO [FilePath]
    getSystemConfigDirs :: [Char] -> IO [[Char]]
    getSystemConfigDirs = [Char] -> [Char] -> IO [[Char]]
    multiDirs "XDG_CONFIG_DIRS"
    -- | Get a list of all data directories.
    getAllDataDirs      :: String -> IO [FilePath]
    getAllDataDirs :: [Char] -> IO [[Char]]
    getAllDataDirs a :: [Char]
    a    = ([Char] -> [[Char]] -> [[Char]])
    -> IO [Char] -> IO [[Char]] -> IO [[Char]]
    forall (m :: * -> *) a1 a2 r.
    Monad m =>
    (a1 -> a2 -> r) -> m a1 -> m a2 -> m r
    liftM2 (:) ([Char] -> IO [Char]
    getUserDataDir [Char]
    a) ([Char] -> IO [[Char]]
    getSystemDataDirs [Char]
    a)
    -- | Get a list of all configuration directories.
    getAllConfigDirs    :: String -> IO [FilePath]
    getAllConfigDirs :: [Char] -> IO [[Char]]
    getAllConfigDirs a :: [Char]
    a  = ([Char] -> [[Char]] -> [[Char]])
    -> IO [Char] -> IO [[Char]] -> IO [[Char]]
    forall (m :: * -> *) a1 a2 r.
    Monad m =>
    (a1 -> a2 -> r) -> m a1 -> m a2 -> m r
    liftM2 (:) ([Char] -> IO [Char]
    getUserConfigDir [Char]
    a) ([Char] -> IO [[Char]]
    getSystemConfigDirs [Char]
    a)
    -- | Get the path to a specific user data file.
    getUserDataFile          :: String -> String -> IO FilePath
    getUserDataFile :: [Char] -> [Char] -> IO [Char]
    getUserDataFile a :: [Char]
    a f :: [Char]
    f      = ([Char] -> [Char]) -> IO [Char] -> IO [Char]
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap ([Char] -> [Char] -> [Char]
    </> [Char]
    f) (IO [Char] -> IO [Char]) -> IO [Char] -> IO [Char]
    forall a b. (a -> b) -> a -> b
    $ [Char] -> IO [Char]
    getUserDataDir [Char]
    a
    -- | Get the path to a specific user configuration file.
    getUserConfigFile        :: String -> String -> IO FilePath
    getUserConfigFile :: [Char] -> [Char] -> IO [Char]
    getUserConfigFile a :: [Char]
    a f :: [Char]
    f    = ([Char] -> [Char]) -> IO [Char] -> IO [Char]
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap ([Char] -> [Char] -> [Char]
    </> [Char]
    f) (IO [Char] -> IO [Char]) -> IO [Char] -> IO [Char]
    forall a b. (a -> b) -> a -> b
    $ [Char] -> IO [Char]
    getUserConfigDir [Char]
    a
    -- | Get the path to a specific user cache file.
    getUserCacheFile         :: String -> String -> IO FilePath
    getUserCacheFile :: [Char] -> [Char] -> IO [Char]
    getUserCacheFile a :: [Char]
    a f :: [Char]
    f     = ([Char] -> [Char]) -> IO [Char] -> IO [Char]
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap ([Char] -> [Char] -> [Char]
    </> [Char]
    f) (IO [Char] -> IO [Char]) -> IO [Char] -> IO [Char]
    forall a b. (a -> b) -> a -> b
    $ [Char] -> IO [Char]
    getUserCacheDir [Char]
    a
    -- | Get a list of all paths for a specific system data file.
    getSystemDataFiles       :: String -> String -> IO [FilePath]
    getSystemDataFiles :: [Char] -> [Char] -> IO [[Char]]
    getSystemDataFiles a :: [Char]
    a f :: [Char]
    f   = ([[Char]] -> [[Char]]) -> IO [[Char]] -> IO [[Char]]
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap (([Char] -> [Char]) -> [[Char]] -> [[Char]]
    forall a b. (a -> b) -> [a] -> [b]
    map ([Char] -> [Char] -> [Char]
    </> [Char]
    f)) (IO [[Char]] -> IO [[Char]]) -> IO [[Char]] -> IO [[Char]]
    forall a b. (a -> b) -> a -> b
    $ [Char] -> IO [[Char]]
    getSystemDataDirs [Char]
    a
    -- | Get a list of all paths for a specific system configuration file.
    getSystemConfigFiles     :: String -> String -> IO [FilePath]
    getSystemConfigFiles :: [Char] -> [Char] -> IO [[Char]]
    getSystemConfigFiles a :: [Char]
    a f :: [Char]
    f = ([[Char]] -> [[Char]]) -> IO [[Char]] -> IO [[Char]]
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap (([Char] -> [Char]) -> [[Char]] -> [[Char]]
    forall a b. (a -> b) -> [a] -> [b]
    map ([Char] -> [Char] -> [Char]
    </> [Char]
    f)) (IO [[Char]] -> IO [[Char]]) -> IO [[Char]] -> IO [[Char]]
    forall a b. (a -> b) -> a -> b
    $ [Char] -> IO [[Char]]
    getSystemConfigDirs [Char]
    a
    -- | Get a list of all paths for a specific data file.
    getAllDataFiles          :: String -> String -> IO [FilePath]
    getAllDataFiles :: [Char] -> [Char] -> IO [[Char]]
    getAllDataFiles a :: [Char]
    a f :: [Char]
    f      = ([[Char]] -> [[Char]]) -> IO [[Char]] -> IO [[Char]]
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap (([Char] -> [Char]) -> [[Char]] -> [[Char]]
    forall a b. (a -> b) -> [a] -> [b]
    map ([Char] -> [Char] -> [Char]
    </> [Char]
    f)) (IO [[Char]] -> IO [[Char]]) -> IO [[Char]] -> IO [[Char]]
    forall a b. (a -> b) -> a -> b
    $ [Char] -> IO [[Char]]
    getAllDataDirs [Char]
    a
    -- | Get a list of all paths for a specific configuration file.
    getAllConfigFiles        :: String -> String -> IO [FilePath]
    getAllConfigFiles :: [Char] -> [Char] -> IO [[Char]]
    getAllConfigFiles a :: [Char]
    a f :: [Char]
    f    = ([[Char]] -> [[Char]]) -> IO [[Char]] -> IO [[Char]]
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap (([Char] -> [Char]) -> [[Char]] -> [[Char]]
    forall a b. (a -> b) -> [a] -> [b]
    map ([Char] -> [Char] -> [Char]
    </> [Char]
    f)) (IO [[Char]] -> IO [[Char]]) -> IO [[Char]] -> IO [[Char]]
    forall a b. (a -> b) -> a -> b
    $ [Char] -> IO [[Char]]
    getAllConfigDirs [Char]
    a

    singleDir :: String -> String -> IO FilePath
    singleDir :: [Char] -> [Char] -> IO [Char]
    singleDir key :: [Char]
    key app :: [Char]
    app = [Char] -> IO [Char]
    envLookup [Char]
    key IO [Char] -> ([Char] -> IO [Char]) -> IO [Char]
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
    >>= [Char] -> IO [Char]
    forall (m :: * -> *) a. Monad m => a -> m a
    return ([Char] -> IO [Char]) -> ([Char] -> [Char]) -> [Char] -> IO [Char]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . ([Char] -> [Char] -> [Char]
    </> [Char]
    app)

    multiDirs :: String -> String -> IO [FilePath]
    multiDirs :: [Char] -> [Char] -> IO [[Char]]
    multiDirs key :: [Char]
    key app :: [Char]
    app = [Char] -> IO [Char]
    envLookup [Char]
    key IO [Char] -> ([Char] -> IO [[Char]]) -> IO [[Char]]
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
    >>= [[Char]] -> IO [[Char]]
    forall (m :: * -> *) a. Monad m => a -> m a
    return ([[Char]] -> IO [[Char]])
    -> ([Char] -> [[Char]]) -> [Char] -> IO [[Char]]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . ([Char] -> [Char]) -> [[Char]] -> [[Char]]
    forall a b. (a -> b) -> [a] -> [b]
    map ([Char] -> [Char] -> [Char]
    </> [Char]
    app) ([[Char]] -> [[Char]])
    -> ([Char] -> [[Char]]) -> [Char] -> [[Char]]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . [Char] -> [[Char]]
    splitSearchPath

    envLookup :: String -> IO String
    envLookup :: [Char] -> IO [Char]
    envLookup key :: [Char]
    key = do [([Char], [Char])]
    env <- IO [([Char], [Char])]
    getEnvironment
                       case [Char] -> [([Char], [Char])] -> Maybe [Char]
    forall a b. Eq a => a -> [(a, b)] -> Maybe b
    lookup [Char]
    key [([Char], [Char])]
    env of
                            Just val :: [Char]
    val -> [Char] -> IO [Char]
    forall (m :: * -> *) a. Monad m => a -> m a
    return [Char]
    val
                            Nothing  -> [Char] -> IO [Char]
    getDefault [Char]
    key

    userRelative :: FilePath -> IO FilePath
    userRelative :: [Char] -> IO [Char]
    userRelative p :: [Char]
    p = IO [Char]
    getHomeDirectory IO [Char] -> ([Char] -> IO [Char]) -> IO [Char]
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
    >>= [Char] -> IO [Char]
    forall (m :: * -> *) a. Monad m => a -> m a
    return ([Char] -> IO [Char]) -> ([Char] -> [Char]) -> [Char] -> IO [Char]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . ([Char] -> [Char] -> [Char]
    </> [Char]
    p)