module Game.LambdaHack.Config
( CP, mkConfig, appDataDir
, getOption, get, getItems, getFile, dump, getSetGen
) where
import System.Directory
import System.FilePath
import System.Environment
import qualified Data.ConfigFile as CF
import qualified Data.Binary as Binary
import qualified Data.Char as Char
import qualified Data.List as L
import qualified System.Random as R
newtype CP = CP CF.ConfigParser
instance Binary.Binary CP where
put (CP conf) = Binary.put $ CF.to_string conf
get = do
string <- Binary.get
let c = CF.readstring CF.emptyCP string
return $ toCP $ forceEither c
instance Show CP where
show (CP conf) = show $ CF.to_string conf
forceEither :: Show a => Either a b -> b
forceEither (Left a) = error (show a)
forceEither (Right b) = b
toCP :: CF.ConfigParser -> CP
toCP cf = CP $ cf {CF.optionxform = id}
overrideCP :: CP -> FilePath -> IO CP
overrideCP (CP defCF) cfile = do
c <- CF.readfile defCF cfile
return $ toCP $ forceEither c
mkConfig :: String -> IO CP
mkConfig configDefault = do
let delFileMarker = L.init $ L.drop 3 $ lines configDefault
delComment = L.map (L.drop 2) delFileMarker
unConfig = unlines delComment
!defCF = forceEither $ CF.readstring CF.emptyCP unConfig
!defConfig = toCP defCF
cfile <- configFile
b <- doesFileExist cfile
if not b
then return defConfig
else overrideCP defConfig cfile
appDataDir :: IO FilePath
appDataDir = do
progName <- getProgName
let name = L.takeWhile Char.isAlphaNum progName
getAppUserDataDirectory name
configFile :: IO FilePath
configFile = do
appData <- appDataDir
return $ combine appData "config"
getOption :: CF.Get_C a => CP -> CF.SectionSpec -> CF.OptionSpec -> Maybe a
getOption (CP conf) s o =
if CF.has_option conf s o
then Just $ forceEither $ CF.get conf s o
else Nothing
get :: CF.Get_C a => CP -> CF.SectionSpec -> CF.OptionSpec -> a
get (CP conf) s o =
if CF.has_option conf s o
then forceEither $ CF.get conf s o
else error $ "Unknown config option: " ++ s ++ "." ++ o
getItems :: CP -> CF.SectionSpec -> [(String, String)]
getItems (CP conf) s =
if CF.has_section conf s
then forceEither $ CF.items conf s
else error $ "Unknown config section: " ++ s
getFile :: CP -> CF.SectionSpec -> CF.OptionSpec -> IO FilePath
getFile conf s o = do
current <- getCurrentDirectory
appData <- appDataDir
let path = get conf s o
appPath = combine appData path
curPath = combine current path
b <- doesDirectoryExist appData
return $ if b then appPath else curPath
dump :: FilePath -> CP -> IO ()
dump fn (CP conf) = do
current <- getCurrentDirectory
let path = combine current fn
sdump = CF.to_string conf
writeFile path sdump
set :: CP -> CF.SectionSpec -> CF.OptionSpec -> String -> CP
set (CP conf) s o v =
if CF.has_option conf s o
then error $ "Overwritten config option: " ++ s ++ "." ++ o
else CP $ forceEither $ CF.set conf s o v
getSetGen :: CP
-> String
-> IO (R.StdGen, CP)
getSetGen config option =
case getOption config "engine" option of
Just sg -> return (read sg, config)
Nothing -> do
g <- R.newStdGen
let gs = show g
c = set config "engine" option gs
return (g, c)