6fec277f5699308bce6ebde0356b150b0412dc77
[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 #ifndef __HUGS__
85 import Control.Exception.Base
86 #endif
87
88 #ifndef __HUGS__
89 import Data.Either
90 #endif
91 import Data.Maybe
92
93 #ifdef __GLASGOW_HASKELL__
94 import GHC.Base
95 import GHC.IO
96 import GHC.IO.Exception
97 import GHC.IO.Handle.Types
98 import Text.Show
99 #endif
100
101 #ifdef __HUGS__
102 import Hugs.Prelude(Handle, IOException(..), IOErrorType(..), IO)
103 #endif
104
105 -- | The construct 'tryIOError' @comp@ exposes IO errors which occur within a
106 -- computation, and which are not fully handled.
107 --
108 -- Non-I\/O exceptions are not caught by this variant; to catch all
109 -- exceptions, use 'Control.Exception.try' from "Control.Exception".
110 tryIOError :: IO a -> IO (Either IOError a)
111 tryIOError f = catch (do r <- f
112 return (Right r))
113 (return . Left)
114
115 -- -----------------------------------------------------------------------------
116 -- Constructing an IOError
117
118 -- | Construct an 'IOError' of the given type where the second argument
119 -- describes the error location and the third and fourth argument
120 -- contain the file handle and file path of the file involved in the
121 -- error if applicable.
122 mkIOError :: IOErrorType -> String -> Maybe Handle -> Maybe FilePath -> IOError
123 mkIOError t location maybe_hdl maybe_filename =
124 IOError{ ioe_type = t,
125 ioe_location = location,
126 ioe_description = "",
127 #if defined(__GLASGOW_HASKELL__)
128 ioe_errno = Nothing,
129 #endif
130 ioe_handle = maybe_hdl,
131 ioe_filename = maybe_filename
132 }
133
134 -- -----------------------------------------------------------------------------
135 -- IOErrorType
136
137 -- | An error indicating that an 'IO' operation failed because
138 -- one of its arguments already exists.
139 isAlreadyExistsError :: IOError -> Bool
140 isAlreadyExistsError = isAlreadyExistsErrorType . ioeGetErrorType
141
142 -- | An error indicating that an 'IO' operation failed because
143 -- one of its arguments does not exist.
144 isDoesNotExistError :: IOError -> Bool
145 isDoesNotExistError = isDoesNotExistErrorType . ioeGetErrorType
146
147 -- | An error indicating that an 'IO' operation failed because
148 -- one of its arguments is a single-use resource, which is already
149 -- being used (for example, opening the same file twice for writing
150 -- might give this error).
151 isAlreadyInUseError :: IOError -> Bool
152 isAlreadyInUseError = isAlreadyInUseErrorType . ioeGetErrorType
153
154 -- | An error indicating that an 'IO' operation failed because
155 -- the device is full.
156 isFullError :: IOError -> Bool
157 isFullError = isFullErrorType . ioeGetErrorType
158
159 -- | An error indicating that an 'IO' operation failed because
160 -- the end of file has been reached.
161 isEOFError :: IOError -> Bool
162 isEOFError = isEOFErrorType . ioeGetErrorType
163
164 -- | An error indicating that an 'IO' operation failed because
165 -- the operation was not possible.
166 -- Any computation which returns an 'IO' result may fail with
167 -- 'isIllegalOperation'. In some cases, an implementation will not be
168 -- able to distinguish between the possible error causes. In this case
169 -- it should fail with 'isIllegalOperation'.
170 isIllegalOperation :: IOError -> Bool
171 isIllegalOperation = isIllegalOperationErrorType . ioeGetErrorType
172
173 -- | An error indicating that an 'IO' operation failed because
174 -- the user does not have sufficient operating system privilege
175 -- to perform that operation.
176 isPermissionError :: IOError -> Bool
177 isPermissionError = isPermissionErrorType . ioeGetErrorType
178
179 -- | A programmer-defined error value constructed using 'userError'.
180 isUserError :: IOError -> Bool
181 isUserError = isUserErrorType . ioeGetErrorType
182
183 -- -----------------------------------------------------------------------------
184 -- IOErrorTypes
185
186 -- | I\/O error where the operation failed because one of its arguments
187 -- already exists.
188 alreadyExistsErrorType :: IOErrorType
189 alreadyExistsErrorType = AlreadyExists
190
191 -- | I\/O error where the operation failed because one of its arguments
192 -- does not exist.
193 doesNotExistErrorType :: IOErrorType
194 doesNotExistErrorType = NoSuchThing
195
196 -- | I\/O error where the operation failed because one of its arguments
197 -- is a single-use resource, which is already being used.
198 alreadyInUseErrorType :: IOErrorType
199 alreadyInUseErrorType = ResourceBusy
200
201 -- | I\/O error where the operation failed because the device is full.
202 fullErrorType :: IOErrorType
203 fullErrorType = ResourceExhausted
204
205 -- | I\/O error where the operation failed because the end of file has
206 -- been reached.
207 eofErrorType :: IOErrorType
208 eofErrorType = EOF
209
210 -- | I\/O error where the operation is not possible.
211 illegalOperationErrorType :: IOErrorType
212 illegalOperationErrorType = IllegalOperation
213
214 -- | I\/O error where the operation failed because the user does not
215 -- have sufficient operating system privilege to perform that operation.
216 permissionErrorType :: IOErrorType
217 permissionErrorType = PermissionDenied
218
219 -- | I\/O error that is programmer-defined.
220 userErrorType :: IOErrorType
221 userErrorType = UserError
222
223 -- -----------------------------------------------------------------------------
224 -- IOErrorType predicates
225
226 -- | I\/O error where the operation failed because one of its arguments
227 -- already exists.
228 isAlreadyExistsErrorType :: IOErrorType -> Bool
229 isAlreadyExistsErrorType AlreadyExists = True
230 isAlreadyExistsErrorType _ = False
231
232 -- | I\/O error where the operation failed because one of its arguments
233 -- does not exist.
234 isDoesNotExistErrorType :: IOErrorType -> Bool
235 isDoesNotExistErrorType NoSuchThing = True
236 isDoesNotExistErrorType _ = False
237
238 -- | I\/O error where the operation failed because one of its arguments
239 -- is a single-use resource, which is already being used.
240 isAlreadyInUseErrorType :: IOErrorType -> Bool
241 isAlreadyInUseErrorType ResourceBusy = True
242 isAlreadyInUseErrorType _ = False
243
244 -- | I\/O error where the operation failed because the device is full.
245 isFullErrorType :: IOErrorType -> Bool
246 isFullErrorType ResourceExhausted = True
247 isFullErrorType _ = False
248
249 -- | I\/O error where the operation failed because the end of file has
250 -- been reached.
251 isEOFErrorType :: IOErrorType -> Bool
252 isEOFErrorType EOF = True
253 isEOFErrorType _ = False
254
255 -- | I\/O error where the operation is not possible.
256 isIllegalOperationErrorType :: IOErrorType -> Bool
257 isIllegalOperationErrorType IllegalOperation = True
258 isIllegalOperationErrorType _ = False
259
260 -- | I\/O error where the operation failed because the user does not
261 -- have sufficient operating system privilege to perform that operation.
262 isPermissionErrorType :: IOErrorType -> Bool
263 isPermissionErrorType PermissionDenied = True
264 isPermissionErrorType _ = False
265
266 -- | I\/O error that is programmer-defined.
267 isUserErrorType :: IOErrorType -> Bool
268 isUserErrorType UserError = True
269 isUserErrorType _ = False
270
271 -- -----------------------------------------------------------------------------
272 -- Miscellaneous
273
274 ioeGetErrorType :: IOError -> IOErrorType
275 ioeGetErrorString :: IOError -> String
276 ioeGetLocation :: IOError -> String
277 ioeGetHandle :: IOError -> Maybe Handle
278 ioeGetFileName :: IOError -> Maybe FilePath
279
280 ioeGetErrorType ioe = ioe_type ioe
281
282 ioeGetErrorString ioe
283 | isUserErrorType (ioe_type ioe) = ioe_description ioe
284 | otherwise = show (ioe_type ioe)
285
286 ioeGetLocation ioe = ioe_location ioe
287
288 ioeGetHandle ioe = ioe_handle ioe
289
290 ioeGetFileName ioe = ioe_filename ioe
291
292 ioeSetErrorType :: IOError -> IOErrorType -> IOError
293 ioeSetErrorString :: IOError -> String -> IOError
294 ioeSetLocation :: IOError -> String -> IOError
295 ioeSetHandle :: IOError -> Handle -> IOError
296 ioeSetFileName :: IOError -> FilePath -> IOError
297
298 ioeSetErrorType ioe errtype = ioe{ ioe_type = errtype }
299 ioeSetErrorString ioe str = ioe{ ioe_description = str }
300 ioeSetLocation ioe str = ioe{ ioe_location = str }
301 ioeSetHandle ioe hdl = ioe{ ioe_handle = Just hdl }
302 ioeSetFileName ioe filename = ioe{ ioe_filename = Just filename }
303
304 -- | Catch any 'IOError' that occurs in the computation and throw a
305 -- modified version.
306 modifyIOError :: (IOError -> IOError) -> IO a -> IO a
307 modifyIOError f io = catch io (\e -> ioError (f e))
308
309 -- -----------------------------------------------------------------------------
310 -- annotating an IOError
311
312 -- | Adds a location description and maybe a file path and file handle
313 -- to an 'IOError'. If any of the file handle or file path is not given
314 -- the corresponding value in the 'IOError' remains unaltered.
315 annotateIOError :: IOError
316 -> String
317 -> Maybe Handle
318 -> Maybe FilePath
319 -> IOError
320 annotateIOError ioe loc hdl path =
321 ioe{ ioe_handle = hdl `mplus` ioe_handle ioe,
322 ioe_location = loc, ioe_filename = path `mplus` ioe_filename ioe }
323 where
324 mplus :: Maybe a -> Maybe a -> Maybe a
325 Nothing `mplus` ys = ys
326 xs `mplus` _ = xs
327
328 #ifndef __HUGS__
329 -- | The 'catchIOError' function establishes a handler that receives any
330 -- 'IOError' raised in the action protected by 'catchIOError'.
331 -- An 'IOError' is caught by
332 -- the most recent handler established by one of the exception handling
333 -- functions. These handlers are
334 -- not selective: all 'IOError's are caught. Exception propagation
335 -- must be explicitly provided in a handler by re-raising any unwanted
336 -- exceptions. For example, in
337 --
338 -- > f = catchIOError g (\e -> if IO.isEOFError e then return [] else ioError e)
339 --
340 -- the function @f@ returns @[]@ when an end-of-file exception
341 -- (cf. 'System.IO.Error.isEOFError') occurs in @g@; otherwise, the
342 -- exception is propagated to the next outer handler.
343 --
344 -- When an exception propagates outside the main program, the Haskell
345 -- system prints the associated 'IOError' value and exits the program.
346 --
347 -- Non-I\/O exceptions are not caught by this variant; to catch all
348 -- exceptions, use 'Control.Exception.catch' from "Control.Exception".
349 catchIOError :: IO a -> (IOError -> IO a) -> IO a
350 catchIOError = catch
351 #endif /* !__HUGS__ */
352