module Trivialini
(
readIniFile
, readIniFileStrings
, Ini(..)
, toStringMap
) where
import Trivialini.SafeTypes
import Data.Map (Map, fromList, assocs, mapKeys)
import Data.List
import Data.Maybe
import Text.ParserCombinators.ReadP
import Control.Monad
readIniFile :: FilePath -> IO Ini
readIniFile :: String -> IO Ini
readIniFile = (String -> Ini) -> IO String -> IO Ini
forall a b. (a -> b) -> IO a -> IO b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap String -> Ini
forall a. Read a => String -> a
read (IO String -> IO Ini) -> (String -> IO String) -> String -> IO Ini
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> IO String
readFile
readIniFileStrings :: FilePath -> IO (Map String (Map String String))
readIniFileStrings :: String -> IO (Map String (Map String String))
readIniFileStrings = (String -> Map String (Map String String))
-> IO String -> IO (Map String (Map String String))
forall a b. (a -> b) -> IO a -> IO b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Ini -> Map String (Map String String)
toStringMap (Ini -> Map String (Map String String))
-> (String -> Ini) -> String -> Map String (Map String String)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Ini
forall a. Read a => String -> a
read) (IO String -> IO (Map String (Map String String)))
-> (String -> IO String)
-> String
-> IO (Map String (Map String String))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> IO String
readFile
newtype Ini = Ini { Ini -> Map IniHeading (Map IniKey IniValue)
sections :: Map IniHeading (Map IniKey IniValue) }
deriving
( Ini -> Ini -> Bool
(Ini -> Ini -> Bool) -> (Ini -> Ini -> Bool) -> Eq Ini
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Ini -> Ini -> Bool
== :: Ini -> Ini -> Bool
$c/= :: Ini -> Ini -> Bool
/= :: Ini -> Ini -> Bool
Eq
)
instance Show Ini where
show :: Ini -> String
show = [String] -> String
unlines ([String] -> String) -> (Ini -> [String]) -> Ini -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((IniHeading, Map IniKey IniValue) -> String)
-> [(IniHeading, Map IniKey IniValue)] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (IniHeading, Map IniKey IniValue) -> String
section ([(IniHeading, Map IniKey IniValue)] -> [String])
-> (Ini -> [(IniHeading, Map IniKey IniValue)]) -> Ini -> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Map IniHeading (Map IniKey IniValue)
-> [(IniHeading, Map IniKey IniValue)]
forall k a. Map k a -> [(k, a)]
assocs (Map IniHeading (Map IniKey IniValue)
-> [(IniHeading, Map IniKey IniValue)])
-> (Ini -> Map IniHeading (Map IniKey IniValue))
-> Ini
-> [(IniHeading, Map IniKey IniValue)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Ini -> Map IniHeading (Map IniKey IniValue)
sections
where section :: (IniHeading, Map IniKey IniValue) -> String
section (IniHeading
name, Map IniKey IniValue
sec) = String
"[" String -> ShowS
forall a. [a] -> [a] -> [a]
++ IniHeading -> String
getHeading IniHeading
name String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"]\n" String -> ShowS
forall a. [a] -> [a] -> [a]
++ Map IniKey IniValue -> String
pairs Map IniKey IniValue
sec
pairs :: Map IniKey IniValue -> String
pairs = [String] -> String
unlines ([String] -> String)
-> (Map IniKey IniValue -> [String])
-> Map IniKey IniValue
-> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((IniKey, IniValue) -> String) -> [(IniKey, IniValue)] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (IniKey, IniValue) -> String
pair ([(IniKey, IniValue)] -> [String])
-> (Map IniKey IniValue -> [(IniKey, IniValue)])
-> Map IniKey IniValue
-> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Map IniKey IniValue -> [(IniKey, IniValue)]
forall k a. Map k a -> [(k, a)]
assocs
pair :: (IniKey, IniValue) -> String
pair (IniKey
k, IniValue
v) = IniKey -> String
getKey IniKey
k String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" = " String -> ShowS
forall a. [a] -> [a] -> [a]
++ IniValue -> String
getValue IniValue
v
instance Read Ini where
readsPrec :: Int -> ReadS Ini
readsPrec Int
_ = ReadP Ini -> ReadS Ini
forall a. ReadP a -> ReadS a
readP_to_S ReadP Ini
parser
where parser :: ReadP Ini
parser = Map IniHeading (Map IniKey IniValue) -> Ini
Ini (Map IniHeading (Map IniKey IniValue) -> Ini)
-> ([(IniHeading, Map IniKey IniValue)]
-> Map IniHeading (Map IniKey IniValue))
-> [(IniHeading, Map IniKey IniValue)]
-> Ini
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [(IniHeading, Map IniKey IniValue)]
-> Map IniHeading (Map IniKey IniValue)
forall k a. Ord k => [(k, a)] -> Map k a
fromList ([(IniHeading, Map IniKey IniValue)] -> Ini)
-> ReadP [(IniHeading, Map IniKey IniValue)] -> ReadP Ini
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ReadP (IniHeading, Map IniKey IniValue)
-> ReadP [(IniHeading, Map IniKey IniValue)]
forall a. ReadP a -> ReadP [a]
many ReadP (IniHeading, Map IniKey IniValue)
section
section :: ReadP (IniHeading, Map IniKey IniValue)
section = do String
name <- ShowS
trim ShowS -> ReadP String -> ReadP String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ReadP Char -> ReadP String -> ReadP String -> ReadP String
forall open close a.
ReadP open -> ReadP close -> ReadP a -> ReadP a
between (Char -> ReadP Char
char Char
'[') (Char -> ReadP Char
char Char
']' ReadP Char -> ReadP String -> ReadP String
forall a b. ReadP a -> ReadP b -> ReadP b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> ReadP String
nls) (String -> ReadP String
no String
"=\n]")
Bool -> ReadP ()
forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Bool -> ReadP ()) -> Bool -> ReadP ()
forall a b. (a -> b) -> a -> b
$ String -> Bool
isValidHeading String
name
[(IniKey, IniValue)]
pairs <- ReadP (IniKey, IniValue) -> ReadP [(IniKey, IniValue)]
forall a. ReadP a -> ReadP [a]
many ReadP (IniKey, IniValue)
pair
(IniHeading, Map IniKey IniValue)
-> ReadP (IniHeading, Map IniKey IniValue)
forall a. a -> ReadP a
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe IniHeading -> IniHeading
forall a. HasCallStack => Maybe a -> a
fromJust (String -> Maybe IniHeading
mkHdg String
name), [(IniKey, IniValue)] -> Map IniKey IniValue
forall k a. Ord k => [(k, a)] -> Map k a
fromList [(IniKey, IniValue)]
pairs)
pair :: ReadP (IniKey, IniValue)
pair = do String
key <- ShowS
trim ShowS -> ReadP String -> ReadP String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> String -> ReadP String
no String
"\n[="
String
val <- ShowS
trim ShowS -> ReadP String -> ReadP String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ReadP Char -> ReadP String -> ReadP String -> ReadP String
forall open close a.
ReadP open -> ReadP close -> ReadP a -> ReadP a
between (Char -> ReadP Char
char Char
'=') ReadP String
nls (String -> ReadP String
no String
"\n")
Bool -> ReadP ()
forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Bool -> ReadP ()) -> Bool -> ReadP ()
forall a b. (a -> b) -> a -> b
$ String -> Bool
isValidKey String
key Bool -> Bool -> Bool
&& String -> Bool
isValidValue String
val
(IniKey, IniValue) -> ReadP (IniKey, IniValue)
forall a. a -> ReadP a
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe IniKey -> IniKey
forall a. HasCallStack => Maybe a -> a
fromJust (String -> Maybe IniKey
mkKey String
key), Maybe IniValue -> IniValue
forall a. HasCallStack => Maybe a -> a
fromJust (String -> Maybe IniValue
mkVal String
val))
nls :: ReadP String
nls = (Char -> Bool) -> ReadP String
munch1 (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
==Char
'\n')
no :: String -> ReadP String
no = (Char -> Bool) -> ReadP String
munch1 ((Char -> Bool) -> ReadP String)
-> (String -> Char -> Bool) -> String -> ReadP String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Char -> String -> Bool) -> String -> Char -> Bool
forall a b c. (a -> b -> c) -> b -> a -> c
flip Char -> String -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
notElem
trim :: ShowS
trim = (Char -> Bool) -> ShowS
forall a. (a -> Bool) -> [a] -> [a]
dropWhile (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
==Char
' ') ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Char -> Bool) -> ShowS
forall a. (a -> Bool) -> [a] -> [a]
dropWhileEnd (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
==Char
' ')
toStringMap :: Ini -> Map String (Map String String)
toStringMap :: Ini -> Map String (Map String String)
toStringMap = (IniHeading -> String)
-> Map IniHeading (Map String String)
-> Map String (Map String String)
forall k2 k1 a. Ord k2 => (k1 -> k2) -> Map k1 a -> Map k2 a
mapKeys IniHeading -> String
getHeading (Map IniHeading (Map String String)
-> Map String (Map String String))
-> (Ini -> Map IniHeading (Map String String))
-> Ini
-> Map String (Map String String)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Map IniKey IniValue -> Map String String)
-> Map IniHeading (Map IniKey IniValue)
-> Map IniHeading (Map String String)
forall a b. (a -> b) -> Map IniHeading a -> Map IniHeading b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Map IniKey IniValue -> Map String String
sectionToStringMap (Map IniHeading (Map IniKey IniValue)
-> Map IniHeading (Map String String))
-> (Ini -> Map IniHeading (Map IniKey IniValue))
-> Ini
-> Map IniHeading (Map String String)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Ini -> Map IniHeading (Map IniKey IniValue)
sections
where sectionToStringMap :: Map IniKey IniValue -> Map String String
sectionToStringMap = (IniKey -> String) -> Map IniKey String -> Map String String
forall k2 k1 a. Ord k2 => (k1 -> k2) -> Map k1 a -> Map k2 a
mapKeys IniKey -> String
getKey (Map IniKey String -> Map String String)
-> (Map IniKey IniValue -> Map IniKey String)
-> Map IniKey IniValue
-> Map String String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (IniValue -> String) -> Map IniKey IniValue -> Map IniKey String
forall a b. (a -> b) -> Map IniKey a -> Map IniKey b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap IniValue -> String
getValue