-- Module : Data.TConfig -- Copyright : (c) Anthony Simpson 2009 -- License : see LICENSE -- -- Maintainer : DiscipleRayne@gmail.com -- Stability : Semi-stable -- Portability : portable --------------------------------------------------- {-| A small and simple text file configuration library written in Haskell. It is similar to the INI file format, but lacks a few of it's features, such as sections which will be added eventually. It is suitable for simple games that need to keep track of certain information between plays. -} module Data.TConfig ( Configuration , getValue , repConfig , readConfig , writeConfig , remKey , addKey ) where import IO import Data.List import Data.Char type Key = String type Value = String -- |The 'Configuration' type takes a key and a value, -- and returns a Configuration type. data Configuration = Config { key :: Key , value :: Value } deriving (Show,Eq) -- |Adds a key and value to the end of the Configuration. addKey :: Key -> Value -> [Configuration] -> [Configuration] addKey k v conf = Config k (addQuotes v) : conf -- |Utility function. -- Removes a key and it's value from the configuration. remKey :: Key -> [Configuration] -> [Configuration] remKey k xs = foldl' step [] xs where step ys y | key y == k = ys | otherwise = y : ys -- |Utility function. Searches a Configuration for a -- key, and returns it's value. getValue :: Key -> [Configuration] -> Maybe Value getValue s (x:xs) | key x == s = Just $ stripQuotes $ value x | otherwise = getValue s xs where stripQuotes a |any isSpace a = filter (not .(== '\"')) a getValue _ [] = Nothing -- |Returns a String with quotes of it contains spaces, -- otherwise returns the string untouched. addQuotes :: String -> String addQuotes x = if any isSpace x then "\"" ++ x ++ "\"" else x -- |Utility function. Replaces the value for a key in -- a Configuration. repConfig :: Key -> Value -> [Configuration] -> [Configuration] repConfig k rv xs = foldl' step [] $ reverse xs where step ds d | key d == k = Config (key d) (addQuotes rv) : ds | otherwise = d : ds addQuotes a | any isSpace a = "\"" ++ a ++ "\"" -- |Reads and parses a string from a file into a Configuration. readConfig :: FilePath -> IO [Configuration] readConfig path = do contents <- readFile path return $ parseConfig contents -- |Parses a parsed Configuration back to a file. writeConfig :: FilePath -> [Configuration] -> IO () writeConfig path con = do writeFile path $ putTogether con -- |Turns a list of configuration types back into a String -- to write to a file. putTogether :: [Configuration] -> String putTogether xs = concat $ putTogether' $ backToString xs where putTogether' (x:y:xs) = x : " = " : y : "\n" : putTogether' xs putTogether' _ = [] -- |Turns a list of configuration types into a list of Strings backToString :: [Configuration] -> [String] backToString ((Config x y):xs) = x : y : backToString xs backToString _ = [] -- |Parses a string into a list of Configuration types. parseConfig :: String -> [Configuration] parseConfig x = listConfig . popString . words $ filter (not . (== '=')) x -- |Turns a list of key value key value etc... pairs into -- A list of Configuration types. listConfig :: [String] -> [Configuration] listConfig (x:y:xs) = Config x y : listConfig xs listConfig _ = [] -- |Parses strings from the parseConfig'd file. popString :: [String] -> [String] popString [] = [] popString (x:xs) | head x == '\"' = findClose $ break (('\"' ==) . last) xs | otherwise = x : popString xs where findClose (y,ys) = [unwords $ x : y ++ [head ys]] ++ popString (tail ys)