+\begin{code}
+hConnectTerms :: Handle -> Handle -> IO ()
+hConnectTerms hW hR = hConnectHdl_ hW hR 1{-check if they're both coming connected to ttys-}
+
+hConnectTo :: Handle -> Handle -> IO ()
+hConnectTo hW hR = hConnectHdl_ hW hR 0{-connect regardless-}
+
+hConnectHdl_ :: Handle -> Handle -> Int -> IO ()
+hConnectHdl_ hW hR is_tty = do
+ hW_ <- wantWriteableHandle "hConnectTo" hW
+ hR_ <- wantReadableHandle "hConnectTo" hR
+ _ccall_ setConnectedTo (haFO__ hR_) (haFO__ hW_) is_tty -- ConcHask: SAFE, won't block
+ writeHandle hR hR_
+ writeHandle hW hW_
+
+\end{code}
+
+As an extension, we also allow characters to be pushed back.
+Like ANSI C stdio, we guarantee no more than one character of
+pushback. (For unbuffered channels, the (default) push-back limit is
+2 chars tho.)
+
+\begin{code}
+hUngetChar :: Handle -> Char -> IO ()
+hUngetChar handle c = do
+ handle_ <- wantReadableHandle "hLookAhead" handle
+ rc <- _ccall_ ungetChar (haFO__ handle_) (ord c) -- ConcHask: SAFE, won't block
+ writeHandle handle handle_
+ if rc == (-1)
+ then constructErrorAndFail "hUngetChar"
+ else return ()
+
+\end{code}
+
+
+Hoisting files in in one go is sometimes useful, so we support
+this as an extension:
+
+\begin{code}
+-- in one go, read file into an externally allocated buffer.
+slurpFile :: FilePath -> IO (Addr, Int)
+slurpFile fname = do
+ hdl <- openFile fname ReadMode
+ sz <- hFileSize hdl
+ if sz > toInteger (maxBound::Int) then
+ fail (userError "slurpFile: file too big")
+ else do
+ let sz_i = fromInteger sz
+ chunk <- _ccall_ allocMemory__ (sz_i::Int)
+ if chunk == nullAddr
+ then do
+ hClose hdl
+ constructErrorAndFail "slurpFile"
+ else do
+ handle_ <- readHandle hdl
+ let fo = haFO__ handle_
+ rc <- mayBlock fo (_ccall_ readChunk fo chunk sz_i) -- ConcHask: UNSAFE, may block.
+ writeHandle hdl handle_
+ hClose hdl
+ if rc < 0
+ then constructErrorAndFail "slurpFile"
+ else return (chunk, rc)
+
+\end{code}
+
+The @hPutBuf hdl buf len@ action writes an already packed sequence of
+bytes to the file/channel managed by @hdl@ - non-standard.
+
+\begin{code}
+hPutBuf :: Handle -> Addr -> Int -> IO ()
+hPutBuf handle buf len = do
+ handle_ <- wantWriteableHandle "hPutBuf" handle
+ let fo = haFO__ handle_
+ rc <- mayBlock fo (_ccall_ writeBuf fo buf len) -- ConcHask: UNSAFE, may block.
+ writeHandle handle handle_
+ if rc == 0
+ then return ()
+ else constructErrorAndFail "hPutBuf"
+
+hPutBufBA :: Handle -> ByteArray Int -> Int -> IO ()
+hPutBufBA handle buf len = do
+ handle_ <- wantWriteableHandle "hPutBufBA" handle
+ let fo = haFO__ handle_
+ rc <- mayBlock fo (_ccall_ writeBufBA fo buf len) -- ConcHask: UNSAFE, may block.
+ writeHandle handle handle_
+ if rc == 0
+ then return ()
+ else constructErrorAndFail "hPutBuf"
+\end{code}
+
+Sometimes it's useful to get at the file descriptor that
+the Handle contains..
+
+\begin{code}
+getHandleFd :: Handle -> IO Int
+getHandleFd handle = do
+ handle_ <- readHandle handle
+ case (haType__ handle_) of
+ ErrorHandle ioError -> do
+ writeHandle handle handle_
+ fail ioError
+ ClosedHandle -> do
+ writeHandle handle handle_
+ ioe_closedHandle "getHandleFd" handle
+ _ -> do
+ fd <- _ccall_ getFileFd (haFO__ handle_)
+ writeHandle handle handle_
+ return fd
+\end{code}