[project @ 1997-12-04 11:05:32 by simonm]
[ghc-hetmet.git] / ghc / lib / ghc / IOHandle.lhs
index 67b1978..b0c3c81 100644 (file)
@@ -8,21 +8,34 @@ This module defines Haskell {\em handles} and the basic operations
 which are supported for them.
 
 \begin{code}
+{-# OPTIONS -fno-implicit-prelude -#include "cbits/stgio.h" #-}
 #include "error.h"
 
+
 module IOHandle where
 
-import Prelude ()
 import ST
 import STBase
-import ArrBase ( ByteArray(..) )
+import ArrBase ( ByteArray(..), newVar, readVar, writeVar )
 import PrelRead        ( Read )
+import PrelList (span)
 import Ix
 import IOBase
+import Unsafe   ( unsafePerformIO )
 import PrelTup
+import PrelMaybe
 import PrelBase
 import GHC
+import Addr
+import Error
+
+#ifndef __PARALLEL_HASKELL__
+import Foreign  ( ForeignObj, makeForeignObj, writeForeignObj )
+#endif
 
+#if defined(__CONCURRENT_HASKELL__)
+import ConcBase
+#endif
 \end{code}
 
 
@@ -32,43 +45,28 @@ import GHC
 %*                                                     *
 %*********************************************************
 
+The @Handle@ and @Handle__@ types are defined in @IOBase@.
+
 \begin{code}
 type FilePath = String
 
-#if defined(__CONCURRENT_HASKELL__)
-type Handle = MVar Handle__
+{-# INLINE newHandle   #-}
+{-# INLINE readHandle  #-}
+{-# INLINE writeHandle #-}
+newHandle   :: Handle__ -> IO Handle
+readHandle  :: Handle   -> IO Handle__
+writeHandle :: Handle -> Handle__ -> IO ()
 
+#if defined(__CONCURRENT_HASKELL__)
 newHandle   = newMVar
 readHandle  = takeMVar
 writeHandle = putMVar
-
-#else
-type Handle = MutableVar RealWorld Handle__
-
+#else 
 newHandle v     = stToIO (newVar   v)
 readHandle h    = stToIO (readVar  h)
 writeHandle h v = stToIO (writeVar h v)
+#endif
 
-#endif {- __CONCURRENT_HASKELL__ -}
-
-data Handle__
-  = ErrorHandle                IOError
-  | ClosedHandle
-  | SemiClosedHandle   Addr (Addr, Int)
-  | ReadHandle         Addr (Maybe BufferMode) Bool
-  | WriteHandle                Addr (Maybe BufferMode) Bool
-  | AppendHandle       Addr (Maybe BufferMode) Bool
-  | ReadWriteHandle    Addr (Maybe BufferMode) Bool
-
-instance Eq Handle{-partain:????-}
-
-{-# INLINE newHandle   #-}
-{-# INLINE readHandle  #-}
-{-# INLINE writeHandle #-}
-
-newHandle   :: Handle__ -> IO Handle
-readHandle  :: Handle   -> IO Handle__
-writeHandle :: Handle -> Handle__ -> IO ()
 \end{code}
 
 %*********************************************************
@@ -78,7 +76,11 @@ writeHandle :: Handle -> Handle__ -> IO ()
 %*********************************************************
 
 \begin{code}
+#ifndef __PARALLEL_HASKELL__
+filePtr :: Handle__ -> ForeignObj
+#else
 filePtr :: Handle__ -> Addr
+#endif
 filePtr (SemiClosedHandle fp _)  = fp
 filePtr (ReadHandle fp _ _)     = fp
 filePtr (WriteHandle fp _ _)    = fp
@@ -122,44 +124,50 @@ standard error channel. These handles are initially open.
 \begin{code}
 stdin, stdout, stderr :: Handle
 
-stdin = unsafePerformPrimIO (
-    _ccall_ getLock (``stdin''::Addr) 0                >>= \ rc ->
-    (case rc of
-       0 -> new_handle ClosedHandle
-       1 -> new_handle (ReadHandle ``stdin'' Nothing False)
-       _ -> constructError "stdin"             >>= \ ioError -> 
-            new_handle (ErrorHandle ioError)
-    )                                          >>= \ handle ->
-    returnPrimIO handle
+stdin = unsafePerformIO (do
+    rc <- _ccall_ getLock (``stdin''::Addr) 0
+    case rc of
+       0 -> newHandle ClosedHandle
+       1 -> do
+#ifndef __PARALLEL_HASKELL__
+            fp <- makeForeignObj (``stdin''::Addr) (``&freeStdFile''::Addr)
+           newHandle (ReadHandle fp Nothing False)
+#else
+           newHandle (ReadHandle ``stdin'' Nothing False)
+#endif
+       _ -> do ioError <- constructError "stdin"
+               newHandle (ErrorHandle ioError)
   )
-  where
-    new_handle x = ioToST (newHandle x)
-
-stdout = unsafePerformPrimIO (
-    _ccall_ getLock (``stdout''::Addr) 1       >>= \ rc ->
-    (case rc of
-       0 -> new_handle ClosedHandle
-       1 -> new_handle (WriteHandle ``stdout'' Nothing False)
-       _ -> constructError "stdout"            >>= \ ioError -> 
-            new_handle (ErrorHandle ioError)
-    )                                          >>= \ handle ->
-    returnPrimIO handle
+
+stdout = unsafePerformIO (do
+    rc <- _ccall_ getLock (``stdout''::Addr) 1
+    case rc of
+       0 -> newHandle ClosedHandle
+       1 -> do
+#ifndef __PARALLEL_HASKELL__
+            fp <- makeForeignObj (``stdout''::Addr) (``&freeStdFile''::Addr)
+           newHandle (WriteHandle fp Nothing False)
+#else
+           newHandle (WriteHandle ``stdout'' Nothing False)
+#endif
+       _ -> do ioError <- constructError "stdout"
+               newHandle (ErrorHandle ioError)
   )
-  where
-    new_handle x = ioToST (newHandle x)
-
-stderr = unsafePerformPrimIO (
-    _ccall_ getLock (``stderr''::Addr) 1       >>= \ rc ->
-    (case rc of
-       0 -> new_handle ClosedHandle
-       1 -> new_handle (WriteHandle ``stderr'' (Just NoBuffering) False)       
-       _ -> constructError "stderr"            >>= \ ioError -> 
-            new_handle (ErrorHandle ioError)
-    )                                          >>= \ handle ->
-    returnPrimIO handle
+
+stderr = unsafePerformIO (do
+    rc <- _ccall_ getLock (``stderr''::Addr) 1
+    case rc of
+       0 -> newHandle ClosedHandle
+       1 -> do
+#ifndef __PARALLEL_HASKELL__
+            fp <- makeForeignObj (``stderr''::Addr) (``&freeStdFile''::Addr)
+            newHandle (WriteHandle fp (Just NoBuffering) False)        
+#else
+            newHandle (WriteHandle ``stderr'' (Just NoBuffering) False)
+#endif
+       _ -> do ioError <- constructError "stderr"
+               newHandle (ErrorHandle ioError)
   )
-  where
-    new_handle x = ioToST (newHandle x)
 \end{code}
 
 %*********************************************************
@@ -174,20 +182,24 @@ data IOMode      =  ReadMode | WriteMode | AppendMode | ReadWriteMode
 
 openFile :: FilePath -> IOMode -> IO Handle
 
-openFile f m = 
-    stToIO (_ccall_ openFile f m')                 >>= \ ptr ->
-    if ptr /= ``NULL'' then
-        newHandle (htype ptr Nothing False)
-    else
-       stToIO (constructError "openFile")          >>= \ ioError -> 
+openFile f m = do
+    ptr <- _ccall_ openFile f m'
+    if ptr /= ``NULL'' then do
+#ifndef __PARALLEL_HASKELL__
+       fp <- makeForeignObj ptr ((``&freeFile'')::Addr)
+       newHandle (htype fp Nothing False)
+#else
+       newHandle (htype ptr Nothing False)
+#endif
+      else do
+       ioError@(IOError hn iot msg) <- constructError "openFile"
        let
            improved_error -- a HACK, I guess
-             = case ioError of
-                 AlreadyExists    msg -> AlreadyExists    (msg ++ ": " ++ f)
-                 NoSuchThing      msg -> NoSuchThing      (msg ++ ": " ++ f)
-                 PermissionDenied msg -> PermissionDenied (msg ++ ": " ++ f)
-                 _                    -> ioError
-       in
+             = case iot of
+                 AlreadyExists    -> IOError hn AlreadyExists    (msg ++ ": " ++ f)
+                 NoSuchThing      -> IOError hn NoSuchThing      (msg ++ ": " ++ f)
+                 PermissionDenied -> IOError hn PermissionDenied (msg ++ ": " ++ f)
+                 _                -> ioError
         fail improved_error
   where
     m' = case m of 
@@ -230,33 +242,55 @@ implementation is free to impose stricter conditions.
 \begin{code}
 hClose :: Handle -> IO ()
 
-hClose handle =
-    readHandle handle                              >>= \ htype ->
-    writeHandle handle ClosedHandle                >>
+hClose handle = do
+    htype <- readHandle handle
     case htype of 
-      ErrorHandle ioError ->
+      ErrorHandle ioError -> do
+         writeHandle handle htype
          fail ioError
-      ClosedHandle -> 
-         fail (IllegalOperation "handle is closed")
-      SemiClosedHandle fp (buf,_) ->
-          (if buf /= ``NULL'' then
-             _ccall_ free buf
-           else                            
-              returnPrimIO ())                     `thenIO_Prim` \ () ->
-          if fp /= ``NULL'' then
-              _ccall_ closeFile fp                 `thenIO_Prim` \ rc ->
-              if rc == 0 then 
-                 return ()
-              else
+      ClosedHandle -> do
+          writeHandle handle htype
+         ioe_closedHandle handle
+      SemiClosedHandle fp (buf,_) -> do
+          (if buf /= ``NULL'' then 
+               _ccall_ free buf 
+          else 
+               return ())
+         fp_a <- _casm_ `` %r = (char *)%0; '' fp
+          if fp_a /= (``NULL''::Addr) then do 
+               -- Under what condition can this be NULL?
+                rc <- _ccall_ closeFile fp
+                 {- We explicitly close a file object so that we can be told
+                    if there were any errors. Note that after @hClose@
+                    has been performed, the ForeignObj embedded in the Handle
+                     is still lying around in the heap, so care is taken
+                     to avoid closing the file object when the ForeignObj
+                    is finalised.  -}
+                if rc == 0 then do
+#ifndef __PARALLEL_HASKELL__
+                 -- Mark the foreign object data value as 
+                 -- gone to the finaliser (freeFile())
+                 writeForeignObj fp ``NULL''
+#endif
+                 writeHandle handle ClosedHandle
+                 else do
+                 writeHandle handle htype
                  constructErrorAndFail "hClose"
-          else                     
-              return ()
-      other -> 
-          _ccall_ closeFile (filePtr other)        `thenIO_Prim` \ rc ->
-          if rc == 0 then 
-             return ()
-          else
-             constructErrorAndFail "hClose"
+
+            else  writeHandle handle htype
+
+      other -> do
+         let fp = filePtr other
+          rc <- _ccall_ closeFile fp
+          if rc == 0 then do
+#ifndef __PARALLEL_HASKELL__
+               -- Mark the foreign object data
+               writeForeignObj fp ``NULL''
+#endif
+               writeHandle handle ClosedHandle
+            else do
+               writeHandle handle htype
+               constructErrorAndFail "hClose"
 \end{code}
 
 Computation $hClose hdl$ makes handle {\em hdl} closed.  Before the
@@ -276,34 +310,36 @@ which can be read from {\em hdl}.
 
 \begin{code}
 hFileSize :: Handle -> IO Integer
-hFileSize handle =
-    readHandle handle                              >>= \ htype ->
+hFileSize handle = do
+    htype <- readHandle handle
     case htype of 
-      ErrorHandle ioError ->
-         writeHandle handle htype                          >>
+      ErrorHandle ioError -> do
+         writeHandle handle htype
          fail ioError
-      ClosedHandle -> 
-         writeHandle handle htype                          >>
-          fail (IllegalOperation "handle is closed")
-      SemiClosedHandle _ _ -> 
-         writeHandle handle htype                          >>
-          fail (IllegalOperation "handle is closed")
+      ClosedHandle -> do
+         writeHandle handle htype
+         ioe_closedHandle handle
+      SemiClosedHandle _ _ -> do
+         writeHandle handle htype
+         ioe_closedHandle handle
       other ->
           -- HACK!  We build a unique MP_INT of the right shape to hold
-          -- a single unsigned word, and we let the C routine change the data bits
-          _casm_ ``%r = 1;''                       `thenIO_Prim` \ (I# hack#) ->
+          -- a single unsigned word, and we let the C routine 
+         -- change the data bits
+         --
+         -- For some reason, this fails to typecheck if converted to a do
+         -- expression --SDM
+          _casm_ ``%r = 1;'' >>= \(I# hack#) ->
           case int2Integer# hack# of
-            result@(J# _ _ d#) ->
-               let
-                   bogus_bounds = (error "fileSize"::(Int,Int))
-               in
-                _ccall_ fileSize (filePtr other) (ByteArray bogus_bounds d#)
-                                                    `thenIO_Prim` \ rc ->
-               writeHandle handle htype                    >>
-               if rc == 0 then
+            result@(J# _ _ d#) -> do
+               let bogus_bounds = (error "fileSize"::(Int,Int))
+                rc <- _ccall_ fileSize (filePtr other) 
+                               (ByteArray bogus_bounds d#)
+                writeHandle handle htype
+                if rc == 0 then
                   return result
-               else
-                   constructErrorAndFail "hFileSize"
+                 else
+                  constructErrorAndFail "hFileSize"
 \end{code}
 
 For a readable handle {\em hdl}, computation $hIsEOF hdl$ returns
@@ -313,27 +349,29 @@ the file.  Otherwise, it returns $False$.
 
 \begin{code}
 hIsEOF :: Handle -> IO Bool
-hIsEOF handle =
-    readHandle handle                              >>= \ htype ->
+hIsEOF handle = do
+    htype <- readHandle handle
     case htype of 
-      ErrorHandle ioError ->
-         writeHandle handle htype                  >>
+      ErrorHandle ioError -> do
+         writeHandle handle htype
          fail ioError
-      ClosedHandle -> 
-         writeHandle handle htype                  >>
-          fail (IllegalOperation "handle is closed")
-      SemiClosedHandle _ _ -> 
-         writeHandle handle htype                  >>
-          fail (IllegalOperation "handle is closed")
-      WriteHandle _ _ _ -> 
-         writeHandle handle htype                  >>
-          fail (IllegalOperation "handle is not open for reading")
-      AppendHandle _ _ _ -> 
-         writeHandle handle htype                  >>
-          fail (IllegalOperation "handle is not open for reading")
-      other -> 
-          _ccall_ fileEOF (filePtr other)          `thenIO_Prim` \ rc ->
-         writeHandle handle (markHandle htype)     >>
+      ClosedHandle -> do
+         writeHandle handle htype
+         ioe_closedHandle handle
+      SemiClosedHandle _ _ -> do
+         writeHandle handle htype
+         ioe_closedHandle handle
+      WriteHandle _ _ _ -> do
+         writeHandle handle htype
+          fail (IOError (Just handle) IllegalOperation 
+               "handle is not open for reading")
+      AppendHandle _ _ _ -> do 
+         writeHandle handle htype
+          fail (IOError (Just handle) IllegalOperation 
+               "handle is not open for reading")
+      other -> do
+          rc <- _ccall_ fileEOF (filePtr other)
+         writeHandle handle (markHandle htype)
          case rc of
             0 -> return False
             1 -> return True
@@ -350,62 +388,26 @@ isEOF = hIsEOF stdin
 %*********************************************************
 
 Three kinds of buffering are supported: line-buffering, 
-block-buffering or no-buffering.  These modes have the following effects.
-For output, items are written out from the internal buffer 
-according to the buffer mode:
-\begin{itemize}
-\item[line-buffering]  the entire output buffer is written
-out whenever a newline is output, the output buffer overflows, 
-a flush is issued, or the handle is closed.
-
-\item[block-buffering] the entire output buffer is written out whenever 
-it overflows, a flush is issued, or the handle
-is closed.
-
-\item[no-buffering] output is written immediately, and never stored
-in the output buffer.
-\end{itemize}
-
-The output buffer is emptied as soon as it has been written out.
-
-Similarly, input occurs according to the buffer mode for handle {\em hdl}.
-\begin{itemize}
-\item[line-buffering] when the input buffer for {\em hdl} is not empty,
-the next item is obtained from the buffer;
-otherwise, when the input buffer is empty,
-characters up to and including the next newline
-character are read into the buffer.  No characters
-are available until the newline character is
-available.
-\item[block-buffering] when the input buffer for {\em hdl} becomes empty,
-the next block of data is read into this buffer.
-\item[no-buffering] the next input item is read and returned.
-\end{itemize}
-For most implementations, physical files will normally be block-buffered 
-and terminals will normally be line-buffered.
+block-buffering or no-buffering.  See @IOBase@ for definition
+and further explanation of what the type represent.
 
-\begin{code}
-data BufferMode  =  NoBuffering | LineBuffering | BlockBuffering (Maybe Int)
-                    deriving (Eq, Ord, Read, Show)
-\end{code}
-
-Computation $hSetBuffering hdl mode$ sets the mode of buffering for
+Computation @hSetBuffering hdl mode@ sets the mode of buffering for
 handle {\em hdl} on subsequent reads and writes.
 
 \begin{itemize}
 \item
-If {\em mode} is $LineBuffering$, line-buffering should be
+If {\em mode} is @LineBuffering@, line-buffering should be
 enabled if possible.
 \item
-If {\em mode} is $BlockBuffering$ {\em size}, then block-buffering
+If {\em mode} is @BlockBuffering@ {\em size}, then block-buffering
 should be enabled if possible.  The size of the buffer is {\em n} items
-if {\em size} is $Just${\em n} and is otherwise implementation-dependent.
+if {\em size} is @Just@~{\em n} and is otherwise implementation-dependent.
 \item
-If {\em mode} is $NoBuffering$, then buffering is disabled if possible.
+If {\em mode} is @NoBuffering@, then buffering is disabled if possible.
 \end{itemize}
 
-If the buffer mode is changed from $BlockBuffering$ or $LineBuffering$
-to $NoBuffering$, then any items in the output buffer are written to
+If the buffer mode is changed from @BlockBuffering@ or @LineBuffering@
+to @NoBuffering@, then any items in the output buffer are written to
 the device, and any items in the input buffer are discarded.  The
 default buffering mode when a handle is opened is
 implementation-dependent and may depend on the object which is
@@ -416,33 +418,34 @@ hSetBuffering :: Handle -> BufferMode -> IO ()
 
 hSetBuffering handle mode =
     case mode of
-      (BlockBuffering (Just n)) 
-        | n <= 0 -> fail (InvalidArgument "illegal buffer size")
-      other ->
-         readHandle handle                         >>= \ htype ->
-          if isMarked htype then
-              writeHandle handle htype             >>
-              fail (UnsupportedOperation "can't set buffering for a dirty handle")
-          else
+      BlockBuffering (Just n) 
+        | n <= 0 -> fail (IOError (Just handle) InvalidArgument 
+                               "illegal buffer size")
+      other -> do
+         htype <- readHandle handle
+          if isMarked htype then do
+              writeHandle handle htype
+              fail (IOError (Just handle) 
+                           UnsupportedOperation 
+                           "can't set buffering for a dirty handle")
+           else
               case htype of
-               ErrorHandle ioError ->
-                   writeHandle handle htype        >>
+               ErrorHandle ioError -> do
+                   writeHandle handle htype
                    fail ioError
-                ClosedHandle ->
-                   writeHandle handle htype        >>
-                   fail (IllegalOperation "handle is closed")
-                SemiClosedHandle _ _ ->
-                   writeHandle handle htype        >>
-                   fail (IllegalOperation "handle is closed")
-                other ->
-                    _ccall_ setBuffering (filePtr other) bsize
-                                                   `thenIO_Prim` \ rc -> 
+                ClosedHandle -> do
+                   writeHandle handle htype
+                   ioe_closedHandle handle
+                SemiClosedHandle _ _ -> do
+                   writeHandle handle htype
+                   ioe_closedHandle handle
+                other -> do
+                    rc <- _ccall_ setBuffering (filePtr other) bsize
                     if rc == 0 then
-                        writeHandle handle ((hcon other) (filePtr other) (Just mode) True)
-                                                   >>
-                       return ()
-                    else
-                       writeHandle handle htype         >>
+                        writeHandle handle ((hcon other) (filePtr other) 
+                                               (Just mode) True)
+                     else do
+                       writeHandle handle htype
                        constructErrorAndFail "hSetBuffering"
                
   where
@@ -459,7 +462,11 @@ hSetBuffering handle mode =
               BlockBuffering Nothing -> -2
               BlockBuffering (Just n) -> n
 
+#ifndef __PARALLEL_HASKELL__
+    hcon :: Handle__ -> (ForeignObj -> (Maybe BufferMode) -> Bool -> Handle__)
+#else
     hcon :: Handle__ -> (Addr -> (Maybe BufferMode) -> Bool -> Handle__)
+#endif
     hcon (ReadHandle _ _ _) = ReadHandle
     hcon (WriteHandle _ _ _) = WriteHandle
     hcon (AppendHandle _ _ _) = AppendHandle
@@ -471,25 +478,25 @@ Computation $flush hdl$ causes any items buffered for output in handle
 
 \begin{code}
 hFlush :: Handle -> IO () 
-hFlush handle = 
-    readHandle handle                              >>= \ htype ->
+hFlush handle = do
+    htype <- readHandle handle
     case htype of 
-      ErrorHandle ioError ->
-         writeHandle handle htype                  >>
+      ErrorHandle ioError -> do
+         writeHandle handle htype
          fail ioError
-      ClosedHandle ->
-         writeHandle handle htype                  >>
-         fail (IllegalOperation "handle is closed")
-      SemiClosedHandle _ _ ->
-         writeHandle handle htype                  >>
-         fail (IllegalOperation "handle is closed")
-      other ->
-         _ccall_ flushFile (filePtr other)         `thenIO_Prim` \ rc ->
-         writeHandle handle (markHandle htype)   >>
-               if rc == 0 then 
-                  return ()
-               else
-                   constructErrorAndFail "hFlush"
+      ClosedHandle -> do
+         writeHandle handle htype
+          ioe_closedHandle handle
+      SemiClosedHandle _ _ -> do
+         writeHandle handle htype
+          ioe_closedHandle handle
+      other -> do
+         rc <- _ccall_ flushFile (filePtr other)
+         writeHandle handle (markHandle htype)
+          if rc == 0 then 
+               return ()
+           else
+               constructErrorAndFail "hFlush"
 \end{code}
 
 
@@ -502,8 +509,6 @@ hFlush handle =
 \begin{code}
 data HandlePosn = HandlePosn Handle Int
 
-instance Eq HandlePosn{-partain-}
-
 data SeekMode    =  AbsoluteSeek | RelativeSeek | SeekFromEnd
                     deriving (Eq, Ord, Ix, Enum, Read, Show)
 \end{code}
@@ -515,49 +520,49 @@ to a previously obtained position {\em p}.
 
 \begin{code}
 hGetPosn :: Handle -> IO HandlePosn
-hGetPosn handle = 
-    readHandle handle                              >>= \ htype ->
+hGetPosn handle = do
+    htype <- readHandle handle
     case htype of 
-      ErrorHandle ioError ->
-         writeHandle handle htype                  >>
+      ErrorHandle ioError -> do
+         writeHandle handle htype
          fail ioError
-      ClosedHandle ->
-         writeHandle handle htype                  >>
-         fail (IllegalOperation "handle is closed")
-      SemiClosedHandle _ _ ->
-         writeHandle handle htype                  >>
-         fail (IllegalOperation "handle is closed")
-      other -> 
-          _ccall_ getFilePosn (filePtr other)      `thenIO_Prim` \ posn ->
-          writeHandle handle htype                 >>
+      ClosedHandle -> do
+         writeHandle handle htype
+          ioe_closedHandle handle
+      SemiClosedHandle _ _ -> do
+         writeHandle handle htype
+          ioe_closedHandle handle
+      other -> do
+          posn <- _ccall_ getFilePosn (filePtr other)
+          writeHandle handle htype
           if posn /= -1 then
              return (HandlePosn handle posn)
-          else
+           else
              constructErrorAndFail "hGetPosn"
 
 hSetPosn :: HandlePosn -> IO () 
-hSetPosn (HandlePosn handle posn) = 
-    readHandle handle                              >>= \ htype ->
+hSetPosn (HandlePosn handle posn) = do
+    htype <- readHandle handle
     case htype of 
-      ErrorHandle ioError ->
-         writeHandle handle htype                  >>
+      ErrorHandle ioError -> do
+         writeHandle handle htype
          fail ioError
-      ClosedHandle ->
-         writeHandle handle htype                  >>
-         fail (IllegalOperation "handle is closed")
-      SemiClosedHandle _ _ ->
-         writeHandle handle htype                  >>
-         fail (IllegalOperation "handle is closed")
-      AppendHandle _ _ _ ->
-         writeHandle handle htype                  >>
-         fail (IllegalOperation "handle is not seekable")
-      other -> 
-         _ccall_ setFilePosn (filePtr other) posn `thenIO_Prim` \ rc ->
-         writeHandle handle (markHandle htype)    >>
-               if rc == 0 then 
-                  return ()
-               else
-                  constructErrorAndFail "hSetPosn"
+      ClosedHandle -> do
+         writeHandle handle htype
+          ioe_closedHandle handle
+      SemiClosedHandle _ _ -> do
+         writeHandle handle htype
+          ioe_closedHandle handle
+      AppendHandle _ _ _ -> do
+         writeHandle handle htype
+         fail (IOError (Just handle) IllegalOperation "handle is not seekable")
+      other -> do
+         rc <- _ccall_ setFilePosn (filePtr other) posn
+         writeHandle handle (markHandle htype)
+          if rc == 0 then 
+               return ()
+           else
+               constructErrorAndFail "hSetPosn"
 \end{code}
 
 Computation $hSeek hdl mode i$ sets the position of handle
@@ -582,35 +587,35 @@ file, an I/O position beyond the current end-of-file.
 
 \begin{code}
 hSeek :: Handle -> SeekMode -> Integer -> IO () 
-hSeek handle mode offset@(J# _ s# d#) = 
-    readHandle handle                              >>= \ htype ->
+hSeek handle mode offset@(J# _ s# d#) =  do
+    htype <- readHandle handle
     case htype of 
-      ErrorHandle ioError ->
-         writeHandle handle htype                  >>
+      ErrorHandle ioError -> do
+         writeHandle handle htype
          fail ioError
-      ClosedHandle ->
-         writeHandle handle htype                  >>
-         fail (IllegalOperation "handle is closed")
-      SemiClosedHandle _ _ ->
-         writeHandle handle htype                  >>
-         fail (IllegalOperation "handle is closed")
-      AppendHandle _ _ _ ->
-         writeHandle handle htype                  >>
-         fail (IllegalOperation "handle is not seekable")
-      other -> 
-         _ccall_ seekFile (filePtr other) whence (I# s#) (ByteArray (0,0) d#)
-                                                   `thenIO_Prim` \ rc ->
-         writeHandle handle (markHandle htype)   >>
-               if rc == 0 then 
-                  return ()
-               else
-                   constructErrorAndFail "hSeek"
+      ClosedHandle -> do
+         writeHandle handle htype
+          ioe_closedHandle handle
+      SemiClosedHandle _ _ -> do
+         writeHandle handle htype
+          ioe_closedHandle handle
+      AppendHandle _ _ _ -> do
+         writeHandle handle htype
+         fail (IOError (Just handle) IllegalOperation "handle is not seekable")
+      other -> do
+         rc <- _ccall_ seekFile (filePtr other) whence (I# s#) 
+                       (ByteArray (0,0) d#)
+         writeHandle handle (markHandle htype)
+          if rc == 0 then 
+               return ()
+           else
+               constructErrorAndFail "hSeek"
   where
     whence :: Int
     whence = case mode of
                AbsoluteSeek -> ``SEEK_SET''
                RelativeSeek -> ``SEEK_CUR''
-               SeekFromEnd -> ``SEEK_END''
+               SeekFromEnd  -> ``SEEK_END''
 \end{code}
 
 %*********************************************************
@@ -631,51 +636,51 @@ $( Just n )$ for block-buffering of {\em n} bytes.
 
 \begin{code}
 hIsOpen :: Handle -> IO Bool
-hIsOpen handle = 
-    readHandle handle                              >>= \ htype ->
+hIsOpen handle = do
+    htype <- readHandle handle
     case htype of 
-      ErrorHandle ioError ->
-         writeHandle handle htype                  >>
+      ErrorHandle ioError -> do
+         writeHandle handle htype
           fail ioError
-      ClosedHandle ->
-         writeHandle handle htype                  >>
+      ClosedHandle -> do
+         writeHandle handle htype
          return False
-      SemiClosedHandle _ _ ->
-         writeHandle handle htype                  >>
+      SemiClosedHandle _ _ -> do
+         writeHandle handle htype
          return False
-      other ->
-         writeHandle handle htype                  >>
+      other -> do
+         writeHandle handle htype
          return True
 
 hIsClosed :: Handle -> IO Bool
-hIsClosed handle = 
-    readHandle handle                              >>= \ htype ->
+hIsClosed handle = do
+    htype <- readHandle handle
     case htype of 
-      ErrorHandle ioError ->
-         writeHandle handle htype                  >>
+      ErrorHandle ioError -> do
+         writeHandle handle htype
           fail ioError
-      ClosedHandle ->
-         writeHandle handle htype                  >>
+      ClosedHandle -> do
+         writeHandle handle htype
          return True
-      other ->
-         writeHandle handle htype                  >>
+      other -> do
+         writeHandle handle htype
          return False
 
 hIsReadable :: Handle -> IO Bool
-hIsReadable handle = 
-    readHandle handle                              >>= \ htype ->
+hIsReadable handle = do
+    htype <- readHandle handle
     case htype of 
-      ErrorHandle ioError ->
-         writeHandle handle htype                  >>
+      ErrorHandle ioError -> do
+         writeHandle handle htype
           fail ioError
-      ClosedHandle ->
-         writeHandle handle htype                  >>
-         fail (IllegalOperation "handle is closed")
-      SemiClosedHandle _ _ ->
-         writeHandle handle htype                  >>
-         fail (IllegalOperation "handle is closed")
-      other ->
-         writeHandle handle htype                  >>
+      ClosedHandle -> do
+         writeHandle handle htype
+          ioe_closedHandle handle
+      SemiClosedHandle _ _ -> do
+         writeHandle handle htype
+          ioe_closedHandle handle
+      other -> do
+         writeHandle handle htype
          return (isReadable other)
   where
     isReadable (ReadHandle _ _ _) = True
@@ -683,20 +688,20 @@ hIsReadable handle =
     isReadable _ = False
 
 hIsWritable :: Handle -> IO Bool
-hIsWritable handle = 
-    readHandle handle                      >>= \ htype ->
+hIsWritable handle = do
+    htype <- readHandle handle
     case htype of 
-      ErrorHandle ioError ->
-         writeHandle handle htype          >>
+      ErrorHandle ioError -> do
+         writeHandle handle htype
           fail ioError
-      ClosedHandle ->
-         writeHandle handle htype          >>
-         fail (IllegalOperation "handle is closed")
-      SemiClosedHandle _ _ ->
-         writeHandle handle htype          >>
-         fail (IllegalOperation "handle is closed")
-      other ->
-         writeHandle handle htype          >>
+      ClosedHandle -> do
+         writeHandle handle htype
+          ioe_closedHandle handle
+      SemiClosedHandle _ _ -> do
+         writeHandle handle htype
+          ioe_closedHandle handle
+      other -> do
+         writeHandle handle htype
          return (isWritable other)
   where
     isWritable (AppendHandle _ _ _) = True
@@ -704,12 +709,12 @@ hIsWritable handle =
     isWritable (ReadWriteHandle _ _ _) = True
     isWritable _ = False
 
-getBufferMode :: Handle__ -> PrimIO Handle__
+getBufferMode :: Handle__ -> IO Handle__
 getBufferMode htype =
     case bufferMode htype of
-      Just x -> returnPrimIO htype
-      Nothing ->
-       _ccall_ getBufferMode (filePtr htype)       `thenPrimIO` \ rc ->
+      Just x -> return htype
+      Nothing -> do
+       rc <- _ccall_ getBufferMode (filePtr htype)
        let 
            mode = 
                case rc of
@@ -718,129 +723,128 @@ getBufferMode htype =
                  -2 -> Just (BlockBuffering Nothing)
                   -3 -> Nothing
                   n  -> Just (BlockBuffering (Just n))
-       in
-       returnPrimIO (case htype of
+       return (case htype of
          ReadHandle      fp _ b -> ReadHandle      fp mode b
          WriteHandle     fp _ b -> WriteHandle     fp mode b
          AppendHandle    fp _ b -> AppendHandle    fp mode b
          ReadWriteHandle fp _ b -> ReadWriteHandle fp mode b)
 
 hIsBlockBuffered :: Handle -> IO (Bool,Maybe Int)
-hIsBlockBuffered handle =
-    readHandle handle                              >>= \ htype ->
+hIsBlockBuffered handle = do
+    htype <- readHandle handle
     case htype of 
-      ErrorHandle ioError ->
-         writeHandle handle htype                  >>
+      ErrorHandle ioError -> do
+         writeHandle handle htype
           fail ioError
-      ClosedHandle ->
-         writeHandle handle htype                  >>
-         fail (IllegalOperation "handle is closed")
-      SemiClosedHandle _ _ ->
-         writeHandle handle htype                  >>
-         fail (IllegalOperation "handle is closed")
-      other ->
-          getBufferMode other                      `thenIO_Prim` \ other ->
+      ClosedHandle -> do
+         writeHandle handle htype
+          ioe_closedHandle handle
+      SemiClosedHandle _ _ -> do
+         writeHandle handle htype
+          ioe_closedHandle handle
+      other -> do
+          other <- getBufferMode other
           case bufferMode other of
-            Just (BlockBuffering size) ->
-               writeHandle handle other            >>
+            Just (BlockBuffering size) -> do
+               writeHandle handle other
                 return (True, size)
-            Just _ ->
-               writeHandle handle other            >>
+            Just _ -> do
+               writeHandle handle other
                 return (False, Nothing)
            Nothing -> 
                constructErrorAndFail "hIsBlockBuffered"
 
 hIsLineBuffered :: Handle -> IO Bool
-hIsLineBuffered handle =
-    readHandle handle                              >>= \ htype ->
+hIsLineBuffered handle = do
+    htype <- readHandle handle
     case htype of 
-      ErrorHandle ioError ->
-         writeHandle handle htype                  >>
+      ErrorHandle ioError -> do
+         writeHandle handle htype
           fail ioError
-      ClosedHandle ->
-         writeHandle handle htype                  >>
-         fail (IllegalOperation "handle is closed")
-      SemiClosedHandle _ _ ->
-         writeHandle handle htype                  >>
-         fail (IllegalOperation "handle is closed")
-      other ->
-         getBufferMode other                       `thenIO_Prim` \ other ->
+      ClosedHandle -> do
+         writeHandle handle htype
+          ioe_closedHandle handle
+      SemiClosedHandle _ _ -> do
+         writeHandle handle htype
+          ioe_closedHandle handle
+      other -> do
+         other <- getBufferMode other
           case bufferMode other of
-            Just LineBuffering ->
-               writeHandle handle other            >>
+            Just LineBuffering -> do
+               writeHandle handle other
                 return True
-            Just _ ->
-               writeHandle handle other            >>
+            Just _ -> do
+               writeHandle handle other
                 return False
            Nothing -> 
                constructErrorAndFail "hIsLineBuffered"
 
 hIsNotBuffered :: Handle -> IO Bool
-hIsNotBuffered handle =
-    readHandle handle                              >>= \ htype ->
+hIsNotBuffered handle = do
+    htype <- readHandle handle
     case htype of 
-      ErrorHandle ioError ->
-         writeHandle handle htype                  >>
+      ErrorHandle ioError -> do
+         writeHandle handle htype
           fail ioError
-      ClosedHandle ->
-         writeHandle handle htype                  >>
-         fail (IllegalOperation "handle is closed")
-      SemiClosedHandle _ _ ->
-         writeHandle handle htype                  >>
-         fail (IllegalOperation "handle is closed")
-      other ->
-         getBufferMode other                       `thenIO_Prim` \ other ->
+      ClosedHandle -> do
+         writeHandle handle htype
+          ioe_closedHandle handle
+      SemiClosedHandle _ _ -> do
+         writeHandle handle htype
+          ioe_closedHandle handle
+      other -> do
+         other <- getBufferMode other
           case bufferMode other of
-            Just NoBuffering ->
-               writeHandle handle other            >>
+            Just NoBuffering -> do
+               writeHandle handle other
                 return True
-            Just _ ->
-               writeHandle handle other            >>
+            Just _ -> do
+               writeHandle handle other
                 return False
            Nothing -> 
                constructErrorAndFail "hIsNotBuffered"
 
 hGetBuffering :: Handle -> IO BufferMode
-hGetBuffering hndl =
-    readHandle hndl                                >>= \ htype ->
+hGetBuffering handle = do
+    htype <- readHandle handle
     case htype of 
-      ErrorHandle ioError ->
-         writeHandle hndl htype                    >>
+      ErrorHandle ioError -> do
+         writeHandle handle htype
           fail ioError
-      ClosedHandle ->
-         writeHandle hndl htype                    >>
-         fail (IllegalOperation "handle is closed")
-      SemiClosedHandle _ _ ->
-         writeHandle hndl htype                    >>
-         fail (IllegalOperation "handle is closed")
-      other ->
-         getBufferMode other                       `thenIO_Prim` \ other ->
+      ClosedHandle -> do
+         writeHandle handle htype
+          ioe_closedHandle handle
+      SemiClosedHandle _ _ -> do
+         writeHandle handle htype
+          ioe_closedHandle handle
+      other -> do
+         other <- getBufferMode other
           case bufferMode other of
-            Just v ->
-               writeHandle hndl other              >>
+            Just v -> do
+               writeHandle handle other
                 return v
            Nothing -> 
                constructErrorAndFail "hGetBuffering"
 
 hIsSeekable :: Handle -> IO Bool
-hIsSeekable handle = 
-    readHandle handle                              >>= \ htype ->
+hIsSeekable handle = do
+    htype <- readHandle handle
     case htype of 
-      ErrorHandle ioError ->
-         writeHandle handle htype                  >>
+      ErrorHandle ioError -> do
+         writeHandle handle htype
           fail ioError
-      ClosedHandle ->
-         writeHandle handle htype                  >>
-         fail (IllegalOperation "handle is closed")
-      SemiClosedHandle _ _ ->
-         writeHandle handle htype                  >>
-         fail (IllegalOperation "handle is closed")
-      AppendHandle _ _ _ ->
-         writeHandle handle htype                  >>
+      ClosedHandle -> do
+         writeHandle handle htype
+          ioe_closedHandle handle
+      SemiClosedHandle _ _ -> do
+         writeHandle handle htype
+          ioe_closedHandle handle
+      AppendHandle _ _ _ -> do
+         writeHandle handle htype
          return False
-      other ->
-         _ccall_ seekFileP (filePtr other)         `thenIO_Prim` \ rc ->
-         writeHandle handle htype                  >>
+      other -> do
+         rc <- _ccall_ seekFileP (filePtr other)
+         writeHandle handle htype
          case rc of
             0 -> return False
             1 -> return True
@@ -858,10 +862,28 @@ These two functions are meant to get things out of @IOErrors@.  They don't!
 
 \begin{code}
 ioeGetFileName        :: IOError -> Maybe FilePath
+ioeGetErrorString     :: IOError -> String
 ioeGetHandle          :: IOError -> Maybe Handle
 
+ioeGetHandle   (IOError h _ _)   = h
+ioeGetErrorString (IOError _ iot str) =
+ case iot of
+   EOF -> "end of file"
+   _   -> str
+
+ioeGetFileName (IOError _ _ str) = 
+ case span (/=':') str of
+   (fs,[]) -> Nothing
+   (fs,_)  -> Just fs
 
-ioeGetHandle   _ = Nothing -- a stub, essentially
-ioeGetFileName _ = Nothing -- a stub, essentially
 \end{code}
 
+Internal function for creating an @IOError@ representing the
+access of a closed file.
+
+\begin{code}
+
+ioe_closedHandle :: Handle -> IO a
+ioe_closedHandle h = fail (IOError (Just h) IllegalOperation "handle is closed")
+
+\end{code}