{-# LINE 1 "libraries/base/System/Environment/ExecutablePath.hsc" #-}
{-# LANGUAGE Safe #-}
{-# LANGUAGE CPP #-}
module System.Environment.ExecutablePath
( getExecutablePath
, executablePath
) where
{-# LINE 28 "libraries/base/System/Environment/ExecutablePath.hsc" #-}
import Control.Exception (catch, throw)
import Data.Word
import Foreign.C
import Foreign.Marshal.Alloc
import Foreign.Ptr
import Foreign.Storable
import System.IO.Error (isDoesNotExistError)
import System.Posix.Internals
{-# LINE 69 "libraries/base/System/Environment/ExecutablePath.hsc" #-}
getExecutablePath :: IO FilePath
executablePath :: Maybe (IO (Maybe FilePath))
{-# LINE 113 "libraries/base/System/Environment/ExecutablePath.hsc" #-}
type UInt32 = Word32
foreign import ccall unsafe "mach-o/dyld.h _NSGetExecutablePath"
c__NSGetExecutablePath :: CString -> Ptr UInt32 -> IO CInt
_NSGetExecutablePath :: IO FilePath
_NSGetExecutablePath :: IO FilePath
_NSGetExecutablePath =
Int -> (Ptr CChar -> IO FilePath) -> IO FilePath
forall a b. Int -> (Ptr a -> IO b) -> IO b
allocaBytes Int
1024 ((Ptr CChar -> IO FilePath) -> IO FilePath)
-> (Ptr CChar -> IO FilePath) -> IO FilePath
forall a b. (a -> b) -> a -> b
$ \ Ptr CChar
buf ->
(Ptr UInt32 -> IO FilePath) -> IO FilePath
forall a b. Storable a => (Ptr a -> IO b) -> IO b
alloca ((Ptr UInt32 -> IO FilePath) -> IO FilePath)
-> (Ptr UInt32 -> IO FilePath) -> IO FilePath
forall a b. (a -> b) -> a -> b
$ \ Ptr UInt32
bufsize -> do
Ptr UInt32 -> UInt32 -> IO ()
forall a. Storable a => Ptr a -> a -> IO ()
poke Ptr UInt32
bufsize UInt32
1024
CInt
status <- Ptr CChar -> Ptr UInt32 -> IO CInt
c__NSGetExecutablePath Ptr CChar
buf Ptr UInt32
bufsize
if CInt
status CInt -> CInt -> Bool
forall a. Eq a => a -> a -> Bool
== CInt
0
then Ptr CChar -> IO FilePath
peekFilePath Ptr CChar
buf
else do Int
reqBufsize <- UInt32 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (UInt32 -> Int) -> IO UInt32 -> IO Int
forall a b. (a -> b) -> IO a -> IO b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
`fmap` Ptr UInt32 -> IO UInt32
forall a. Storable a => Ptr a -> IO a
peek Ptr UInt32
bufsize
Int -> (Ptr CChar -> IO FilePath) -> IO FilePath
forall a b. Int -> (Ptr a -> IO b) -> IO b
allocaBytes Int
reqBufsize ((Ptr CChar -> IO FilePath) -> IO FilePath)
-> (Ptr CChar -> IO FilePath) -> IO FilePath
forall a b. (a -> b) -> a -> b
$ \ Ptr CChar
newBuf -> do
CInt
status2 <- Ptr CChar -> Ptr UInt32 -> IO CInt
c__NSGetExecutablePath Ptr CChar
newBuf Ptr UInt32
bufsize
if CInt
status2 CInt -> CInt -> Bool
forall a. Eq a => a -> a -> Bool
== CInt
0
then Ptr CChar -> IO FilePath
peekFilePath Ptr CChar
newBuf
else FilePath -> IO FilePath
forall a. FilePath -> a
errorWithoutStackTrace FilePath
"_NSGetExecutablePath: buffer too small"
foreign import ccall unsafe "stdlib.h realpath"
c_realpath :: CString -> CString -> IO CString
realpath :: FilePath -> IO FilePath
realpath :: FilePath -> IO FilePath
realpath FilePath
path =
FilePath -> (Ptr CChar -> IO FilePath) -> IO FilePath
forall a. FilePath -> (Ptr CChar -> IO a) -> IO a
withFilePath FilePath
path ((Ptr CChar -> IO FilePath) -> IO FilePath)
-> (Ptr CChar -> IO FilePath) -> IO FilePath
forall a b. (a -> b) -> a -> b
$ \ Ptr CChar
fileName ->
Int -> (Ptr CChar -> IO FilePath) -> IO FilePath
forall a b. Int -> (Ptr a -> IO b) -> IO b
allocaBytes Int
1024 ((Ptr CChar -> IO FilePath) -> IO FilePath)
-> (Ptr CChar -> IO FilePath) -> IO FilePath
forall a b. (a -> b) -> a -> b
$ \ Ptr CChar
resolvedName -> do
Ptr CChar
_ <- FilePath -> IO (Ptr CChar) -> IO (Ptr CChar)
forall a. FilePath -> IO (Ptr a) -> IO (Ptr a)
throwErrnoIfNull FilePath
"realpath" (IO (Ptr CChar) -> IO (Ptr CChar))
-> IO (Ptr CChar) -> IO (Ptr CChar)
forall a b. (a -> b) -> a -> b
$ Ptr CChar -> Ptr CChar -> IO (Ptr CChar)
c_realpath Ptr CChar
fileName Ptr CChar
resolvedName
Ptr CChar -> IO FilePath
peekFilePath Ptr CChar
resolvedName
getExecutablePath :: IO FilePath
getExecutablePath = IO FilePath
_NSGetExecutablePath IO FilePath -> (FilePath -> IO FilePath) -> IO FilePath
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= FilePath -> IO FilePath
realpath
executablePath :: Maybe (IO (Maybe FilePath))
executablePath = IO (Maybe FilePath) -> Maybe (IO (Maybe FilePath))
forall a. a -> Maybe a
Just ((FilePath -> Maybe FilePath) -> IO FilePath -> IO (Maybe FilePath)
forall a b. (a -> b) -> IO a -> IO b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap FilePath -> Maybe FilePath
forall a. a -> Maybe a
Just IO FilePath
getExecutablePath IO (Maybe FilePath)
-> (IOError -> IO (Maybe FilePath)) -> IO (Maybe FilePath)
forall e a. Exception e => IO a -> (e -> IO a) -> IO a
`catch` IOError -> IO (Maybe FilePath)
forall {f :: * -> *} {a}. Applicative f => IOError -> f (Maybe a)
f)
where
f :: IOError -> f (Maybe a)
f IOError
e | IOError -> Bool
isDoesNotExistError IOError
e = Maybe a -> f (Maybe a)
forall a. a -> f a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Maybe a
forall a. Maybe a
Nothing
| Bool
otherwise = IOError -> f (Maybe a)
forall a e. Exception e => e -> a
throw IOError
e
{-# LINE 371 "libraries/base/System/Environment/ExecutablePath.hsc" #-}