packages feed

mighttpd-0.3.0: Config.hs

{-# LANGUAGE TypeSynonymInstances #-}

module Config (Option(..), parseOption, defaultOption) where

import Control.Applicative ((<$>),(<$),(<*),(<*>),(*>))
import Data.List (isPrefixOf)
import Text.ParserCombinators.Parsec

----------------------------------------------------------------

defaultOption :: Option
defaultOption = Option {
    opt_port = 8080
  , opt_prefork_process_number = 20
  , opt_thread_number_per_process = 500
  , opt_connection_timer = 10
  , opt_sleep_timer = 2
  , opt_debug_mode = True
  , opt_user = "nobody"
  , opt_group = "nobody"
  , opt_syslog_facility = "local5"
  , opt_log_level = "info"
  , opt_pid_file = "/var/run/mighttpd.pid"
}

data Option = Option {
    opt_port :: Int
  , opt_prefork_process_number :: Int
  , opt_thread_number_per_process :: Int
  , opt_connection_timer :: Int
  , opt_sleep_timer :: Int
  , opt_debug_mode :: Bool
  , opt_user :: String
  , opt_group :: String
  , opt_syslog_facility :: String
  , opt_log_level :: String
  , opt_pid_file :: String
} deriving Show

----------------------------------------------------------------

parseOption :: String -> Option
parseOption = makeOpt defaultOption . parseConfig

----------------------------------------------------------------

makeOpt :: Option -> [Conf] -> Option
makeOpt def conf = Option {
    opt_port = get "Port" opt_port
  , opt_prefork_process_number = get "Prefork_Process_Number" opt_prefork_process_number
  , opt_thread_number_per_process = get "Thread_Number_Per_Process" opt_thread_number_per_process
  , opt_connection_timer = get "Connection_Timer" opt_connection_timer
  , opt_sleep_timer      = get "Sleep_Timer" opt_sleep_timer
  , opt_debug_mode       = get "Debug_Mode" opt_debug_mode
  , opt_user             = get "User" opt_user
  , opt_group            = get "Group" opt_group
  , opt_syslog_facility  = get "Syslog_Facility" opt_syslog_facility
  , opt_log_level        = get "Log_Level" opt_log_level
  , opt_pid_file         = get "Pid_File" opt_pid_file
  }
    where
      get key func = maybe (func def) fromConf $ lookup key conf

----------------------------------------------------------------

type Conf = (String, ConfValue)

data ConfValue = CV_Int Int | CV_Bool Bool | CV_String String deriving Show

class FromConf a where
    fromConf :: ConfValue -> a

instance FromConf Int where
    fromConf (CV_Int n) = n
    fromConf _ = error "fromConf int"

instance FromConf Bool where
    fromConf (CV_Bool b) = b
    fromConf _ = error "fromConf bool"

instance FromConf String where
    fromConf (CV_String s) = s
    fromConf _ = error "fromConf string"

----------------------------------------------------------------

parseConfig :: String -> [Conf]
parseConfig cs = map parseConf css
    where
      css = filter (not.isPrefixOf "#") . lines $ cs
      parseConf xs = case parse config "config" xs of
                       Right cnf -> cnf
                       Left  err -> error $ "parseConfig " ++ show err

----------------------------------------------------------------

config :: Parser Conf
config = (,) <$> name <*> (spaces >> char ':' >> spaces *> value)

name :: Parser String
name = many1.oneOf $ ['a'..'z'] ++ ['A'..'Z'] ++ ['0'..'9'] ++ "_"

value :: Parser ConfValue
value = choice [try cv_int, try cv_bool, cv_string]

cv_int :: Parser ConfValue
cv_int = CV_Int . read <$> (many1 digit <* (spaces >> eof))

cv_bool :: Parser ConfValue
cv_bool = CV_Bool True  <$ (string "Yes" >> spaces >> eof) <|>
          CV_Bool False <$ (string "No"  >> spaces >> eof)

cv_string :: Parser ConfValue
cv_string = CV_String <$> many1 (noneOf " \t\n")