module Network.HostName (
    HostName, getHostName
  ) where

import Foreign.C.Error
import Foreign.C.String
import Foreign.C.Types
import Foreign.Marshal.Array

#ifdef WINDOWS

import Foreign.Marshal.Utils
import Foreign.Ptr
import Foreign.Storable

import System.Win32.Types

foreign import stdcall unsafe "windows.h GetComputerNameExW" getComputerNameEx :: COMPUTER_NAME_FORMAT -> LPTSTR -> LPDWORD -> IO BOOL

type COMPUTER_NAME_FORMAT = CInt

computerNamePhysicalDnsHostname :: COMPUTER_NAME_FORMAT
computerNamePhysicalDnsHostname = 5

getHostName :: IO HostName
getHostName = with 0 $ \p_charcount -> do
    -- On the first run, determine the character count and ignore any error we get
    _ <- getComputerNameEx computerNamePhysicalDnsHostname nullPtr p_charcount
    charcount <- peek p_charcount
    
    -- The second time around, use the correct character count to retrieve the data
    withTString (replicate (fromIntegral charcount) ' ') $ \name -> do
        failIfFalse_ "GetComputerNameExW" $ getComputerNameEx computerNamePhysicalDnsHostname name p_charcount
        peekTString name

#else

foreign import ccall unsafe "gethostname" gethostname :: CString -> CSize -> IO CInt

getHostName :: IO HostName
getHostName :: IO HostName
getHostName = Int -> (Ptr CChar -> IO HostName) -> IO HostName
forall a b. Storable a => Int -> (Ptr a -> IO b) -> IO b
allocaArray0 Int
size ((Ptr CChar -> IO HostName) -> IO HostName)
-> (Ptr CChar -> IO HostName) -> IO HostName
forall a b. (a -> b) -> a -> b
$ \Ptr CChar
cstr -> do
        HostName -> IO CInt -> IO ()
forall a. (Eq a, Num a) => HostName -> IO a -> IO ()
throwErrnoIfMinus1_ HostName
"getHostName" (IO CInt -> IO ()) -> IO CInt -> IO ()
forall a b. (a -> b) -> a -> b
$ Ptr CChar -> CSize -> IO CInt
gethostname Ptr CChar
cstr (Int -> CSize
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
size)
        Ptr CChar -> IO HostName
peekCString Ptr CChar
cstr
    where size :: Int
size = Int
256

#endif

type HostName = String