module Main where import Prelude import Char ( isSpace, toLower ) import IO import IOExts ( IORef, modifyIORef, newIORef, readIORef, unsafePerformIO ) -- Bung everything inside a record, to save us multiple IORefs data Config = Config { cfgSomeSetting :: String } configRef = unsafePerformIO $ newIORef $ Config { cfgSomeSetting = "this is the default setting" } config = unsafePerformIO $ readIORef configRef -- as a shortcut / compatibility with existing code someSetting = cfgSomeSetting config -- returns lines in reverse order, I know, but it's irrelevant hGetLines h = get [] where get ls = (hGetLine h >>= get . (: ls)) `catch` (const $ return ls) -- *should* be called first thing in main (if at all); -- otherwise madness ensues... loadConfig :: FilePath -> IO () loadConfig conf = bracket (openFile conf ReadMode) hClose $ \ h -> do kvs <- fmap (map keyVal . filter isNotComment . lines) (hGetContents h) --kvs <- fmap (map keyVal . filter isNotComment) (hGetLines h) --mapM_ putStrLn kvs modifyIORef configRef (\ c -> foldl cfgLine c kvs) where keyVal s = (map toLower key, dropWhile isSpace rest) where (key, rest) = break isSpace s isNotComment ('#':_) = False isNotComment [] = False isNotComment _ = True cfgLine c ("setting", v) = c { cfgSomeSetting = v } cfgLine c _ = c -- ignore everything else main = do loadConfig "prefs.conf" local <- readIORef configRef mapM_ putStrLn [ cfgSomeSetting local, cfgSomeSetting config, someSetting ]