I was able to do:
import Foreign.C.String
import Foreign.Marshal.Alloc
-- Your declarations and foreign bindings here
getTime :: IO String
getTime = do
p <- malloc
c_time p
tmPtr <- c_localtime p
str <- peekCString $ c_asctime tmPtr
free p
return str
main :: IO ()
main = do
currentTime <- getTime
putStrLn currentTime
The key is using malloc
and free
, you explicitly allocate the space, pass it to c_time
to set the contents, then c_localtime
to format it as a CTmStruct
, then pass that to c_asctime
to convert to a CString
, marshal back to a Haskell String
with peekCString
, and finally free the pointer used to get the time.
I guess I should have realized this sooner, but a better solution would be to use alloca
:
getTime :: IO String
getTime = alloca $ \p -> do
c_time p
tm <- c_localtime p
peekCString $ c_astime tm
Which is safer, shorter, and easier. The alloca
function does the allocation and freeing of the pointer for you, all you have to do is use it.