packages feed

board-games-0.1: src/Game/Server/Option.hs

module Game.Server.Option (
   T(..),
   get,
   printVerbose,
   ) where

import System.Console.GetOpt
          (getOpt, ArgOrder(..), OptDescr(..), ArgDescr(..), usageInfo, )
import System.Environment (getArgs, getProgName, )
import System.Exit (exitSuccess, exitFailure, )
import qualified System.IO as IO

import Control.Monad (when, )


data T =
   Cons {
      verbosity :: Int,
      port :: Int
   }
   deriving (Show)


deflt :: T
deflt =
   Cons {
      verbosity = 0,
      port = 8080
      -- other options might control maximum values for some dimensions in the games
   }


exitFailureMsg :: String -> IO a
exitFailureMsg msg =
   IO.hPutStrLn IO.stderr msg >> exitFailure

parseNumber ::
   (Read a) =>
   String -> (a -> Bool) -> String -> String -> IO a
parseNumber name constraint constraintName str =
   case reads str of
      [(n, "")] ->
         if constraint n
           then return n
           else exitFailureMsg $ name ++ " must be " ++ constraintName
      _ ->
         exitFailureMsg $ name ++ " must be a number, but is '" ++ str ++ "'"


printVerbose :: (Show a) => T -> Int -> a -> IO ()
printVerbose opt verb a =
   when (verb <= verbosity opt) $ print a


{-
Guide for common Linux/Unix command-line options:
  http://www.faqs.org/docs/artu/ch10s05.html
-}
description :: [OptDescr (T -> IO T)]
description =
   Option ['h'] ["help"]
      (NoArg $ \ _flags -> do
         programName <- getProgName
         putStrLn
            (usageInfo ("Usage: " ++ programName ++ " [OPTIONS]") description)
         exitSuccess)
      "show options" :
   Option ['v'] ["verbose"]
      (flip ReqArg "LEVEL" $ \str flags ->
         fmap (\verb -> flags{verbosity = fromInteger verb}) $
         parseNumber "verbosity" (\n -> 0<=n && n<=2) "from the range from 0 to 2" str)
      "level of verbosity" :
   Option ['p'] ["port"]
      (flip ReqArg "NUMBER" $ \str flags ->
         fmap (\p -> flags{port = fromInteger p}) $
         parseNumber "port" (\n -> 0<n && n<0x10000) "a positive 16-bit number" str)
      "port number" :
   []


get :: IO T
get = do
   argv <- getArgs
   let (opts, files, errors) = getOpt RequireOrder description argv
   when (not $ null errors) $
      exitFailureMsg (init (concat errors))
   when (not $ null files) $
      exitFailureMsg $
         "Do not know what to do with arguments " ++ show files
   foldl (>>=)
      (return deflt)
      opts