{-# LANGUAGE ScopedTypeVariables #-}
module GHC.ResponseFile (
getArgsWithResponseFiles,
unescapeArgs,
escapeArgs,
expandResponse
) where
import Control.Exception
import Data.Char (isSpace)
import Data.Foldable (foldl')
import System.Environment (getArgs)
import System.Exit (exitFailure)
import System.IO
getArgsWithResponseFiles :: IO [String]
getArgsWithResponseFiles :: IO [String]
getArgsWithResponseFiles = IO [String]
getArgs IO [String] -> ([String] -> IO [String]) -> IO [String]
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= [String] -> IO [String]
expandResponse
unescapeArgs :: String -> [String]
unescapeArgs :: String -> [String]
unescapeArgs = (String -> Bool) -> [String] -> [String]
forall a. (a -> Bool) -> [a] -> [a]
filter (Bool -> Bool
not (Bool -> Bool) -> (String -> Bool) -> String -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null) ([String] -> [String])
-> (String -> [String]) -> String -> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> [String]
unescape
escapeArgs :: [String] -> String
escapeArgs :: [String] -> String
escapeArgs = [String] -> String
unlines ([String] -> String)
-> ([String] -> [String]) -> [String] -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (String -> String) -> [String] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map String -> String
escapeArg
expandResponse :: [String] -> IO [String]
expandResponse :: [String] -> IO [String]
expandResponse = ([[String]] -> [String]) -> IO [[String]] -> IO [String]
forall a b. (a -> b) -> IO a -> IO b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap [[String]] -> [String]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat (IO [[String]] -> IO [String])
-> ([String] -> IO [[String]]) -> [String] -> IO [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (String -> IO [String]) -> [String] -> IO [[String]]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> [a] -> m [b]
mapM String -> IO [String]
expand
where
expand :: String -> IO [String]
expand :: String -> IO [String]
expand (Char
'@':String
f) = String -> IO String
readFileExc String
f IO String -> (String -> IO [String]) -> IO [String]
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= [String] -> IO [String]
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ([String] -> IO [String])
-> (String -> [String]) -> String -> IO [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> [String]
unescapeArgs
expand String
x = [String] -> IO [String]
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return [String
x]
readFileExc :: String -> IO String
readFileExc String
f =
String -> IO String
readFile String
f IO String -> (IOException -> IO String) -> IO String
forall e a. Exception e => IO a -> (e -> IO a) -> IO a
`catch` \(IOException
e :: IOException) -> do
Handle -> String -> IO ()
hPutStrLn Handle
stderr (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ String
"Error while expanding response file: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ IOException -> String
forall a. Show a => a -> String
show IOException
e
IO String
forall a. IO a
exitFailure
data Quoting = NoneQ | SngQ | DblQ
unescape :: String -> [String]
unescape :: String -> [String]
unescape String
args = [String] -> [String]
forall a. [a] -> [a]
reverse ([String] -> [String])
-> ([String] -> [String]) -> [String] -> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (String -> String) -> [String] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map String -> String
forall a. [a] -> [a]
reverse ([String] -> [String]) -> [String] -> [String]
forall a b. (a -> b) -> a -> b
$ String -> Quoting -> Bool -> String -> [String] -> [String]
go String
args Quoting
NoneQ Bool
False [] []
where
go :: String -> Quoting -> Bool -> String -> [String] -> [String]
go [] Quoting
_q Bool
_bs String
a [String]
as = String
aString -> [String] -> [String]
forall a. a -> [a] -> [a]
:[String]
as
go (Char
c:String
cs) Quoting
q Bool
True String
a [String]
as = String -> Quoting -> Bool -> String -> [String] -> [String]
go String
cs Quoting
q Bool
False (Char
cChar -> String -> String
forall a. a -> [a] -> [a]
:String
a) [String]
as
go (Char
c:String
cs) Quoting
q Bool
False String
a [String]
as
| Char
'\\' Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
c = String -> Quoting -> Bool -> String -> [String] -> [String]
go String
cs Quoting
q Bool
True String
a [String]
as
go (Char
c:String
cs) Quoting
SngQ Bool
False String
a [String]
as
| Char
'\'' Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
c = String -> Quoting -> Bool -> String -> [String] -> [String]
go String
cs Quoting
NoneQ Bool
False String
a [String]
as
| Bool
otherwise = String -> Quoting -> Bool -> String -> [String] -> [String]
go String
cs Quoting
SngQ Bool
False (Char
cChar -> String -> String
forall a. a -> [a] -> [a]
:String
a) [String]
as
go (Char
c:String
cs) Quoting
DblQ Bool
False String
a [String]
as
| Char
'"' Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
c = String -> Quoting -> Bool -> String -> [String] -> [String]
go String
cs Quoting
NoneQ Bool
False String
a [String]
as
| Bool
otherwise = String -> Quoting -> Bool -> String -> [String] -> [String]
go String
cs Quoting
DblQ Bool
False (Char
cChar -> String -> String
forall a. a -> [a] -> [a]
:String
a) [String]
as
go (Char
c:String
cs) Quoting
NoneQ Bool
False String
a [String]
as
| Char -> Bool
isSpace Char
c = String -> Quoting -> Bool -> String -> [String] -> [String]
go String
cs Quoting
NoneQ Bool
False [] (String
aString -> [String] -> [String]
forall a. a -> [a] -> [a]
:[String]
as)
| Char
'\'' Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
c = String -> Quoting -> Bool -> String -> [String] -> [String]
go String
cs Quoting
SngQ Bool
False String
a [String]
as
| Char
'"' Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
c = String -> Quoting -> Bool -> String -> [String] -> [String]
go String
cs Quoting
DblQ Bool
False String
a [String]
as
| Bool
otherwise = String -> Quoting -> Bool -> String -> [String] -> [String]
go String
cs Quoting
NoneQ Bool
False (Char
cChar -> String -> String
forall a. a -> [a] -> [a]
:String
a) [String]
as
escapeArg :: String -> String
escapeArg :: String -> String
escapeArg = String -> String
forall a. [a] -> [a]
reverse (String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (String -> Char -> String) -> String -> String -> String
forall b a. (b -> a -> b) -> b -> [a] -> b
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' String -> Char -> String
escape []
escape :: String -> Char -> String
escape :: String -> Char -> String
escape String
cs Char
c
| Char -> Bool
isSpace Char
c
Bool -> Bool -> Bool
|| Char
'\\' Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
c
Bool -> Bool -> Bool
|| Char
'\'' Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
c
Bool -> Bool -> Bool
|| Char
'"' Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
c = Char
cChar -> String -> String
forall a. a -> [a] -> [a]
:Char
'\\'Char -> String -> String
forall a. a -> [a] -> [a]
:String
cs
| Bool
otherwise = Char
cChar -> String -> String
forall a. a -> [a] -> [a]
:String
cs