content: module System.IO.StringHandle(handleWriteToString, stringToHandle) where
  import Prelude; import MiniPrelude
  import Foreign.C.String
  import Foreign.C.Types
  import Foreign.Marshal.Alloc
  import Foreign.Marshal.Utils
  import Foreign.Ptr
  import Foreign.Storable
  import System.IO
  import System.IO.Internal
  
  foreign import ccall "openb_wr_mem"          c_openb_wr_mem          :: IO (Ptr BFILE)
  foreign import ccall "openb_rd_mem"          c_openb_rd_mem          :: CString -> Int -> IO (Ptr BFILE)
  foreign import ccall "get_mem"               c_get_mem               :: Ptr BFILE -> Ptr CString -> Ptr Int -> IO ()
  
  -- Turn all writes to a Handle into a String.
  -- Do not close the Handle in the action
  handleWriteToString :: (Handle -> IO ()) -> IO String
  handleWriteToString act = do
    bf <- c_openb_wr_mem                         -- create a buffer
    h <- mkHandle "handleToString" bf HWrite
    act h
    hFlush h
    with nullPtr $ \ bufp ->
      with 0 $ \ lenp -> do
        c_get_mem bf bufp lenp                   -- get buffer and length
        buf <- peek bufp
        len <- peek lenp
        res <- peekCAStringLen (buf, len)        -- encode as a string
        free buf                                 -- free owned memory
        hClose h                                 -- close
        return res
  
  -- Make a Handle that will read from a String.
  -- Caller should close the Handle.
  stringToHandle :: String -> IO Handle
  stringToHandle file = do
    (ptr, len) <- newCAStringLen file            -- make memory buffer
    bf <- c_openb_rd_mem ptr len                 -- open it for reading
    mkHandle "stringToHandle" bf HRead           -- and make a handle
  