{-# LINE 1 "libraries\\ghc-internal\\src\\GHC\\Internal\\System\\Environment\\ExecutablePath.hsc" #-}
{-# LANGUAGE Trustworthy #-}
{-# LANGUAGE CPP #-}
module GHC.Internal.System.Environment.ExecutablePath
( getExecutablePath
, executablePath
) where
#if defined(javascript_HOST_ARCH)
import GHC.Internal.Base
import GHC.Internal.IO (FilePath)
getExecutablePath :: IO FilePath
getExecutablePath = return "a.jsexe"
executablePath :: Maybe (IO (Maybe FilePath))
executablePath = Nothing
#else
import GHC.Internal.Base
import GHC.Internal.IO (FilePath)
import GHC.Internal.Real
{-# LINE 86 "libraries\\ghc-internal\\src\\GHC\\Internal\\System\\Environment\\ExecutablePath.hsc" #-}
import GHC.Internal.Control.Exception
import GHC.Internal.Control.Monad.Fail
import GHC.Internal.Data.Functor
import GHC.Internal.Data.List (isPrefixOf, drop)
import GHC.Internal.Word
import GHC.Internal.Foreign.C.String
import GHC.Internal.Foreign.Marshal.Array
import GHC.Internal.Foreign.Ptr
import GHC.Internal.Num
import GHC.Internal.Windows
{-# LINE 107 "libraries\\ghc-internal\\src\\GHC\\Internal\\System\\Environment\\ExecutablePath.hsc" #-}
getExecutablePath :: IO FilePath
executablePath :: Maybe (IO (Maybe FilePath))
{-# LINE 306 "libraries\\ghc-internal\\src\\GHC\\Internal\\System\\Environment\\ExecutablePath.hsc" #-}
getExecutablePath = go 2048
where
go size = allocaArray (fromIntegral size) $ \ buf -> do
ret <- c_GetModuleFileName nullPtr buf size
case ret of
0 -> errorWithoutStackTrace "getExecutablePath: GetModuleFileNameW returned an error"
_ | ret < size -> do
path <- peekCWString buf
real <- getFinalPath path
exists <- withCWString real c_pathFileExists
if exists
then return real
else fail path
| otherwise -> go (size * 2)
executablePath = Just (Just <$> getExecutablePath)
getFinalPath :: FilePath -> IO FilePath
getFinalPath path = withCWString path $ \s ->
bracket (createFile s) c_closeHandle $ \h -> do
let invalid = h == iNVALID_HANDLE_VALUE
if invalid then pure path else go h bufSize
where go h sz = allocaArray (fromIntegral sz) $ \outPath -> do
ret <- c_getFinalPathHandle h outPath sz (8)
{-# LINE 342 "libraries\\ghc-internal\\src\\GHC\\Internal\\System\\Environment\\ExecutablePath.hsc" #-}
if ret < sz
then sanitize . rejectUNCPath <$> peekCWString outPath
else go h (2 * sz)
sanitize s
| "\\\\?\\" `isPrefixOf` s = drop 4 s
| otherwise = s
rejectUNCPath s
| "\\\\?\\UNC\\" `isPrefixOf` s = path
| otherwise = s
bufSize = 1024
foreign import ccall unsafe "windows.h GetModuleFileNameW"
c_GetModuleFileName :: Ptr () -> CWString -> Word32 -> IO Word32
foreign import ccall unsafe "windows.h PathFileExistsW"
c_pathFileExists :: CWString -> IO Bool
foreign import ccall unsafe "windows.h CreateFileW"
c_createFile :: CWString
-> Word32
-> Word32
-> Ptr ()
-> Word32
-> Word32
-> Ptr ()
-> IO (Ptr ())
createFile :: CWString -> IO (Ptr ())
createFile file =
c_createFile file (2147483648)
{-# LINE 380 "libraries\\ghc-internal\\src\\GHC\\Internal\\System\\Environment\\ExecutablePath.hsc" #-}
(1)
{-# LINE 381 "libraries\\ghc-internal\\src\\GHC\\Internal\\System\\Environment\\ExecutablePath.hsc" #-}
nullPtr
(3)
{-# LINE 383 "libraries\\ghc-internal\\src\\GHC\\Internal\\System\\Environment\\ExecutablePath.hsc" #-}
(128)
{-# LINE 384 "libraries\\ghc-internal\\src\\GHC\\Internal\\System\\Environment\\ExecutablePath.hsc" #-}
nullPtr
foreign import ccall unsafe "windows.h CloseHandle"
c_closeHandle :: Ptr () -> IO Bool
foreign import ccall unsafe "windows.h GetFinalPathNameByHandleW"
c_getFinalPathHandle :: Ptr () -> CWString -> Word32 -> Word32 -> IO Word32
{-# LINE 418 "libraries\\ghc-internal\\src\\GHC\\Internal\\System\\Environment\\ExecutablePath.hsc" #-}
#endif