-{-# OPTIONS -fno-implicit-prelude #-}
+{-# OPTIONS_GHC -fno-implicit-prelude #-}
-----------------------------------------------------------------------------
-- |
-- Module : System.IO
-- ** Opening files
+ withFile,
openFile, -- :: FilePath -> IOMode -> IO Handle
IOMode(ReadMode,WriteMode,AppendMode,ReadWriteMode),
-- * Operations on handles
- -- ** Determining the size of a file
+ -- ** Determining and changing the size of a file
hFileSize, -- :: Handle -> IO Integer
+#ifdef __GLASGOW_HASKELL__
+ hSetFileSize, -- :: Handle -> Integer -> IO ()
+#endif
-- ** Detecting the end of input
-- * Binary input and output
+ withBinaryFile,
openBinaryFile, -- :: FilePath -> IOMode -> IO Handle
hSetBinaryMode, -- :: Handle -> Bool -> IO ()
-#if !defined(__NHC__)
hPutBuf, -- :: Handle -> Ptr a -> Int -> IO ()
hGetBuf, -- :: Handle -> Ptr a -> Int -> IO Int
-#endif
#if !defined(__NHC__) && !defined(__HUGS__)
hPutBufNonBlocking, -- :: Handle -> Ptr a -> Int -> IO Int
hGetBufNonBlocking, -- :: Handle -> Ptr a -> Int -> IO Int
#endif
- module System.IO.Error,
+ -- * Temporary files
+
+#ifdef __GLASGOW_HASKELL__
+ openTempFile,
+ openBinaryTempFile,
+#endif
) where
#ifdef __GLASGOW_HASKELL__
import GHC.IOBase -- Together these four Prelude modules define
import GHC.Handle -- all the stuff exported by IO for the GHC version
import GHC.IO
-import GHC.ST ( fixST )
import GHC.Exception
import GHC.Num
import GHC.Read
import Hugs.IOExts
import Hugs.IORef
import Hugs.Prelude ( throw, Exception(NonTermination) )
+import Control.Exception ( bracket )
import System.IO.Unsafe ( unsafeInterleaveIO )
#endif
, hGetContents -- :: Handle -> IO [Char]
, hPutChar -- :: Handle -> Char -> IO ()
, hPutStr -- :: Handle -> [Char] -> IO ()
+ , hPutStrLn -- :: Handle -> [Char] -> IO ()
+ , hPrint -- :: Handle -> [Char] -> IO ()
+ , hReady -- :: Handle -> [Char] -> IO ()
, hIsOpen, hIsClosed -- :: Handle -> IO Bool
, hIsReadable, hIsWritable -- :: Handle -> IO Bool
, hIsSeekable -- :: Handle -> IO Bool
+ , bracket
, IO ()
, FilePath -- :: String
)
-import NHC.IOExtras (fixIO)
+import NHC.IOExtras (fixIO, hPutBuf, hGetBuf)
+import NHC.FFI (Ptr)
#endif
-import System.IO.Error (
- isAlreadyExistsError, isDoesNotExistError, -- :: IOError -> Bool
- isAlreadyInUseError, isFullError,
- isEOFError, isIllegalOperation,
- isPermissionError, isUserError,
-
- ioeGetErrorString, -- :: IOError -> String
- ioeGetHandle, -- :: IOError -> Maybe Handle
- ioeGetFileName, -- :: IOError -> Maybe FilePath
-
- try, -- :: IO a -> IO (Either IOError a)
-
- -- re-exports of Prelude names
- IOError,
- ioError, -- :: IOError -> IO a
- userError, -- :: String -> IOError
- catch -- :: IO a -> (IOError -> IO a) -> IO a
- )
-
-- -----------------------------------------------------------------------------
-- Standard IO
-#ifndef __HUGS__
+#ifdef __GLASGOW_HASKELL__
-- | Write a character to the standard output device
-- (same as 'hPutChar' 'stdout').
-- | The computation 'writeFile' @file str@ function writes the string @str@,
-- to the file @file@.
-
-writeFile :: FilePath -> String -> IO ()
-writeFile name str = do
- hdl <- openFile name WriteMode
- hPutStr hdl str
- hClose hdl
+writeFile :: FilePath -> String -> IO ()
+writeFile f txt = withFile f WriteMode (\ hdl -> hPutStr hdl txt)
-- | The computation 'appendFile' @file str@ function appends the string @str@,
-- to the file @file@.
-- > main = appendFile "squares" (show [(x,x*x) | x <- [0,0.1..2]])
appendFile :: FilePath -> String -> IO ()
-appendFile name str = do
- hdl <- openFile name AppendMode
- hPutStr hdl str
- hClose hdl
+appendFile f txt = withFile f AppendMode (\ hdl -> hPutStr hdl txt)
-- | The 'readLn' function combines 'getLine' and 'readIO'.
[x] -> return x
[] -> ioError (userError "Prelude.readIO: no parse")
_ -> ioError (userError "Prelude.readIO: ambiguous parse")
-#endif /* __HUGS__ */
+#endif /* __GLASGOW_HASKELL__ */
+#ifndef __NHC__
-- | Computation 'hReady' @hdl@ indicates whether at least one item is
-- available for input from handle @hdl@.
--
-- This operation may fail with:
--
--- * 'isEOFError' if the end of file has been reached.
+-- * 'System.IO.Error.isEOFError' if the end of file has been reached.
hReady :: Handle -> IO Bool
hReady h = hWaitForInput h 0
--
-- This operation may fail with:
--
--- * 'isFullError' if the device is full; or
+-- * 'System.IO.Error.isFullError' if the device is full; or
--
--- * 'isPermissionError' if another system resource limit would be exceeded.
+-- * 'System.IO.Error.isPermissionError' if another system resource limit would be exceeded.
hPrint :: Show a => Handle -> a -> IO ()
hPrint hdl = hPutStrLn hdl . show
+#endif /* !__NHC__ */
+
+-- | @'withFile' name mode act@ opens a file using 'openFile' and passes
+-- the resulting handle to the computation @act@. The handle will be
+-- closed on exit from 'withFile', whether by normal termination or by
+-- raising an exception.
+withFile :: FilePath -> IOMode -> (Handle -> IO r) -> IO r
+withFile name mode = bracket (openFile name mode) hClose
+
+-- | @'withBinaryFile' name mode act@ opens a file using 'openBinaryFile'
+-- and passes the resulting handle to the computation @act@. The handle
+-- will be closed on exit from 'withBinaryFile', whether by normal
+-- termination or by raising an exception.
+withBinaryFile :: FilePath -> IOMode -> (Handle -> IO r) -> IO r
+withBinaryFile name mode = bracket (openBinaryFile name mode) hClose
-- ---------------------------------------------------------------------------
-- fixIO
-- the file until the entire contents of the file have been consumed.
-- It follows that an attempt to write to a file (using 'writeFile', for
-- example) that was earlier opened by 'readFile' will usually result in
--- failure with 'isAlreadyInUseError'.
+-- failure with 'System.IO.Error.isAlreadyInUseError'.
+
+-- -----------------------------------------------------------------------------
+-- Utils
+
+#ifdef __GLASGOW_HASKELL__
+-- Copied here to avoid recursive dependency with Control.Exception
+bracket
+ :: IO a -- ^ computation to run first (\"acquire resource\")
+ -> (a -> IO b) -- ^ computation to run last (\"release resource\")
+ -> (a -> IO c) -- ^ computation to run in-between
+ -> IO c -- returns the value from the in-between computation
+bracket before after thing =
+ block (do
+ a <- before
+ r <- catchException
+ (unblock (thing a))
+ (\e -> do { after a; throw e })
+ after a
+ return r
+ )
+#endif