1 % -----------------------------------------------------------------------------
2 % $Id: IO.lhs,v 1.40 2000/06/30 13:39:35 simonmar Exp $
4 % (c) The University of Glasgow, 1994-2000
7 \section[IO]{Module @IO@}
9 Implementation of the standard Haskell IO interface, see
10 @http://haskell.org/onlinelibrary/io.html@ for the official
15 Handle, -- abstract, instance of: Eq, Show.
16 HandlePosn(..), -- abstract, instance of: Eq, Show.
18 IOMode(ReadMode,WriteMode,AppendMode,ReadWriteMode),
19 BufferMode(NoBuffering,LineBuffering,BlockBuffering),
20 SeekMode(AbsoluteSeek,RelativeSeek,SeekFromEnd),
22 stdin, stdout, stderr, -- :: Handle
24 openFile, -- :: FilePath -> IOMode -> IO Handle
25 hClose, -- :: Handle -> IO ()
26 hFileSize, -- :: Handle -> IO Integer
27 hIsEOF, -- :: Handle -> IO Bool
30 hSetBuffering, -- :: Handle -> BufferMode -> IO ()
31 hGetBuffering, -- :: Handle -> IO BufferMode
32 hFlush, -- :: Handle -> IO ()
33 hGetPosn, -- :: Handle -> IO HandlePosn
34 hSetPosn, -- :: Handle -> HandlePosn -> IO ()
35 hSeek, -- :: Handle -> SeekMode -> Integer -> IO ()
36 hWaitForInput, -- :: Handle -> Int -> IO Bool
37 hReady, -- :: Handle -> IO Bool
38 hGetChar, -- :: Handle -> IO Char
39 hGetLine, -- :: Handle -> IO [Char]
40 hLookAhead, -- :: Handle -> IO Char
41 hGetContents, -- :: Handle -> IO [Char]
42 hPutChar, -- :: Handle -> Char -> IO ()
43 hPutStr, -- :: Handle -> [Char] -> IO ()
44 hPutStrLn, -- :: Handle -> [Char] -> IO ()
45 hPrint, -- :: Show a => Handle -> a -> IO ()
46 hIsOpen, hIsClosed, -- :: Handle -> IO Bool
47 hIsReadable, hIsWritable, -- :: Handle -> IO Bool
48 hIsSeekable, -- :: Handle -> IO Bool
50 isAlreadyExistsError, isDoesNotExistError, -- :: IOError -> Bool
51 isAlreadyInUseError, isFullError,
52 isEOFError, isIllegalOperation,
53 isPermissionError, isUserError,
55 ioeGetErrorString, -- :: IOError -> String
56 ioeGetHandle, -- :: IOError -> Maybe Handle
57 ioeGetFileName, -- :: IOError -> Maybe FilePath
59 try, -- :: IO a -> IO (Either IOError a)
60 bracket, -- :: IO a -> (a -> IO b) -> (a -> IO c) -> IO c
61 bracket_, -- :: IO a -> (a -> IO b) -> IO c -> IO c
63 -- Non-standard extension (but will hopefully become standard with 1.5) is
64 -- to export the Prelude io functions via IO (in addition to exporting them
65 -- from the prelude...for now.)
67 FilePath, -- :: String
69 ioError, -- :: IOError -> IO a
70 userError, -- :: String -> IOError
71 catch, -- :: IO a -> (IOError -> IO a) -> IO a
72 interact, -- :: (String -> String) -> IO ()
74 putChar, -- :: Char -> IO ()
75 putStr, -- :: String -> IO ()
76 putStrLn, -- :: String -> IO ()
77 print, -- :: Show a => a -> IO ()
78 getChar, -- :: IO Char
79 getLine, -- :: IO String
80 getContents, -- :: IO String
81 readFile, -- :: FilePath -> IO String
82 writeFile, -- :: FilePath -> String -> IO ()
83 appendFile, -- :: FilePath -> String -> IO ()
84 readIO, -- :: Read a => String -> IO a
85 readLn, -- :: Read a => IO a
90 import PrelIOBase -- Together these four Prelude modules define
91 import PrelHandle -- all the stuff exported by IO for the GHC version
96 -- The entire rest of this module is just Hugs
98 #else /* ifndef __HUGS__ */
101 import PrelPrim ( IORef
103 , prelCleanupAfterRunAction
104 , copy_String_to_cstring
106 , primWriteCharOffAddr
127 %*********************************************************
129 \subsection{The HUGS version of IO
131 %*********************************************************
138 unimp s = error ("IO library: function not implemented: " ++ s)
140 type FILE_STAR = Addr
145 = Handle { name :: FilePath,
146 file :: FILE_STAR, -- C handle
147 mut :: IORef Handle_Mut, -- open/closed/semiclosed
153 = Handle_Mut { state :: HState
157 set_state :: Handle -> HState -> IO ()
158 set_state hdl new_state
159 = writeIORef (mut hdl) (Handle_Mut { state = new_state })
160 get_state :: Handle -> IO HState
162 = readIORef (mut hdl) >>= \m -> return (state m)
164 mkErr :: Handle -> String -> IO a
166 = do mut <- readIORef (mut h)
167 when (state mut /= HClosed)
168 (nh_close (file h) >> set_state h HClosed)
170 ioError (IOError msg)
175 file = unsafePerformIO nh_stdin,
176 mut = unsafePerformIO (newIORef (Handle_Mut { state = HOpen })),
183 file = unsafePerformIO nh_stdout,
184 mut = unsafePerformIO (newIORef (Handle_Mut { state = HOpen })),
191 file = unsafePerformIO nh_stderr,
192 mut = unsafePerformIO (newIORef (Handle_Mut { state = HOpen })),
197 instance Eq Handle where
198 h1 == h2 = file h1 == file h2
200 instance Show Handle where
201 showsPrec _ h = showString ("`" ++ name h ++ "'")
208 data IOMode = ReadMode | WriteMode | AppendMode | ReadWriteMode
209 deriving (Eq, Ord, Ix, Bounded, Enum, Read, Show)
211 data BufferMode = NoBuffering | LineBuffering
212 | BlockBuffering (Maybe Int)
213 deriving (Eq, Ord, Read, Show)
215 data SeekMode = AbsoluteSeek | RelativeSeek | SeekFromEnd
216 deriving (Eq, Ord, Ix, Bounded, Enum, Read, Show)
218 data HState = HOpen | HSemiClosed | HClosed
222 -- A global variable holding a list of all open handles.
223 -- Each handle is present as many times as it has been opened.
224 -- Any given file is allowed to have _either_ one writeable handle
225 -- or many readable handles in this list. The list is used to
226 -- enforce single-writer multiple reader semantics. It also
227 -- provides a list of handles for System.exitWith to flush and
228 -- close. In order not to have to put all this stuff in the
229 -- Prelude, System.exitWith merely runs prelExitWithAction,
230 -- which is originally Nothing, but which we set to Just ...
231 -- once handles appear in the list.
233 allHandles :: IORef [Handle]
234 allHandles = unsafePerformIO (newIORef [])
236 elemWriterHandles :: FilePath -> IO Bool
237 elemAllHandles :: FilePath -> IO Bool
238 addHandle :: Handle -> IO ()
239 delHandle :: Handle -> IO ()
240 cleanupHandles :: IO ()
243 = do hdls <- readIORef allHandles
244 mapM_ cleanupHandle hdls
249 >> nh_errno >>= \_ -> return ()
251 = nh_flush (file h) >> nh_close (file h)
252 >> nh_errno >>= \_ -> return ()
254 elemWriterHandles fname
255 = do hdls <- readIORef allHandles
256 let hdls_w = filter ((/= ReadMode).mode) hdls
257 return (fname `elem` (map name hdls_w))
260 = do hdls <- readIORef allHandles
261 return (fname `elem` (map name hdls))
264 = do cleanup_action <- readIORef prelCleanupAfterRunAction
265 case cleanup_action of
267 -> writeIORef prelCleanupAfterRunAction (Just cleanupHandles)
270 hdls <- readIORef allHandles
271 writeIORef allHandles (hdl : hdls)
274 = do hdls <- readIORef allHandles
275 let hdls' = takeWhile (/= hdl) hdls
276 ++ drop 1 (dropWhile (/= hdl) hdls)
277 writeIORef allHandles hdls'
281 openFile :: FilePath -> IOMode -> IO Handle
285 = (ioError.IOError) "openFile: empty file name"
288 = do not_ok <- elemWriterHandles f
290 then (ioError.IOError)
291 ("openFile: `" ++ f ++ "' in " ++ show mode
292 ++ ": is already open for writing")
293 else openFile_main f mode
296 = do not_ok <- elemAllHandles f
298 then (ioError.IOError)
299 ("openFile: `" ++ f ++ "' in " ++ show mode
300 ++ ": is already open for reading or writing")
301 else openFile_main f mode
304 = openFile_main f mode
307 = copy_String_to_cstring f >>= \nameptr ->
308 nh_open nameptr (mode2num mode) >>= \fh ->
311 then (ioError.IOError)
312 ("openFile: can't open <<" ++ f ++ ">> in " ++ show mode)
313 else do r <- newIORef (Handle_Mut { state = HOpen })
314 let hdl = Handle { name = f, file = fh,
315 mut = r, mode = mode }
319 mode2num :: IOMode -> Int
320 mode2num ReadMode = 0
321 mode2num WriteMode = 1
322 mode2num AppendMode = 2
323 mode2num ReadWriteMode
325 ("openFile <<" ++ f ++ ">>: ReadWriteMode not supported")
327 hClose :: Handle -> IO ()
329 = do mut <- readIORef (mut h)
330 if state mut == HClosed
332 ("hClose on closed handle " ++ show h)
334 do set_state h HClosed
341 ("hClose: error closing " ++ name h)
343 hGetContents :: Handle -> IO String
346 = mkErr h ("hGetContents on non-ReadMode handle " ++ show h)
348 = do mut <- readIORef (mut h)
349 if state mut /= HOpen
351 ("hGetContents on closed/semiclosed handle " ++ show h)
353 do set_state h HSemiClosed
357 = nh_read f >>= \ci ->
360 else read_all f >>= \rest ->
361 return ((primIntToChar ci):rest)
363 hPutStr :: Handle -> String -> IO ()
366 = mkErr h ("hPutStr on ReadMode handle " ++ show h)
368 = do mut <- readIORef (mut h)
369 if state mut /= HOpen
371 ("hPutStr on closed/semiclosed handle " ++ show h)
372 else write_all (file h) s
377 = nh_write f c >> write_all f cs
379 hFileSize :: Handle -> IO Integer
381 = do sz <- nh_filesize (file h)
384 then return (fromIntegral sz)
385 else mkErr h ("hFileSize on " ++ show h)
387 hIsEOF :: Handle -> IO Bool
389 = do iseof <- nh_iseof (file h)
392 then return (iseof /= 0)
393 else mkErr h ("hIsEOF on " ++ show h)
398 hSetBuffering :: Handle -> BufferMode -> IO ()
399 hSetBuffering = unimp "IO.hSetBuffering"
400 hGetBuffering :: Handle -> IO BufferMode
401 hGetBuffering = unimp "IO.hGetBuffering"
403 hFlush :: Handle -> IO ()
405 = do mut <- readIORef (mut h)
406 if state mut /= HOpen
408 ("hFlush on closed/semiclosed file " ++ name h)
409 else nh_flush (file h)
411 hGetPosn :: Handle -> IO HandlePosn
412 hGetPosn = unimp "IO.hGetPosn"
413 hSetPosn :: HandlePosn -> IO ()
414 hSetPosn = unimp "IO.hSetPosn"
415 hSeek :: Handle -> SeekMode -> Integer -> IO ()
416 hSeek = unimp "IO.hSeek"
417 hWaitForInput :: Handle -> Int -> IO Bool
418 hWaitForInput = unimp "hWaitForInput"
419 hReady :: Handle -> IO Bool
420 hReady h = unimp "hReady" -- hWaitForInput h 0
422 hGetChar :: Handle -> IO Char
424 = nh_read (file h) >>= \ci ->
425 return (primIntToChar ci)
427 hGetLine :: Handle -> IO String
428 hGetLine h = do c <- hGetChar h
429 if c=='\n' then return ""
430 else do cs <- hGetLine h
433 hLookAhead :: Handle -> IO Char
434 hLookAhead = unimp "IO.hLookAhead"
437 hPutChar :: Handle -> Char -> IO ()
438 hPutChar h c = hPutStr h [c]
440 hPutStrLn :: Handle -> String -> IO ()
441 hPutStrLn h s = do { hPutStr h s; hPutChar h '\n' }
443 hPrint :: Show a => Handle -> a -> IO ()
444 hPrint h = hPutStrLn h . show
446 hIsOpen, hIsClosed, hIsReadable, hIsWritable :: Handle -> IO Bool
447 hIsOpen h = do { s <- get_state h; return (s == HOpen) }
448 hIsClosed h = do { s <- get_state h; return (s == HClosed) }
449 hIsReadable h = return (mode h == ReadMode)
450 hIsWritable h = return (mode h `elem` [WriteMode, AppendMode])
452 hIsSeekable :: Handle -> IO Bool
453 hIsSeekable = unimp "IO.hIsSeekable"
456 isAlreadyExistsError,
462 isUserError :: IOError -> Bool
464 isIllegalOperation = unimp "IO.isIllegalOperation"
465 isAlreadyExistsError = unimp "IO.isAlreadyExistsError"
466 isDoesNotExistError = unimp "IO.isDoesNotExistError"
467 isAlreadyInUseError = unimp "IO.isAlreadyInUseError"
468 isFullError = unimp "IO.isFullError"
469 isEOFError = unimp "IO.isEOFError"
470 isPermissionError = unimp "IO.isPermissionError"
471 isUserError = unimp "IO.isUserError"
474 ioeGetErrorString :: IOError -> String
475 ioeGetErrorString = unimp "IO.ioeGetErrorString"
476 ioeGetHandle :: IOError -> Maybe Handle
477 ioeGetHandle = unimp "IO.ioeGetHandle"
478 ioeGetFileName :: IOError -> Maybe FilePath
479 ioeGetFileName = unimp "IO.ioeGetFileName"
481 try :: IO a -> IO (Either IOError a)
482 try p = catch (p >>= (return . Right)) (return . Left)
484 bracket :: IO a -> (a -> IO b) -> (a -> IO c) -> IO c
485 bracket before after m = do
493 -- variant of the above where middle computation doesn't want x
494 bracket_ :: IO a -> (a -> IO b) -> IO c -> IO c
495 bracket_ before after m = do
503 -- TODO: Hugs/slurpFile
504 slurpFile = unimp "IO.slurpFile"
507 #endif /* #ifndef __HUGS__ */