\subsection{Option handling}

You know the drill...

\begin{code}

module RBR.Options (version,usage,getOptions,Opts(..),parseargs,MaskWith(..)) where

import System.Environment (getArgs)
import System.Console.GetOpt
import System.Exit

version, usagemsg :: String
version = "0.8.4"
usagemsg = "Usage: rbr [-k <k>] [options] FILE.."

getOptions :: IO ([Opts -> IO Opts], [String], [String])
getOptions  = getArgs >>= (return . getOpt Permute options)

usage :: [String] -> String
usage errs = usageInfo (concat errs ++ usagemsg) options

data MaskWith = Lower | Ns | Xs

options :: [OptDescr (Opts -> IO Opts)]
options = [Option ['k'] ["word-size"] (ReqArg (\arg opt -> return opt { kval = read arg }) "Int") "Word size"
          ,Option [] ["sparse-keys"]  (ReqArg (\arg opt -> return opt { skip = read arg })    "Int") "Skip length"
--          ,Option [] ["shape"] (ReqArg ...) "Key shape"
          ,Option ['N'] ["no-stats"]   (NoArg  (\opt -> return opt { stats = False }))         "Omit statistical masking"
          ,Option ['g'] ["gapclosing"] (ReqArg (\arg opt -> return opt { gap = read arg })    "Int") "Close gaps"
          ,Option ['s'] ["stringency"] (ReqArg (\arg opt -> return opt { string = read arg }) "Float") "Mask stringecy"
          ,Option ['t'] ["threshold"]  (ReqArg (\arg opt -> return opt { thresh = read arg }) "Float") "Mask threshold"
          ,Option [] ["preserve-lower-case"] (NoArg (\opt -> return opt { preserve_lower = True })) "Preserve lower case in input sequences"

          ,Option ['D'] ["distribution"] (NoArg (\opt -> return opt { distr = True }))            "Distribution output"
          ,Option ['l'] ["library"]    (ReqArg (\arg opt -> return opt {lib = Just arg}) "file") "Mask words from library"
          ,Option ['L'] ["lower-case"] (NoArg (\opt -> return opt { lower = Lower }))    "Mask using lower case letters"
          ,Option ['n'] ["n-mask"] (NoArg (\opt -> return opt { lower = Ns }))    "Mask using 'n's"
          ,Option ['x'] ["x-mask"] (NoArg (\opt -> return opt { lower = Xs }))    "Mask using 'X's"
          ,Option [] ["server"]        (NoArg (\opt -> return opt { server = True }))     "Run in server mode"
          ,Option ['o'] ["output-file"] (ReqArg (\arg opt -> return opt { ofile = Just arg }) "file") "Output file"
	  ,Option ['v'] ["verbose"]    (NoArg (\opt -> return opt { verb = True })) "Display progress"

          ,Option ['h'] ["help"]    (NoArg (\_ -> do {putStrLn $ usage []; exitWith ExitSuccess })) "Display help"
          ,Option ['V'] ["version"] (NoArg (\_ -> do {putStrLn $ "rbr version "++version; exitWith ExitSuccess })) "Display version"
          ]

data Opts = Opts { kval :: Int, ofile :: Maybe FilePath
                 , stats, preserve_lower :: Bool
                 , thresh, string  :: Double
                 , gap :: Int
                 , lower :: MaskWith
                 , distr, verb, server :: Bool
                 , lib :: Maybe FilePath
                 , skip :: Int
                 }

defaultopts :: Opts
defaultopts = Opts 16 Nothing True False 0 0 0 Lower False False False Nothing 0

parseargs :: [Opts -> IO Opts] -> IO Opts
parseargs args = foldl (>>=) (return defaultopts) args >>= fixS >>= fixT
    where fixS opts = return $ case (string opts,lower opts) of -- sensible(?) defaults
                         (0,Ns) -> opts { string = 2.0 }
                         (0,Xs) -> opts { string = 2.0 }
                         (0,Lower) -> opts { string = 1.1 }
                         _ -> opts
          fixT opts = return $ case (thresh opts,lower opts) of -- sensible(?) defaults
                         (0,Ns) -> opts { thresh = 8.0 }
                         (0,Xs) -> opts { thresh = 8.0 }
                         (0,Lower) -> opts { thresh = 5.0 }
                         _ -> opts

\end{code}