module Setup where import System.Console.GetOpt ( ArgDescr (..), OptDescr (..), usageInfo, getOpt', ArgOrder (..) ) import System.Environment ( getProgName ) import System.Exit ( exitWith, ExitCode (..) ) import System.Directory ( findExecutable ) import Data.Maybe ( fromMaybe ) data ConfigFlags = ConfigFlags { configGHCPath :: FilePath , configInputFile :: FilePath , configOutputFile :: FilePath , configCpphsPath :: FilePath , configGHCArgs :: [String] , configCpphsArgs :: [String] } deriving Show getExecutable :: String -> Maybe FilePath -> IO FilePath getExecutable _ (Just path) = return path getExecutable name Nothing = fmap (fromMaybe (error errMsg)) (findExecutable name) where errMsg = "Couldn't find: "++name mkConfigFlags :: TempFlags -> IO ConfigFlags mkConfigFlags tmpFlags = do ghcPath <- getExecutable "ghc" (tempGHCPath tmpFlags) cpphsPath <- getExecutable "cpphs" (tempCpphsPath tmpFlags) return (ConfigFlags { configGHCPath = ghcPath , configCpphsPath = cpphsPath , configInputFile = tempInputFile tmpFlags , configOutputFile = tempOutputFile tmpFlags , configGHCArgs = tempGHCArgs tmpFlags , configCpphsArgs = tempCpphsArgs tmpFlags}) data TempFlags = TempFlags { tempGHCPath :: Maybe FilePath , tempInputFile :: FilePath , tempOutputFile :: FilePath , tempCpphsPath :: Maybe FilePath , tempGHCArgs :: [String] , tempCpphsArgs :: [String] } deriving Show data Flag = WithGHC FilePath | InputFile FilePath | OutputFile FilePath | WithCpphs FilePath | GHCArgs String | CpphsArgs String | HelpFlag -- We don't want to use elem, because that imposes Eq a hasHelpFlag :: [Flag] -> Bool hasHelpFlag flags = not . null $ [ () | HelpFlag <- flags ] emptyTempFlags :: TempFlags emptyTempFlags = TempFlags { tempGHCPath = Nothing , tempInputFile = "-" , tempOutputFile = "-" , tempCpphsPath = Nothing , tempGHCArgs = [] , tempCpphsArgs = [] } globalOptions :: [OptDescr Flag] globalOptions = [ Option "h?" ["help"] (NoArg HelpFlag) "Show this help text" , Option "w" ["ghc"] (ReqArg WithGHC "PATH") "Use this GHC" , Option "" ["cpphs"] (ReqArg WithCpphs "PATH") "Use this cpphs" , Option "i" ["input"] (ReqArg InputFile "PATH") "Input file" , Option "o" ["output"] (ReqArg OutputFile "PATH") "Output file" , Option "" ["ghc-args"] (ReqArg GHCArgs "Arguments") "Arguments to GHC" , Option "" ["cpphs-args"] (ReqArg CpphsArgs "Arguments") "Arguments to cpphs" ] printHelp :: IO () printHelp = do pname <- getProgName let syntax_line = concat [ "Usage: ", pname , " [FLAGS]\n"] putStrLn (usageInfo syntax_line globalOptions) parseArgs :: [String] -> IO TempFlags parseArgs args = case getOpt' RequireOrder globalOptions args of (flags, _, _, []) | hasHelpFlag flags -> do printHelp exitWith ExitSuccess (flags, [], _, []) -> return (mkTempFlags flags emptyTempFlags) (_, _, _, errs) -> do putStrLn "Errors:" mapM_ putStrLn errs exitWith (ExitFailure 1) mkTempFlags :: [Flag] -> TempFlags -> TempFlags mkTempFlags = updateCfg where updateCfg [] t = t updateCfg (fl:flags) t = updateCfg flags $ case fl of WithGHC path -> t { tempGHCPath = Just path } InputFile path -> t { tempInputFile = path } OutputFile path -> t { tempOutputFile = path } WithCpphs path -> t { tempCpphsPath = Just path } GHCArgs args -> t { tempGHCArgs = tempGHCArgs t ++ words args } CpphsArgs args -> t { tempCpphsArgs = tempCpphsArgs t ++ words args } _ -> error $ "Unexpected flag!"