{-# 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 [Char]
"XDG_DATA_HOME"   = [Char] -> IO [Char]
userRelative ([Char] -> IO [Char]) -> [Char] -> IO [Char]
forall a b. (a -> b) -> a -> b
$ [Char]
".local" [Char] -> [Char] -> [Char]
</> [Char]
"share"
getDefault [Char]
"XDG_CONFIG_HOME" = [Char] -> IO [Char]
userRelative ([Char] -> IO [Char]) -> [Char] -> IO [Char]
forall a b. (a -> b) -> a -> b
$ [Char]
".config"
getDefault [Char]
"XDG_CACHE_HOME"  = [Char] -> IO [Char]
userRelative ([Char] -> IO [Char]) -> [Char] -> IO [Char]
forall a b. (a -> b) -> a -> b
$ [Char]
".cache"
getDefault [Char]
"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
$ [Char]
"/usr/local/share:/usr/share"
getDefault [Char]
"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
$ [Char]
"/etc/xdg"
getDefault [Char]
_                 = [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
$ [Char]
""

#endif

-- | Get the directory for user-specific data files.
getUserDataDir      :: String -> IO FilePath
getUserDataDir :: [Char] -> IO [Char]
getUserDataDir      = [Char] -> [Char] -> IO [Char]
singleDir [Char]
"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 [Char]
"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 [Char]
"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 [Char]
"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 [Char]
"XDG_CONFIG_DIRS"
-- | Get a list of all data directories.
getAllDataDirs      :: String -> IO [FilePath]
getAllDataDirs :: [Char] -> IO [[Char]]
getAllDataDirs [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 [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 [Char]
a [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 [Char]
a [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 [Char]
a [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 [Char]
a [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 [Char]
a [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 [Char]
a [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 [Char]
a [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 [Char]
key [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 [Char]
key [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 [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 [Char]
val -> [Char] -> IO [Char]
forall (m :: * -> *) a. Monad m => a -> m a
return [Char]
val
                        Maybe [Char]
Nothing  -> [Char] -> IO [Char]
getDefault [Char]
key

userRelative :: FilePath -> IO FilePath
userRelative :: [Char] -> IO [Char]
userRelative [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)