import Control.Exception
import Data.Char
import Data.List
+import Data.Monoid
import System.Cmd
import System.Directory
import System.Environment
import System.FilePath
import System.IO
+#if defined(mingw32_HOST_OS)
+import Control.Monad
+import Foreign
+import Foreign.C.String
+#endif
+
main :: IO ()
main = do
args <- getArgs
- case getGhcLoc args of
- (Just ghc, args') -> doIt ghc args'
- (Nothing, args') -> do
+ case parseRunGhcFlags args of
+ (Help, _) -> printUsage
+ (ShowVersion, _) -> printVersion
+ (RunGhcFlags (Just ghc), args') -> doIt ghc args'
+ (RunGhcFlags Nothing, args') -> do
mbPath <- getExecPath
case mbPath of
Nothing -> dieProg ("cannot find ghc")
let ghc = takeDirectory (normalise path) </> "ghc"
in doIt ghc args'
-getGhcLoc :: [String] -> (Maybe FilePath, [String])
-getGhcLoc args = case args of
- "-f" : ghc : args' -> f ghc args'
- ('-' : 'f' : ghc) : args' -> f ghc args'
- -- If you need the first GHC flag to be a -f flag then
- -- you can pass -- first
- "--" : args -> (Nothing, args)
- args -> (Nothing, args)
- where f ghc args' = -- If there is another -f flag later on then
- -- that overrules the one that we've already
- -- found
- case getGhcLoc args' of
- (Nothing, _) -> (Just ghc, args')
- success -> success
+data RunGhcFlags = RunGhcFlags (Maybe FilePath) -- GHC location
+ | Help -- Print help text
+ | ShowVersion -- Print version info
+
+instance Monoid RunGhcFlags where
+ mempty = RunGhcFlags Nothing
+ Help `mappend` _ = Help
+ _ `mappend` Help = Help
+ ShowVersion `mappend` _ = ShowVersion
+ _ `mappend` ShowVersion = ShowVersion
+ RunGhcFlags _ `mappend` right@(RunGhcFlags (Just _)) = right
+ left@(RunGhcFlags _) `mappend` RunGhcFlags Nothing = left
+
+parseRunGhcFlags :: [String] -> (RunGhcFlags, [String])
+parseRunGhcFlags = f mempty
+ where f flags ("-f" : ghc : args)
+ = f (flags `mappend` RunGhcFlags (Just ghc)) args
+ f flags (('-' : 'f' : ghc) : args)
+ = f (flags `mappend` RunGhcFlags (Just ghc)) args
+ f flags ("--help" : args) = f (flags `mappend` Help) args
+ f flags ("--version" : args) = f (flags `mappend` ShowVersion) args
+ -- If you need the first GHC flag to be a -f flag then
+ -- you can pass -- first
+ f flags ("--" : args) = (flags, args)
+ f flags args = (flags, args)
+
+printVersion :: IO ()
+printVersion = do
+ putStrLn ("runghc " ++ VERSION)
+
+printUsage :: IO ()
+printUsage = do
+ putStrLn "Usage: runghc [runghc flags] [GHC flags] module [program args]"
+ putStrLn ""
+ putStrLn "The runghc flags are"
+ putStrLn " -f /path/to/ghc Tell runghc where GHC is"
+ putStrLn " --help Print this usage information"
+ putStrLn " --version Print version number"
doIt :: String -> [String] -> IO ()
doIt ghc args = do
tmpdir <- getTemporaryDirectory
bracket
(openTempFile tmpdir "runghcXXXX.hs")
- (\(filename,_) -> removeFile filename)
+ (\(filename,h) -> do hClose h; removeFile filename)
$ \(filename,h) -> do
getContents >>= hPutStr h
hClose h
doIt ghc (ghc_args ++ [filename])
filename : prog_args -> do
- let c1 = ":set prog " ++ show filename
+ -- If the file exists, and is not a .lhs file, then we
+ -- want to treat it as a .hs file.
+ --
+ -- If the file doesn't exist then GHC is going to look for
+ -- filename.hs and filename.lhs, and use the appropriate
+ -- type.
+ exists <- doesFileExist filename
+ let xflag = if exists && (takeExtension filename /= ".lhs")
+ then ["-x", "hs"]
+ else []
+ c1 = ":set prog " ++ show filename
c2 = ":main " ++ show prog_args
- res <- rawSystem ghc (["-ignore-dot-ghci"] ++ ghc_args ++
+ res <- rawSystem ghc (["-ignore-dot-ghci"] ++
+ xflag ++
+ ghc_args ++
[ "-e", c1, "-e", c2, filename])
exitWith res