-- | The Quipper preprocessor. This is just a wrapper around an awk
-- script.
import System.Environment
import System.Exit
import System.Process
import System.IO
import System.IO.Error
-- The Paths_quipper_language module is automatically generated by Cabal.
import Paths_quipper_language
-- | Print usage information.
usage :: String -> IO ()
usage myname = do
putStrLn $ myname ++ ": the Quipper preprocessor"
putStrLn $ ""
putStrLn $ "Usage: " ++ myname ++ " <sourcefile> <infile> <outfile>"
putStrLn $ " " ++ myname ++ " -f"
putStrLn $ ""
putStrLn $ "Arguments and options:"
putStrLn $ " <sourcefile> - the name of the original source file"
putStrLn $ " <infile> - the name of the file holding the input"
putStrLn $ " <outfile> - the name of the file to write the output to"
putStrLn $ " -f - act as a filter (for testing)"
-- | Escape backslash characters in a string.
escape :: String -> String
escape [] = []
escape ('\\' : t) = "\\\\" ++ escape t
escape (h : t) = h : escape t
-- | Run awk with the given arguments on the given input string.
runAWK :: [String] -> String -> IO (ExitCode, String, String)
runAWK args input = catchIOError body handler
where
body = do
readProcessWithExitCode "awk" args input
handler e = do
name <- getProgName
hPutStrLn stderr $ name ++ ": unable to run awk. Please ensure that awk is installed and on your PATH."
exitFailure
-- | Check whether awk needs one or two rounds of character escaping.
-- For unknown reasons, the behavior of awk in Windows is different
-- from that in Linux. Maybe it differs from implementation to
-- implementation, so we better check it at runtime.
awk_needs_two_escapes :: IO Bool
awk_needs_two_escapes = do
(r, out, err) <- runAWK ["-v", "var=x\\\\\\\\y", "--", "BEGIN { print var }"] ""
case out of
"x\\\\y\n" -> return False
"x\\y\n" -> return True
otherwise -> return False
-- | Run the Quipper preprocessor on the given input string.
runPP :: String -> String -> IO (ExitCode, String, String)
runPP filename input = do
b <- awk_needs_two_escapes
let esc = if b then escape . escape else escape
script <- getDataFileName "scripts/convert_template.awk"
let args = ["-f", script, "-v", "haskell_filename=\"" ++ esc filename ++ "\""]
runAWK args input
-- | Run the Quipper preprocessor on the given pair of files.
runPP_filter :: String -> Handle -> Handle -> IO ExitCode
runPP_filter filename fin fout = do
input <- hGetContents fin
(r, out, err) <- runPP filename input
hPutStr fout out
hPutStr stderr err
hFlush fout
hFlush stderr
return r
main :: IO ()
main = do
args <- getArgs
myname <- getProgName
case args of
"-h" : _ -> do
usage myname
exitSuccess
"--help" : _ -> do
usage myname
exitSuccess
["-f"] -> do
r <- runPP_filter "stdin" stdin stdout
exitWith r
[filename, infile, outfile] -> do
fin <- openFile infile ReadMode
fout <- openFile outfile WriteMode
r <- runPP_filter filename fin fout
hClose fin
hClose fout
exitWith r
_ -> do
putStrLn $ myname ++ ": illegal command line"
putStrLn $ "For usage information, try the `--help' option."
exitFailure