{- Handle Options Options: --prime model for starting points [uniform] --error error model [uniform,gradient,..] --terminator termination condition [sigma..] --model shortcut for useful combinations [sanger|454|solexa] -} module Options where import System.Environment (getArgs) import System.Exit (exitWith,ExitCode(..)) import System.Console.GetOpt import System.IO import Data.List (unfoldr) import Control.Monad (when) import Bio.Sequence import UnfoldMut import Sanger import R454 version, usagemsg :: String version = "0.0" usagemsg = "Usage: simseq [options] FILE.." data Opts = Opts { primer :: Primer , errmod :: [Mutator] , term :: Terminator } getOpts :: IO (Opts,[Sequence]) getOpts = do (opt1,fs,err) <- getArgs >>= (return . getOpt Permute options) opts <- parseargs opt1 when (not $ null err) (error $ usage err) when (forceOpts opts) (error "Impossible!") ss <- if null fs then hReadFasta stdin else return . concat =<< mapM readFasta fs return (opts, ss) where forceOpts (Opts x y z) = x `seq` y `seq` z `seq` False parseargs :: [Opts -> IO Opts] -> IO Opts parseargs args = foldl (>>=) (return defaultopts) args usage :: [String] -> String usage errs = usageInfo (concat errs ++ usagemsg) options ------------------------------------------------------------ options :: [OptDescr (Opts -> IO Opts)] options = [ Option [] ["primer"] (ReqArg (setPrimer . processArgs) "p") ("Model for initiating sequencing "++show (map fst primers)) , Option [] ["error"] (ReqArg (setMutator . processArgs) "e") ("Error model "++show (map fst mutators)) , Option [] ["terminator"] (ReqArg (setTerm . processArgs) "t") ("Termination condition "++show (map fst terminators)) , Option [] ["model"] (ReqArg (setModel . processArgs) "m") ("Shortcut for useful combinations "++show (map fst models)) , Option ['h'] ["help"] (ReqArg help "option") ("Help with 'option'") ] defaultopts :: Opts defaultopts = Opts (error "no primer specified") (error "no error model specified") (error "no terminator specified") help :: String -> Opts -> IO Opts help arg _ = do putStrLn usagemsg case arg of "primer" -> list "specifies when sequence generation starts" primers "error" -> list "adds an error model for sequence generation" mutators "terminator" -> list "specifies when sequence generation terminates" terminators "model" -> list "specifies a complete model including primer, error model, and terminator" models _ -> putStrLn (" "++arg++": no such option") exitWith ExitSuccess where list str tbl = putStrLn (" "++arg ++ ": "++str++"\n Valid alternatives are: "++unwords (map fst tbl)) ------------------------------------------------------------ -- | Break a string argument representing a function and arguments -- into components. Syntax is func:arg1,arg2,.. processArgs :: String -> (String,[String]) processArgs ss = let (fn,as) = break (==':') ss in (fn,splitStr ',' as) splitStr :: Char -> String -> [String] splitStr c = unfoldr (\s -> if null s then Nothing else let (x,y) = break (==c) (drop 1 s) in Just (x,y)) ------------------------------------------------------------ -- Lookup tables for selecting the desired behavior ------------------------------------------------------------ notfound :: String -> [(String,a)] -> String -> String notfound what whats which = "'"++which++"': no such "++what++".\n"++ "Available "++what++"s are: "++ (unwords $ map fst whats) setPrimer :: (String,[String]) -> Opts -> IO Opts setPrimer (prim,args) (Opts _ m t) = return (Opts p m t) where p = maybe (error $ notfound "primer" primers prim) (\f -> f args) (lookup prim primers) primers :: [(String,[String]->Primer)] primers = [("uniform",p_uniform)] -- help text? "uniform:n,p","select n random starting points, with probability p of forward direction, 1-p or reverse" ------------------------------------------------------------ setTerm :: (String,[String]) -> Opts -> IO Opts setTerm (trm,args) (Opts p m _) = return (Opts p m t) where t = maybe (error $ notfound "terminator" terminators trm) (\f -> f args) (lookup trm terminators) terminators :: [(String,[String]->Terminator)] terminators = [("sigma",\args -> case args of [s,w] -> \ (MS _ _ l) -> sigma (read s) (read w) $ fromIntegral l _ -> error "terminator 'sigma' needs two arguments") ] ------------------------------------------------------------ setMutator :: (String,[String]) -> Opts -> IO Opts setMutator (mut,args) (Opts p m t) = return (Opts p m' t) where m' = maybe (error $ notfound "mutator" mutators mut) (\f -> f args : m) (lookup mut mutators) mutators :: [(String,[String]->Mutator)] mutators = [] -- ("uniform",...)] ------------------------------------------------------------ setModel :: (String,[String]) -> Opts -> IO Opts setModel (md,args) _ = return (maybe (error $ notfound "model" models md) (\f -> case f args of (p,m,t) -> Opts {primer=p,errmod=m,term=t}) (lookup md models)) models :: [(String,[String]->Model)] models = [("sanger",sanger) ,("stest",\[] -> sanger ["1","1"]) ,("454",r454) ]