1 {-# OPTIONS_GHC -XNoImplicitPrelude #-}
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
94 import qualified Control.Exception.Base as New (catch)
102 #ifdef __GLASGOW_HASKELL__
109 import Hugs.Prelude(Handle, IOException(..), IOErrorType(..), IO)
118 , isAlreadyExistsError -- :: IOError -> Bool
119 , isDoesNotExistError
120 , isAlreadyInUseError
126 , ioeGetErrorString -- :: IOError -> String
127 , ioeGetHandle -- :: IOError -> Maybe Handle
128 , ioeGetFileName -- :: IOError -> Maybe FilePath
130 --import Data.Maybe (fromJust)
131 --import Control.Monad (MonadPlus(mplus))
134 -- | The construct 'try' @comp@ exposes IO errors which occur within a
135 -- computation, and which are not fully handled.
137 -- Non-I\/O exceptions are not caught by this variant; to catch all
138 -- exceptions, use 'Control.Exception.try' from "Control.Exception".
141 try :: IO a -> IO (Either IOError a)
142 try f = catch (do r <- f
147 #if defined(__GLASGOW_HASKELL__) || defined(__HUGS__)
148 -- -----------------------------------------------------------------------------
149 -- Constructing an IOError
151 -- | Construct an 'IOError' of the given type where the second argument
152 -- describes the error location and the third and fourth argument
153 -- contain the file handle and file path of the file involved in the
154 -- error if applicable.
155 mkIOError :: IOErrorType -> String -> Maybe Handle -> Maybe FilePath -> IOError
156 mkIOError t location maybe_hdl maybe_filename =
157 IOError{ ioe_type = t,
158 ioe_location = location,
159 ioe_description = "",
160 #if defined(__GLASGOW_HASKELL__)
163 ioe_handle = maybe_hdl,
164 ioe_filename = maybe_filename
167 mkIOError EOF location maybe_hdl maybe_filename =
168 EOFError location (fromJust maybe_hdl)
169 mkIOError UserError location maybe_hdl maybe_filename =
170 UserError location ""
171 mkIOError t location maybe_hdl maybe_filename =
172 NHC.FFI.mkIOError location maybe_filename maybe_handle (ioeTypeToInt t)
174 ioeTypeToInt AlreadyExists = fromEnum EEXIST
175 ioeTypeToInt NoSuchThing = fromEnum ENOENT
176 ioeTypeToInt ResourceBusy = fromEnum EBUSY
177 ioeTypeToInt ResourceExhausted = fromEnum ENOSPC
178 ioeTypeToInt IllegalOperation = fromEnum EPERM
179 ioeTypeToInt PermissionDenied = fromEnum EACCES
181 #endif /* __GLASGOW_HASKELL__ || __HUGS__ */
184 -- -----------------------------------------------------------------------------
187 -- | An error indicating that an 'IO' operation failed because
188 -- one of its arguments already exists.
189 isAlreadyExistsError :: IOError -> Bool
190 isAlreadyExistsError = isAlreadyExistsErrorType . ioeGetErrorType
192 -- | An error indicating that an 'IO' operation failed because
193 -- one of its arguments does not exist.
194 isDoesNotExistError :: IOError -> Bool
195 isDoesNotExistError = isDoesNotExistErrorType . ioeGetErrorType
197 -- | An error indicating that an 'IO' operation failed because
198 -- one of its arguments is a single-use resource, which is already
199 -- being used (for example, opening the same file twice for writing
200 -- might give this error).
201 isAlreadyInUseError :: IOError -> Bool
202 isAlreadyInUseError = isAlreadyInUseErrorType . ioeGetErrorType
204 -- | An error indicating that an 'IO' operation failed because
205 -- the device is full.
206 isFullError :: IOError -> Bool
207 isFullError = isFullErrorType . ioeGetErrorType
209 -- | An error indicating that an 'IO' operation failed because
210 -- the end of file has been reached.
211 isEOFError :: IOError -> Bool
212 isEOFError = isEOFErrorType . ioeGetErrorType
214 -- | An error indicating that an 'IO' operation failed because
215 -- the operation was not possible.
216 -- Any computation which returns an 'IO' result may fail with
217 -- 'isIllegalOperation'. In some cases, an implementation will not be
218 -- able to distinguish between the possible error causes. In this case
219 -- it should fail with 'isIllegalOperation'.
220 isIllegalOperation :: IOError -> Bool
221 isIllegalOperation = isIllegalOperationErrorType . ioeGetErrorType
223 -- | An error indicating that an 'IO' operation failed because
224 -- the user does not have sufficient operating system privilege
225 -- to perform that operation.
226 isPermissionError :: IOError -> Bool
227 isPermissionError = isPermissionErrorType . ioeGetErrorType
229 -- | A programmer-defined error value constructed using 'userError'.
230 isUserError :: IOError -> Bool
231 isUserError = isUserErrorType . ioeGetErrorType
234 -- -----------------------------------------------------------------------------
238 data IOErrorType = AlreadyExists | NoSuchThing | ResourceBusy
239 | ResourceExhausted | EOF | IllegalOperation
240 | PermissionDenied | UserError
243 -- | I\/O error where the operation failed because one of its arguments
245 alreadyExistsErrorType :: IOErrorType
246 alreadyExistsErrorType = AlreadyExists
248 -- | I\/O error where the operation failed because one of its arguments
250 doesNotExistErrorType :: IOErrorType
251 doesNotExistErrorType = NoSuchThing
253 -- | I\/O error where the operation failed because one of its arguments
254 -- is a single-use resource, which is already being used.
255 alreadyInUseErrorType :: IOErrorType
256 alreadyInUseErrorType = ResourceBusy
258 -- | I\/O error where the operation failed because the device is full.
259 fullErrorType :: IOErrorType
260 fullErrorType = ResourceExhausted
262 -- | I\/O error where the operation failed because the end of file has
264 eofErrorType :: IOErrorType
267 -- | I\/O error where the operation is not possible.
268 illegalOperationErrorType :: IOErrorType
269 illegalOperationErrorType = IllegalOperation
271 -- | I\/O error where the operation failed because the user does not
272 -- have sufficient operating system privilege to perform that operation.
273 permissionErrorType :: IOErrorType
274 permissionErrorType = PermissionDenied
276 -- | I\/O error that is programmer-defined.
277 userErrorType :: IOErrorType
278 userErrorType = UserError
280 -- -----------------------------------------------------------------------------
281 -- IOErrorType predicates
283 -- | I\/O error where the operation failed because one of its arguments
285 isAlreadyExistsErrorType :: IOErrorType -> Bool
286 isAlreadyExistsErrorType AlreadyExists = True
287 isAlreadyExistsErrorType _ = False
289 -- | I\/O error where the operation failed because one of its arguments
291 isDoesNotExistErrorType :: IOErrorType -> Bool
292 isDoesNotExistErrorType NoSuchThing = True
293 isDoesNotExistErrorType _ = False
295 -- | I\/O error where the operation failed because one of its arguments
296 -- is a single-use resource, which is already being used.
297 isAlreadyInUseErrorType :: IOErrorType -> Bool
298 isAlreadyInUseErrorType ResourceBusy = True
299 isAlreadyInUseErrorType _ = False
301 -- | I\/O error where the operation failed because the device is full.
302 isFullErrorType :: IOErrorType -> Bool
303 isFullErrorType ResourceExhausted = True
304 isFullErrorType _ = False
306 -- | I\/O error where the operation failed because the end of file has
308 isEOFErrorType :: IOErrorType -> Bool
309 isEOFErrorType EOF = True
310 isEOFErrorType _ = False
312 -- | I\/O error where the operation is not possible.
313 isIllegalOperationErrorType :: IOErrorType -> Bool
314 isIllegalOperationErrorType IllegalOperation = True
315 isIllegalOperationErrorType _ = False
317 -- | I\/O error where the operation failed because the user does not
318 -- have sufficient operating system privilege to perform that operation.
319 isPermissionErrorType :: IOErrorType -> Bool
320 isPermissionErrorType PermissionDenied = True
321 isPermissionErrorType _ = False
323 -- | I\/O error that is programmer-defined.
324 isUserErrorType :: IOErrorType -> Bool
325 isUserErrorType UserError = True
326 isUserErrorType _ = False
328 -- -----------------------------------------------------------------------------
331 #if defined(__GLASGOW_HASKELL__) || defined(__HUGS__)
332 ioeGetErrorType :: IOError -> IOErrorType
333 ioeGetErrorString :: IOError -> String
334 ioeGetLocation :: IOError -> String
335 ioeGetHandle :: IOError -> Maybe Handle
336 ioeGetFileName :: IOError -> Maybe FilePath
338 ioeGetErrorType ioe = ioe_type ioe
340 ioeGetErrorString ioe
341 | isUserErrorType (ioe_type ioe) = ioe_description ioe
342 | otherwise = show (ioe_type ioe)
344 ioeGetLocation ioe = ioe_location ioe
346 ioeGetHandle ioe = ioe_handle ioe
348 ioeGetFileName ioe = ioe_filename ioe
350 ioeSetErrorType :: IOError -> IOErrorType -> IOError
351 ioeSetErrorString :: IOError -> String -> IOError
352 ioeSetLocation :: IOError -> String -> IOError
353 ioeSetHandle :: IOError -> Handle -> IOError
354 ioeSetFileName :: IOError -> FilePath -> IOError
356 ioeSetErrorType ioe errtype = ioe{ ioe_type = errtype }
357 ioeSetErrorString ioe str = ioe{ ioe_description = str }
358 ioeSetLocation ioe str = ioe{ ioe_location = str }
359 ioeSetHandle ioe hdl = ioe{ ioe_handle = Just hdl }
360 ioeSetFileName ioe filename = ioe{ ioe_filename = Just filename }
362 -- | Catch any 'IOError' that occurs in the computation and throw a
364 modifyIOError :: (IOError -> IOError) -> IO a -> IO a
365 modifyIOError f io = catch io (\e -> ioError (f e))
367 -- -----------------------------------------------------------------------------
368 -- annotating an IOError
370 -- | Adds a location description and maybe a file path and file handle
371 -- to an 'IOError'. If any of the file handle or file path is not given
372 -- the corresponding value in the 'IOError' remains unaltered.
373 annotateIOError :: IOError
378 annotateIOError ioe loc hdl path =
379 ioe{ ioe_handle = hdl `mplus` ioe_handle ioe,
380 ioe_location = loc, ioe_filename = path `mplus` ioe_filename ioe }
382 Nothing `mplus` ys = ys
384 #endif /* __GLASGOW_HASKELL__ || __HUGS__ */
387 annotateIOError (IOError msg file hdl code) msg' file' hdl' =
388 IOError (msg++'\n':msg') (file`mplus`file') (hdl`mplus`hdl') code
389 annotateIOError (EOFError msg hdl) msg' file' hdl' =
390 EOFError (msg++'\n':msg') (hdl`mplus`hdl')
391 annotateIOError (UserError loc msg) msg' file' hdl' =
392 UserError loc (msg++'\n':msg')
393 annotateIOError (PatternError loc) msg' file' hdl' =
394 PatternError (loc++'\n':msg')
398 -- | The 'catch' function establishes a handler that receives any 'IOError'
399 -- raised in the action protected by 'catch'. An 'IOError' is caught by
400 -- the most recent handler established by 'catch'. These handlers are
401 -- not selective: all 'IOError's are caught. Exception propagation
402 -- must be explicitly provided in a handler by re-raising any unwanted
403 -- exceptions. For example, in
405 -- > f = catch g (\e -> if IO.isEOFError e then return [] else ioError e)
407 -- the function @f@ returns @[]@ when an end-of-file exception
408 -- (cf. 'System.IO.Error.isEOFError') occurs in @g@; otherwise, the
409 -- exception is propagated to the next outer handler.
411 -- When an exception propagates outside the main program, the Haskell
412 -- system prints the associated 'IOError' value and exits the program.
414 -- Non-I\/O exceptions are not caught by this variant; to catch all
415 -- exceptions, use 'Control.Exception.catch' from "Control.Exception".
416 catch :: IO a -> (IOError -> IO a) -> IO a
418 #endif /* !__HUGS__ */