ini (empty) → 0.0.0
raw patch · 4 files changed
+169/−0 lines, 4 filesdep +aesondep +attoparsecdep +basesetup-changed
Dependencies added: aeson, attoparsec, base, text, unordered-containers
Files
- LICENSE +24/−0
- Setup.hs +2/−0
- ini.cabal +23/−0
- src/Data/Ini.hs +120/−0
+ LICENSE view
@@ -0,0 +1,24 @@+Copyright (c) 2013, ini+All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:+ * Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.+ * Redistributions in binary form must reproduce the above copyright+ notice, this list of conditions and the following disclaimer in the+ documentation and/or other materials provided with the distribution.+ * Neither the name of ini nor the+ names of its contributors may be used to endorse or promote products+ derived from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE+DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ ini.cabal view
@@ -0,0 +1,23 @@+name: ini+version: 0.0.0+synopsis: Quick and easy configuration files in the INI format.+description: Simple, easy and fast configuration files in the INI format.+license: BSD3+license-file: LICENSE+author: Chris Done+maintainer: chrisdone@gmail.com+copyright: 2013 Chris Done+category: Data, Configuration+build-type: Simple+cabal-version: >=1.8++library+ hs-source-dirs: src/+ ghc-options: -Wall -O2+ extensions: OverloadedStrings+ exposed-modules: Data.Ini+ build-depends: base >= 4 && <5,+ attoparsec,+ text,+ aeson,+ unordered-containers
+ src/Data/Ini.hs view
@@ -0,0 +1,120 @@+-- | Clean configuration files in the INI format.+--+-- Format rules and recommendations:+--+-- * The @: @ syntax is space-sensitive.+--+-- * Keys are case-sensitive.+--+-- * Lower-case is recommended.+--+-- * Values can be empty.+--+-- * Keys cannot contain @:@, @=@, @[@, or @]@.+--+-- * Comments are not supported at this time.+--+-- An example configuration file:+--+-- @+-- [SERVER]+-- port=6667+-- hostname=localhost+-- [AUTH]+-- user: hello+-- pass: world+-- salt:+-- @+--+-- Parsing example:+--+-- >>> parseIni "[SERVER]\nport: 6667\nhostname: localhost"+-- Right (Ini {unIni = fromList [("SERVER",fromList [("hostname","localhost"),("port","6667")])]})+--++module Data.Ini+ (-- * Reading+ parseIniFile+ ,parseIni+ -- * Writing+ ,writeIniFile+ ,printIni+ -- * Types+ ,Ini(..)+ -- * Parsers+ ,iniParser+ ,sectionParser+ ,keyValueParser+ )+ where++import Control.Monad+import Data.Attoparsec.Combinator+import Data.Attoparsec.Text+import Data.Char+import Data.HashMap.Strict (HashMap)+import qualified Data.HashMap.Strict as M+import Data.Monoid+import Data.Text (Text)+import qualified Data.Text as T+import qualified Data.Text.IO as T+import Prelude hiding (takeWhile)++-- | An INI configuration.+newtype Ini = Ini { unIni :: HashMap Text (HashMap Text Text) }+ deriving (Show)++-- | Parse an INI file.+parseIniFile :: FilePath -> IO (Either String Ini)+parseIniFile = fmap parseIni . T.readFile++-- | Parse an INI config.+parseIni :: Text -> Either String Ini+parseIni = parseOnly iniParser++-- | Print the INI config to a file.+writeIniFile :: FilePath -> Ini -> IO ()+writeIniFile fp = T.writeFile fp . printIni++-- | Print an INI config.+printIni :: Ini -> Text+printIni (Ini sections) =+ T.concat (map buildSection (M.toList sections))+ where buildSection (name,pairs) =+ "[" <> name <> "]\n" <>+ T.concat (map buildPair (M.toList pairs))+ buildPair (name,value) =+ name <> ": " <> value++-- | Parser for an INI.+iniParser :: Parser Ini+iniParser = fmap Ini (fmap M.fromList (many1 sectionParser))++-- | A section. Format: @[foo]@. Conventionally, @[FOO]@.+sectionParser :: Parser (Text,HashMap Text Text)+sectionParser =+ do char '['+ name <- takeWhile (\c -> c /=']' && c /= '[')+ char ']'+ skipEndOfLine+ values <- many1 keyValueParser+ return (name,M.fromList values)++-- | A key-value pair. Either @foo: bar@ or @foo=bar@.+keyValueParser :: Parser (Text,Text)+keyValueParser =+ do key <- takeWhile1 (\c -> not (isDelim c || c == '[' || c == ']'))+ delim <- satisfy isDelim+ value <- fmap (clean delim) (takeWhile (not . isEndOfLine))+ skipEndOfLine+ return (key,value)+ where clean ':' = T.drop 1+ clean _ = id++-- | Is the given character a delimiter?+isDelim :: Char -> Bool+isDelim x = x == '=' || x == ':'++-- | Skip end of line and whitespace beyond.+skipEndOfLine :: Parser ()+skipEndOfLine = skipWhile (\c -> isEndOfLine c || isSpace c)