------------------------------------------------------------------------
--- $Id: Main.hs,v 1.29 2001/03/29 17:56:18 qrczak Exp $
+-- $Id: Main.hs,v 1.41 2002/10/27 10:38:33 mthomas Exp $
--
-- Program for converting .hsc files to .hs files, by converting the
-- file into a C program which is run to generate the Haskell source.
--
-- See the documentation in the Users' Guide for more details.
+#if __GLASGOW_HASKELL__ >= 504
+import System.Console.GetOpt
+#else
import GetOpt
-import System (getProgName, getArgs, ExitCode(..), exitWith, exitFailure)
-import KludgedSystem (system, defaultCompiler)
+#endif
+
+import Config
+import System (getProgName, getArgs, ExitCode(..), exitWith, exitFailure, system)
import Directory (removeFile)
import Monad (MonadPlus(..), liftM, liftM2, when, unless)
import Char (isAlpha, isAlphaNum, isSpace, isDigit, toUpper, intToDigit, ord)
import List (intersperse)
+#include "../../includes/config.h"
+
+#ifdef mingw32_HOST_OS
+-- import Win32DLL
+import Foreign.C.String (CString, peekCString)
+import Foreign.C.Types
+import Foreign.Ptr (nullPtr)
+import Foreign.Marshal.Alloc (mallocBytes, free)
+
+foreign import stdcall "GetModuleHandle" c_GetModuleHandle :: CString -> IO CUInt
+foreign import stdcall "GetModuleFileName" c_GetModuleFilename :: CUInt -> CString -> CUInt -> IO CUInt
+
+ourName :: IO String
+ourName = do h <- c_GetModuleHandle nullPtr
+ cstr <- mallocBytes cstr_len
+ rv <- c_GetModuleFilename h cstr (CUInt (fromIntegral cstr_len))
+ str <- peekCString cstr
+ free cstr
+ return str
+ where cstr_len = 512
+#endif
+
version :: String
version = "hsc2hs-0.65"
Option "I" [] (ReqArg (CompFlag . ("-I"++))
"DIR") "passed to the C compiler",
Option "L" ["lflag"] (ReqArg LinkFlag "FLAG") "flag to pass to the linker",
- Option "" ["no-compile"] (NoArg NoCompile) "stop after writing *_hsc_make.c",
Option "i" ["include"] (ReqArg include "FILE") "as if placed in the source",
Option "D" ["define"] (ReqArg define "NAME[=VALUE]") "as if placed in the source",
Option "o" ["output"] (ReqArg Output "FILE") "name of main output file",
Option "" ["help"] (NoArg Help) "display this help and exit",
- Option "" ["version"] (NoArg Version) "output version information and exit"]
+ Option "" ["version"] (NoArg Version) "output version information and exit",
+ Option "" ["no-compile"] (NoArg NoCompile) "stop after writing *_hsc_make.c"]
main :: IO ()
main = do
prog <- getProgName
let header = "Usage: "++prog++" [OPTIONS] INPUT.hsc [...]"
args <- getArgs
- case getOpt Permute options args of
+ let opts@(flags, files, errs) = getOpt Permute options args
+#ifdef mingw32_HOST_OS
+ n <- ourName
+ let tempName = reverse (drop (length "\\bin\\hsc2hs.exe") (reverse n)) ++ "\\template-hsc.h"
+ let fflags = if [t | Template t <- flags] /= [] then flags else (Template tempName) : flags
+ let opts = (fflags, files, errs)
+#endif
+ case opts of
(flags, _, _)
| any isHelp flags -> putStrLn (usageInfo header options)
| any isVersion flags -> putStrLn version
exitFailure
processFile :: [Flag] -> String -> IO ()
-processFile flags name = do
- s <- readFile name
- case parser of
- Parser p -> case p (SourcePos name 1) s of
- Success _ _ _ toks -> output flags name toks
- Failure (SourcePos name' line) msg -> do
- putStrLn (name'++":"++show line++": "++msg)
- exitFailure
+processFile flags name
+ = do let file_name = dosifyPath name
+ s <- readFile file_name
+ case parser of
+ Parser p -> case p (SourcePos file_name 1) s of
+ Success _ _ _ toks -> output flags file_name toks
+ Failure (SourcePos name' line) msg -> do
+ putStrLn (name'++":"++show line++": "++msg)
+ exitFailure
+
+------------------------------------------------------------------------
+-- Convert paths foo/baz to foo\baz on Windows
+
+#if defined(mingw32_HOST_OS)
+subst a b ls = map (\ x -> if x == a then b else x) ls
+dosifyPath xs = subst '/' '\\' xs
+#else
+dosifyPath xs = xs
+#endif
------------------------------------------------------------------------
-- A deterministic parser which remembers the text which has been parsed.
let cProgName = outDir++outBase++"_hsc_make.c"
oProgName = outDir++outBase++"_hsc_make.o"
- progName = outDir++outBase++"_hsc_make"
- outHName = outDir++outBase++"_hsc.h"
+ progName = outDir++outBase++"_hsc_make" ++ progNameSuffix
+ outHFile = outBase++"_hsc.h"
+ outHName = outDir++outHFile
outCName = outDir++outBase++"_hsc.c"
-
+
let execProgName
- | null outDir = "./"++progName
+ | null outDir = '.':pathSep:progName
| otherwise = progName
let specials = [(pos, key, arg) | Special pos key arg <- toks]
_ -> onlyOne "compiler"
linker <- case [l | Linker l <- flags] of
- [] -> return defaultCompiler
+ [] -> return cGCC
[l] -> return l
_ -> onlyOne "linker"
_ -> return ()
removeFile oProgName
- system (execProgName++" >"++outName)
+ progStatus <- system (execProgName++" >"++outName)
removeFile progName
+ case progStatus of
+ e@(ExitFailure _) -> exitWith e
+ _ -> return ()
when needsH $ writeFile outHName $
- "#ifndef "++includeGuard++"\n\
- \#define "++includeGuard++"\n\
- \#if __GLASGOW_HASKELL__ && __GLASGOW_HASKELL__ < 409\n\
- \#include <Rts.h>\n\
- \#endif\n\
- \#include <HsFFI.h>\n\
- \#if __NHC__\n\
- \#undef HsChar\n\
- \#define HsChar int\n\
+ "#ifndef "++includeGuard++"\n\
+ \#define "++includeGuard++"\n\
+ \#if " ++
+ "__GLASGOW_HASKELL__ && __GLASGOW_HASKELL__ < 409\n\
+ \#include <Rts.h>\n\
+ \#endif\n\
+ \#include <HsFFI.h>\n\
+ \#if __NHC__\n\
+ \#undef HsChar\n\
+ \#define HsChar int\n\
\#endif\n"++
concatMap outFlagH flags++
concatMap outTokenH specials++
"#endif\n"
when needsC $ writeFile outCName $
- "#include \""++outHName++"\"\n"++
+ "#include \""++outHFile++"\"\n"++
concatMap outTokenC specials
+ -- NB. outHFile not outHName; works better when processed
+ -- by gcc or mkdependC.
onlyOne :: String -> IO a
onlyOne what = do
(header, _:body) -> case break isSpace header of
(name, args) ->
outCLine pos++
- "#define hsc_"++name++"("++dropWhile isSpace args++") \
+ "#define hsc_"++name++"("++dropWhile isSpace args++") \
\printf ("++joinLines body++");\n"
_ -> ""
where
outHeaderHs :: [Flag] -> Maybe String -> [(SourcePos, String, String)] -> String
outHeaderHs flags inH toks =
- "#if __GLASGOW_HASKELL__ && __GLASGOW_HASKELL__ < 409\n\
- \ printf (\"{-# OPTIONS -optc-D__GLASGOW_HASKELL__=%d #-}\\n\", \
- \__GLASGOW_HASKELL__);\n\
+ "#if " ++
+ "__GLASGOW_HASKELL__ && __GLASGOW_HASKELL__ < 409\n\
+ \ printf (\"{-# OPTIONS -optc-D" ++
+ "__GLASGOW_HASKELL__=%d #-}\\n\", \
+ \__GLASGOW_HASKELL__);\n\
\#endif\n"++
case inH of
Nothing -> concatMap outFlag flags++concatMap outSpecial toks
(enum, rest) -> let
this = case break (== '=') $ dropWhile isSpace enum of
(name, []) ->
- " hsc_enum ("++t++", "++f++", \
+ " hsc_enum ("++t++", "++f++", \
\hsc_haskellize (\""++name++"\"), "++
name++");\n"
(hsName, _:cName) ->
- " hsc_enum ("++t++", "++f++", \
+ " hsc_enum ("++t++", "++f++", \
\printf (\"%s\", \""++hsName++"\"), "++
cName++");\n"
in this++enums rest
's':'t':'r':'u':'c':'t':' ':_ -> arg++"\n"
't':'y':'p':'e':'d':'e':'f':' ':_ -> arg++"\n"
'i':'n':'l':'i':'n':'e':' ':_ ->
- "#ifdef __GNUC__\n\
- \extern\n\
+ "#ifdef __GNUC__\n\
+ \extern\n\
\#endif\n"++
arg++"\n"
_ -> "extern "++header++";\n"
"def" -> case arg of
's':'t':'r':'u':'c':'t':' ':_ -> ""
't':'y':'p':'e':'d':'e':'f':' ':_ -> ""
- 'i':'n':'l':'i':'n':'e':' ':_ ->
- outCLine pos++
- "#ifndef __GNUC__\n\
- \extern\n\
- \#endif\n"++
- header++
- "\n#ifndef __GNUC__\n\
- \;\n\
- \#else\n"++
- body++
- "\n#endif\n"
+ 'i':'n':'l':'i':'n':'e':' ':arg' ->
+ case span (\c -> c /= '{' && c /= '=') arg' of
+ (header, body) ->
+ outCLine pos++
+ "#ifndef __GNUC__\n\
+ \extern inline\n\
+ \#endif\n"++
+ header++
+ "\n#ifndef __GNUC__\n\
+ \;\n\
+ \#else\n"++
+ body++
+ "\n#endif\n"
_ -> outCLine pos++arg++"\n"
- where (header, body) = span (\c -> c /= '{' && c /= '=') arg
_ | conditional key -> outCLine pos++"#"++key++" "++arg++"\n"
_ -> ""
intToDigit (ord c `quot` 64),
intToDigit (ord c `quot` 8 `mod` 8),
intToDigit (ord c `mod` 8)]
+