Remove Hugs98 specific code
[packages/base.git] / System / IO / Error.hs
1 {-# LANGUAGE Trustworthy #-}
2 {-# LANGUAGE CPP, NoImplicitPrelude #-}
3
4 -----------------------------------------------------------------------------
5 -- |
6 -- Module : System.IO.Error
7 -- Copyright : (c) The University of Glasgow 2001
8 -- License : BSD-style (see the file libraries/base/LICENSE)
9 --
10 -- Maintainer : libraries@haskell.org
11 -- Stability : provisional
12 -- Portability : portable
13 --
14 -- Standard IO Errors.
15 --
16 -----------------------------------------------------------------------------
17
18 module System.IO.Error (
19
20 -- * I\/O errors
21 IOError,
22
23 userError,
24
25 mkIOError,
26
27 annotateIOError,
28
29 -- ** Classifying I\/O errors
30 isAlreadyExistsError,
31 isDoesNotExistError,
32 isAlreadyInUseError,
33 isFullError,
34 isEOFError,
35 isIllegalOperation,
36 isPermissionError,
37 isUserError,
38
39 -- ** Attributes of I\/O errors
40 ioeGetErrorType,
41 ioeGetLocation,
42 ioeGetErrorString,
43 ioeGetHandle,
44 ioeGetFileName,
45
46 ioeSetErrorType,
47 ioeSetErrorString,
48 ioeSetLocation,
49 ioeSetHandle,
50 ioeSetFileName,
51
52 -- * Types of I\/O error
53 IOErrorType, -- abstract
54
55 alreadyExistsErrorType,
56 doesNotExistErrorType,
57 alreadyInUseErrorType,
58 fullErrorType,
59 eofErrorType,
60 illegalOperationErrorType,
61 permissionErrorType,
62 userErrorType,
63
64 -- ** 'IOErrorType' predicates
65 isAlreadyExistsErrorType,
66 isDoesNotExistErrorType,
67 isAlreadyInUseErrorType,
68 isFullErrorType,
69 isEOFErrorType,
70 isIllegalOperationErrorType,
71 isPermissionErrorType,
72 isUserErrorType,
73
74 -- * Throwing and catching I\/O errors
75
76 ioError,
77
78 catchIOError,
79 tryIOError,
80
81 modifyIOError,
82 ) where
83
84 import Control.Exception.Base
85
86 import Data.Either
87 import Data.Maybe
88
89 #ifdef __GLASGOW_HASKELL__
90 import GHC.Base
91 import GHC.IO
92 import GHC.IO.Exception
93 import GHC.IO.Handle.Types
94 import Text.Show
95 #endif
96
97 -- | The construct 'tryIOError' @comp@ exposes IO errors which occur within a
98 -- computation, and which are not fully handled.
99 --
100 -- Non-I\/O exceptions are not caught by this variant; to catch all
101 -- exceptions, use 'Control.Exception.try' from "Control.Exception".
102 tryIOError :: IO a -> IO (Either IOError a)
103 tryIOError f = catch (do r <- f
104 return (Right r))
105 (return . Left)
106
107 -- -----------------------------------------------------------------------------
108 -- Constructing an IOError
109
110 -- | Construct an 'IOError' of the given type where the second argument
111 -- describes the error location and the third and fourth argument
112 -- contain the file handle and file path of the file involved in the
113 -- error if applicable.
114 mkIOError :: IOErrorType -> String -> Maybe Handle -> Maybe FilePath -> IOError
115 mkIOError t location maybe_hdl maybe_filename =
116 IOError{ ioe_type = t,
117 ioe_location = location,
118 ioe_description = "",
119 #if defined(__GLASGOW_HASKELL__)
120 ioe_errno = Nothing,
121 #endif
122 ioe_handle = maybe_hdl,
123 ioe_filename = maybe_filename
124 }
125
126 -- -----------------------------------------------------------------------------
127 -- IOErrorType
128
129 -- | An error indicating that an 'IO' operation failed because
130 -- one of its arguments already exists.
131 isAlreadyExistsError :: IOError -> Bool
132 isAlreadyExistsError = isAlreadyExistsErrorType . ioeGetErrorType
133
134 -- | An error indicating that an 'IO' operation failed because
135 -- one of its arguments does not exist.
136 isDoesNotExistError :: IOError -> Bool
137 isDoesNotExistError = isDoesNotExistErrorType . ioeGetErrorType
138
139 -- | An error indicating that an 'IO' operation failed because
140 -- one of its arguments is a single-use resource, which is already
141 -- being used (for example, opening the same file twice for writing
142 -- might give this error).
143 isAlreadyInUseError :: IOError -> Bool
144 isAlreadyInUseError = isAlreadyInUseErrorType . ioeGetErrorType
145
146 -- | An error indicating that an 'IO' operation failed because
147 -- the device is full.
148 isFullError :: IOError -> Bool
149 isFullError = isFullErrorType . ioeGetErrorType
150
151 -- | An error indicating that an 'IO' operation failed because
152 -- the end of file has been reached.
153 isEOFError :: IOError -> Bool
154 isEOFError = isEOFErrorType . ioeGetErrorType
155
156 -- | An error indicating that an 'IO' operation failed because
157 -- the operation was not possible.
158 -- Any computation which returns an 'IO' result may fail with
159 -- 'isIllegalOperation'. In some cases, an implementation will not be
160 -- able to distinguish between the possible error causes. In this case
161 -- it should fail with 'isIllegalOperation'.
162 isIllegalOperation :: IOError -> Bool
163 isIllegalOperation = isIllegalOperationErrorType . ioeGetErrorType
164
165 -- | An error indicating that an 'IO' operation failed because
166 -- the user does not have sufficient operating system privilege
167 -- to perform that operation.
168 isPermissionError :: IOError -> Bool
169 isPermissionError = isPermissionErrorType . ioeGetErrorType
170
171 -- | A programmer-defined error value constructed using 'userError'.
172 isUserError :: IOError -> Bool
173 isUserError = isUserErrorType . ioeGetErrorType
174
175 -- -----------------------------------------------------------------------------
176 -- IOErrorTypes
177
178 -- | I\/O error where the operation failed because one of its arguments
179 -- already exists.
180 alreadyExistsErrorType :: IOErrorType
181 alreadyExistsErrorType = AlreadyExists
182
183 -- | I\/O error where the operation failed because one of its arguments
184 -- does not exist.
185 doesNotExistErrorType :: IOErrorType
186 doesNotExistErrorType = NoSuchThing
187
188 -- | I\/O error where the operation failed because one of its arguments
189 -- is a single-use resource, which is already being used.
190 alreadyInUseErrorType :: IOErrorType
191 alreadyInUseErrorType = ResourceBusy
192
193 -- | I\/O error where the operation failed because the device is full.
194 fullErrorType :: IOErrorType
195 fullErrorType = ResourceExhausted
196
197 -- | I\/O error where the operation failed because the end of file has
198 -- been reached.
199 eofErrorType :: IOErrorType
200 eofErrorType = EOF
201
202 -- | I\/O error where the operation is not possible.
203 illegalOperationErrorType :: IOErrorType
204 illegalOperationErrorType = IllegalOperation
205
206 -- | I\/O error where the operation failed because the user does not
207 -- have sufficient operating system privilege to perform that operation.
208 permissionErrorType :: IOErrorType
209 permissionErrorType = PermissionDenied
210
211 -- | I\/O error that is programmer-defined.
212 userErrorType :: IOErrorType
213 userErrorType = UserError
214
215 -- -----------------------------------------------------------------------------
216 -- IOErrorType predicates
217
218 -- | I\/O error where the operation failed because one of its arguments
219 -- already exists.
220 isAlreadyExistsErrorType :: IOErrorType -> Bool
221 isAlreadyExistsErrorType AlreadyExists = True
222 isAlreadyExistsErrorType _ = False
223
224 -- | I\/O error where the operation failed because one of its arguments
225 -- does not exist.
226 isDoesNotExistErrorType :: IOErrorType -> Bool
227 isDoesNotExistErrorType NoSuchThing = True
228 isDoesNotExistErrorType _ = False
229
230 -- | I\/O error where the operation failed because one of its arguments
231 -- is a single-use resource, which is already being used.
232 isAlreadyInUseErrorType :: IOErrorType -> Bool
233 isAlreadyInUseErrorType ResourceBusy = True
234 isAlreadyInUseErrorType _ = False
235
236 -- | I\/O error where the operation failed because the device is full.
237 isFullErrorType :: IOErrorType -> Bool
238 isFullErrorType ResourceExhausted = True
239 isFullErrorType _ = False
240
241 -- | I\/O error where the operation failed because the end of file has
242 -- been reached.
243 isEOFErrorType :: IOErrorType -> Bool
244 isEOFErrorType EOF = True
245 isEOFErrorType _ = False
246
247 -- | I\/O error where the operation is not possible.
248 isIllegalOperationErrorType :: IOErrorType -> Bool
249 isIllegalOperationErrorType IllegalOperation = True
250 isIllegalOperationErrorType _ = False
251
252 -- | I\/O error where the operation failed because the user does not
253 -- have sufficient operating system privilege to perform that operation.
254 isPermissionErrorType :: IOErrorType -> Bool
255 isPermissionErrorType PermissionDenied = True
256 isPermissionErrorType _ = False
257
258 -- | I\/O error that is programmer-defined.
259 isUserErrorType :: IOErrorType -> Bool
260 isUserErrorType UserError = True
261 isUserErrorType _ = False
262
263 -- -----------------------------------------------------------------------------
264 -- Miscellaneous
265
266 ioeGetErrorType :: IOError -> IOErrorType
267 ioeGetErrorString :: IOError -> String
268 ioeGetLocation :: IOError -> String
269 ioeGetHandle :: IOError -> Maybe Handle
270 ioeGetFileName :: IOError -> Maybe FilePath
271
272 ioeGetErrorType ioe = ioe_type ioe
273
274 ioeGetErrorString ioe
275 | isUserErrorType (ioe_type ioe) = ioe_description ioe
276 | otherwise = show (ioe_type ioe)
277
278 ioeGetLocation ioe = ioe_location ioe
279
280 ioeGetHandle ioe = ioe_handle ioe
281
282 ioeGetFileName ioe = ioe_filename ioe
283
284 ioeSetErrorType :: IOError -> IOErrorType -> IOError
285 ioeSetErrorString :: IOError -> String -> IOError
286 ioeSetLocation :: IOError -> String -> IOError
287 ioeSetHandle :: IOError -> Handle -> IOError
288 ioeSetFileName :: IOError -> FilePath -> IOError
289
290 ioeSetErrorType ioe errtype = ioe{ ioe_type = errtype }
291 ioeSetErrorString ioe str = ioe{ ioe_description = str }
292 ioeSetLocation ioe str = ioe{ ioe_location = str }
293 ioeSetHandle ioe hdl = ioe{ ioe_handle = Just hdl }
294 ioeSetFileName ioe filename = ioe{ ioe_filename = Just filename }
295
296 -- | Catch any 'IOError' that occurs in the computation and throw a
297 -- modified version.
298 modifyIOError :: (IOError -> IOError) -> IO a -> IO a
299 modifyIOError f io = catch io (\e -> ioError (f e))
300
301 -- -----------------------------------------------------------------------------
302 -- annotating an IOError
303
304 -- | Adds a location description and maybe a file path and file handle
305 -- to an 'IOError'. If any of the file handle or file path is not given
306 -- the corresponding value in the 'IOError' remains unaltered.
307 annotateIOError :: IOError
308 -> String
309 -> Maybe Handle
310 -> Maybe FilePath
311 -> IOError
312 annotateIOError ioe loc hdl path =
313 ioe{ ioe_handle = hdl `mplus` ioe_handle ioe,
314 ioe_location = loc, ioe_filename = path `mplus` ioe_filename ioe }
315 where
316 mplus :: Maybe a -> Maybe a -> Maybe a
317 Nothing `mplus` ys = ys
318 xs `mplus` _ = xs
319
320 -- | The 'catchIOError' function establishes a handler that receives any
321 -- 'IOError' raised in the action protected by 'catchIOError'.
322 -- An 'IOError' is caught by
323 -- the most recent handler established by one of the exception handling
324 -- functions. These handlers are
325 -- not selective: all 'IOError's are caught. Exception propagation
326 -- must be explicitly provided in a handler by re-raising any unwanted
327 -- exceptions. For example, in
328 --
329 -- > f = catchIOError g (\e -> if IO.isEOFError e then return [] else ioError e)
330 --
331 -- the function @f@ returns @[]@ when an end-of-file exception
332 -- (cf. 'System.IO.Error.isEOFError') occurs in @g@; otherwise, the
333 -- exception is propagated to the next outer handler.
334 --
335 -- When an exception propagates outside the main program, the Haskell
336 -- system prints the associated 'IOError' value and exits the program.
337 --
338 -- Non-I\/O exceptions are not caught by this variant; to catch all
339 -- exceptions, use 'Control.Exception.catch' from "Control.Exception".
340 catchIOError :: IO a -> (IOError -> IO a) -> IO a
341 catchIOError = catch