1 {-# OPTIONS_GHC -fno-implicit-prelude #-}
3 -----------------------------------------------------------------------------
5 -- Module : System.IO.Error
6 -- Copyright : (c) The University of Glasgow 2001
7 -- License : BSD-style (see the file libraries/base/LICENSE)
9 -- Maintainer : libraries@haskell.org
10 -- Stability : provisional
11 -- Portability : portable
13 -- Standard IO Errors.
15 -----------------------------------------------------------------------------
17 module System.IO.Error (
20 IOError, -- = IOException
22 userError, -- :: String -> IOError
25 mkIOError, -- :: IOErrorType -> String -> Maybe Handle
26 -- -> Maybe FilePath -> IOError
28 annotateIOError, -- :: IOError -> String -> Maybe Handle
29 -- -> Maybe FilePath -> IOError
32 -- ** Classifying I\/O errors
33 isAlreadyExistsError, -- :: IOError -> Bool
42 -- ** Attributes of I\/O errors
44 ioeGetErrorType, -- :: IOError -> IOErrorType
45 ioeGetLocation, -- :: IOError -> String
47 ioeGetErrorString, -- :: IOError -> String
48 ioeGetHandle, -- :: IOError -> Maybe Handle
49 ioeGetFileName, -- :: IOError -> Maybe FilePath
52 ioeSetErrorType, -- :: IOError -> IOErrorType -> IOError
53 ioeSetErrorString, -- :: IOError -> String -> IOError
54 ioeSetLocation, -- :: IOError -> String -> IOError
55 ioeSetHandle, -- :: IOError -> Handle -> IOError
56 ioeSetFileName, -- :: IOError -> FilePath -> IOError
59 -- * Types of I\/O error
60 IOErrorType, -- abstract
62 alreadyExistsErrorType, -- :: IOErrorType
63 doesNotExistErrorType,
64 alreadyInUseErrorType,
67 illegalOperationErrorType,
71 -- ** 'IOErrorType' predicates
72 isAlreadyExistsErrorType, -- :: IOErrorType -> Bool
73 isDoesNotExistErrorType,
74 isAlreadyInUseErrorType,
77 isIllegalOperationErrorType,
78 isPermissionErrorType,
81 -- * Throwing and catching I\/O errors
83 ioError, -- :: IOError -> IO a
85 catch, -- :: IO a -> (IOError -> IO a) -> IO a
86 try, -- :: IO a -> IO (Either IOError a)
89 modifyIOError, -- :: (IOError -> IOError) -> IO a -> IO a
96 #ifdef __GLASGOW_HASKELL__
104 import Hugs.Prelude(Handle, IOException(..), IOErrorType(..))
113 , isAlreadyExistsError -- :: IOError -> Bool
114 , isDoesNotExistError
115 , isAlreadyInUseError
121 , ioeGetErrorString -- :: IOError -> String
122 , ioeGetHandle -- :: IOError -> Maybe Handle
123 , ioeGetFileName -- :: IOError -> Maybe FilePath
125 --import Data.Maybe (fromJust)
126 --import Control.Monad (MonadPlus(mplus))
129 -- | The construct 'try' @comp@ exposes IO errors which occur within a
130 -- computation, and which are not fully handled.
132 -- Non-I\/O exceptions are not caught by this variant; to catch all
133 -- exceptions, use 'Control.Exception.try' from "Control.Exception".
136 try :: IO a -> IO (Either IOError a)
137 try f = catch (do r <- f
142 #if defined(__GLASGOW_HASKELL__) || defined(__HUGS__)
143 -- -----------------------------------------------------------------------------
144 -- Constructing an IOError
146 -- | Construct an 'IOError' of the given type where the second argument
147 -- describes the error location and the third and fourth argument
148 -- contain the file handle and file path of the file involved in the
149 -- error if applicable.
150 mkIOError :: IOErrorType -> String -> Maybe Handle -> Maybe FilePath -> IOError
151 mkIOError t location maybe_hdl maybe_filename =
152 IOError{ ioe_type = t,
153 ioe_location = location,
154 ioe_description = "",
155 ioe_handle = maybe_hdl,
156 ioe_filename = maybe_filename
159 mkIOError EOF location maybe_hdl maybe_filename =
160 EOFError location (fromJust maybe_hdl)
161 mkIOError UserError location maybe_hdl maybe_filename =
162 UserError location ""
163 mkIOError t location maybe_hdl maybe_filename =
164 NHC.FFI.mkIOError location maybe_filename maybe_handle (ioeTypeToInt t)
166 ioeTypeToInt AlreadyExists = fromEnum EEXIST
167 ioeTypeToInt NoSuchThing = fromEnum ENOENT
168 ioeTypeToInt ResourceBusy = fromEnum EBUSY
169 ioeTypeToInt ResourceExhausted = fromEnum ENOSPC
170 ioeTypeToInt IllegalOperation = fromEnum EPERM
171 ioeTypeToInt PermissionDenied = fromEnum EACCES
173 #endif /* __GLASGOW_HASKELL__ || __HUGS__ */
176 -- -----------------------------------------------------------------------------
179 -- | An error indicating that an 'IO' operation failed because
180 -- one of its arguments already exists.
181 isAlreadyExistsError :: IOError -> Bool
182 isAlreadyExistsError = isAlreadyExistsErrorType . ioeGetErrorType
184 -- | An error indicating that an 'IO' operation failed because
185 -- one of its arguments does not exist.
186 isDoesNotExistError :: IOError -> Bool
187 isDoesNotExistError = isDoesNotExistErrorType . ioeGetErrorType
189 -- | An error indicating that an 'IO' operation failed because
190 -- one of its arguments is a single-use resource, which is already
191 -- being used (for example, opening the same file twice for writing
192 -- might give this error).
193 isAlreadyInUseError :: IOError -> Bool
194 isAlreadyInUseError = isAlreadyInUseErrorType . ioeGetErrorType
196 -- | An error indicating that an 'IO' operation failed because
197 -- the device is full.
198 isFullError :: IOError -> Bool
199 isFullError = isFullErrorType . ioeGetErrorType
201 -- | An error indicating that an 'IO' operation failed because
202 -- the end of file has been reached.
203 isEOFError :: IOError -> Bool
204 isEOFError = isEOFErrorType . ioeGetErrorType
206 -- | An error indicating that an 'IO' operation failed because
207 -- the operation was not possible.
208 -- Any computation which returns an 'IO' result may fail with
209 -- 'isIllegalOperation'. In some cases, an implementation will not be
210 -- able to distinguish between the possible error causes. In this case
211 -- it should fail with 'isIllegalOperation'.
212 isIllegalOperation :: IOError -> Bool
213 isIllegalOperation = isIllegalOperationErrorType . ioeGetErrorType
215 -- | An error indicating that an 'IO' operation failed because
216 -- the user does not have sufficient operating system privilege
217 -- to perform that operation.
218 isPermissionError :: IOError -> Bool
219 isPermissionError = isPermissionErrorType . ioeGetErrorType
221 -- | A programmer-defined error value constructed using 'userError'.
222 isUserError :: IOError -> Bool
223 isUserError = isUserErrorType . ioeGetErrorType
226 -- -----------------------------------------------------------------------------
230 data IOErrorType = AlreadyExists | NoSuchThing | ResourceBusy
231 | ResourceExhausted | EOF | IllegalOperation
232 | PermissionDenied | UserError
235 -- | I\/O error where the operation failed because one of its arguments
237 alreadyExistsErrorType :: IOErrorType
238 alreadyExistsErrorType = AlreadyExists
240 -- | I\/O error where the operation failed because one of its arguments
242 doesNotExistErrorType :: IOErrorType
243 doesNotExistErrorType = NoSuchThing
245 -- | I\/O error where the operation failed because one of its arguments
246 -- is a single-use resource, which is already being used.
247 alreadyInUseErrorType :: IOErrorType
248 alreadyInUseErrorType = ResourceBusy
250 -- | I\/O error where the operation failed because the device is full.
251 fullErrorType :: IOErrorType
252 fullErrorType = ResourceExhausted
254 -- | I\/O error where the operation failed because the end of file has
256 eofErrorType :: IOErrorType
259 -- | I\/O error where the operation is not possible.
260 illegalOperationErrorType :: IOErrorType
261 illegalOperationErrorType = IllegalOperation
263 -- | I\/O error where the operation failed because the user does not
264 -- have sufficient operating system privilege to perform that operation.
265 permissionErrorType :: IOErrorType
266 permissionErrorType = PermissionDenied
268 -- | I\/O error that is programmer-defined.
269 userErrorType :: IOErrorType
270 userErrorType = UserError
272 -- -----------------------------------------------------------------------------
273 -- IOErrorType predicates
275 -- | I\/O error where the operation failed because one of its arguments
277 isAlreadyExistsErrorType :: IOErrorType -> Bool
278 isAlreadyExistsErrorType AlreadyExists = True
279 isAlreadyExistsErrorType _ = False
281 -- | I\/O error where the operation failed because one of its arguments
283 isDoesNotExistErrorType :: IOErrorType -> Bool
284 isDoesNotExistErrorType NoSuchThing = True
285 isDoesNotExistErrorType _ = False
287 -- | I\/O error where the operation failed because one of its arguments
288 -- is a single-use resource, which is already being used.
289 isAlreadyInUseErrorType :: IOErrorType -> Bool
290 isAlreadyInUseErrorType ResourceBusy = True
291 isAlreadyInUseErrorType _ = False
293 -- | I\/O error where the operation failed because the device is full.
294 isFullErrorType :: IOErrorType -> Bool
295 isFullErrorType ResourceExhausted = True
296 isFullErrorType _ = False
298 -- | I\/O error where the operation failed because the end of file has
300 isEOFErrorType :: IOErrorType -> Bool
301 isEOFErrorType EOF = True
302 isEOFErrorType _ = False
304 -- | I\/O error where the operation is not possible.
305 isIllegalOperationErrorType :: IOErrorType -> Bool
306 isIllegalOperationErrorType IllegalOperation = True
307 isIllegalOperationErrorType _ = False
309 -- | I\/O error where the operation failed because the user does not
310 -- have sufficient operating system privilege to perform that operation.
311 isPermissionErrorType :: IOErrorType -> Bool
312 isPermissionErrorType PermissionDenied = True
313 isPermissionErrorType _ = False
315 -- | I\/O error that is programmer-defined.
316 isUserErrorType :: IOErrorType -> Bool
317 isUserErrorType UserError = True
318 isUserErrorType _ = False
320 -- -----------------------------------------------------------------------------
323 #if defined(__GLASGOW_HASKELL__) || defined(__HUGS__)
324 ioeGetErrorType :: IOError -> IOErrorType
325 ioeGetErrorString :: IOError -> String
326 ioeGetLocation :: IOError -> String
327 ioeGetHandle :: IOError -> Maybe Handle
328 ioeGetFileName :: IOError -> Maybe FilePath
330 ioeGetErrorType ioe = ioe_type ioe
332 ioeGetErrorString ioe
333 | isUserErrorType (ioe_type ioe) = ioe_description ioe
334 | otherwise = show (ioe_type ioe)
336 ioeGetLocation ioe = ioe_location ioe
338 ioeGetHandle ioe = ioe_handle ioe
340 ioeGetFileName ioe = ioe_filename ioe
342 ioeSetErrorType :: IOError -> IOErrorType -> IOError
343 ioeSetErrorString :: IOError -> String -> IOError
344 ioeSetLocation :: IOError -> String -> IOError
345 ioeSetHandle :: IOError -> Handle -> IOError
346 ioeSetFileName :: IOError -> FilePath -> IOError
348 ioeSetErrorType ioe errtype = ioe{ ioe_type = errtype }
349 ioeSetErrorString ioe str = ioe{ ioe_description = str }
350 ioeSetLocation ioe str = ioe{ ioe_location = str }
351 ioeSetHandle ioe hdl = ioe{ ioe_handle = Just hdl }
352 ioeSetFileName ioe filename = ioe{ ioe_filename = Just filename }
354 -- | Catch any 'IOError' that occurs in the computation and throw a
356 modifyIOError :: (IOError -> IOError) -> IO a -> IO a
357 modifyIOError f io = catch io (\e -> ioError (f e))
359 -- -----------------------------------------------------------------------------
360 -- annotating an IOError
362 -- | Adds a location description and maybe a file path and file handle
363 -- to an 'IOError'. If any of the file handle or file path is not given
364 -- the corresponding value in the 'IOError' remains unaltered.
365 annotateIOError :: IOError
370 annotateIOError (IOError ohdl errTy _ str opath) loc hdl path =
371 IOError (hdl `mplus` ohdl) errTy loc str (path `mplus` opath)
373 Nothing `mplus` ys = ys
375 #endif /* __GLASGOW_HASKELL__ || __HUGS__ */
378 annotateIOError (IOError msg file hdl code) msg' file' hdl' =
379 IOError (msg++'\n':msg') (file`mplus`file') (hdl`mplus`hdl') code
380 annotateIOError (EOFError msg hdl) msg' file' hdl' =
381 EOFError (msg++'\n':msg') (hdl`mplus`hdl')
382 annotateIOError (UserError loc msg) msg' file' hdl' =
383 UserError loc (msg++'\n':msg')
384 annotateIOError (PatternError loc) msg' file' hdl' =
385 PatternError (loc++'\n':msg')