Question

I try to work with this simple C-code from Haskell:

time_t rawTime = time( NULL );
struct tm* timeInfo = localtime( &rawTime );  /* Using address of a local variable */
printf( "The current date is: %s", asctime( timeInfo ) );

So I write:

data CTmStruct = CTmStruct
type CTmStructPtr = Ptr CTmStruct

foreign import ccall "time"      c_time      :: Ptr CTime    -> IO CTime
foreign import ccall "localtime" c_localtime :: Ptr CTime    -> IO CTmStructPtr
foreign import ccall "asctime"   c_asctime   :: CTmStructPtr -> CString

main :: IO ()
main = do
    rawTime <- c_time nullPtr
    tmStructPtr <- c_localtime ???  -- How to get an address of rawTime?
    print $ c_asctime tmStructPtr

So how can I get an address of a local value rawTime for putting it as an argument of a c_localtime function? I've read documentation to Foreign module, but I didn't find answer for this question. I'd be very grateful for any help.

Was it helpful?

Solution

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top