X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=System%2FIO%2FError.hs;h=372bb152622c658e075245d9e0d1813a9ca45bea;hb=37ab854f9d2c1280117658bbd29919968f4f4585;hp=9ac35a01ed6a923232079c011b80e5b397e1bd2b;hpb=5feea6f48f51876033b43bc6012f6f568ebfd397;p=ghc-base.git diff --git a/System/IO/Error.hs b/System/IO/Error.hs index 9ac35a0..372bb15 100644 --- a/System/IO/Error.hs +++ b/System/IO/Error.hs @@ -1,4 +1,4 @@ -{-# OPTIONS -fno-implicit-prelude #-} +{-# OPTIONS_GHC -XNoImplicitPrelude #-} ----------------------------------------------------------------------------- -- | @@ -15,19 +15,51 @@ ----------------------------------------------------------------------------- module System.IO.Error ( - IOError, -- abstract -#ifdef __GLASGOW_HASKELL__ - IOErrorType, -- abstract + + -- * I\/O errors + IOError, -- = IOException + + userError, -- :: String -> IOError + +#ifndef __NHC__ + mkIOError, -- :: IOErrorType -> String -> Maybe Handle + -- -> Maybe FilePath -> IOError + + annotateIOError, -- :: IOError -> String -> Maybe Handle + -- -> Maybe FilePath -> IOError #endif - ioError, -- :: IOError -> IO a - userError, -- :: String -> IOError + -- ** Classifying I\/O errors + isAlreadyExistsError, -- :: IOError -> Bool + isDoesNotExistError, + isAlreadyInUseError, + isFullError, + isEOFError, + isIllegalOperation, + isPermissionError, + isUserError, + + -- ** Attributes of I\/O errors +#ifndef __NHC__ + ioeGetErrorType, -- :: IOError -> IOErrorType + ioeGetLocation, -- :: IOError -> String +#endif + ioeGetErrorString, -- :: IOError -> String + ioeGetHandle, -- :: IOError -> Maybe Handle + ioeGetFileName, -- :: IOError -> Maybe FilePath + +#ifndef __NHC__ + ioeSetErrorType, -- :: IOError -> IOErrorType -> IOError + ioeSetErrorString, -- :: IOError -> String -> IOError + ioeSetLocation, -- :: IOError -> String -> IOError + ioeSetHandle, -- :: IOError -> Handle -> IOError + ioeSetFileName, -- :: IOError -> FilePath -> IOError +#endif -#ifdef __GLASGOW_HASKELL__ - mkIOError, -- :: IOErrorType -> String -> Maybe Handle - -- -> Maybe FilePath -> IOError + -- * Types of I\/O error + IOErrorType, -- abstract - alreadyExistsErrorType, -- :: IOErrorType + alreadyExistsErrorType, -- :: IOErrorType doesNotExistErrorType, alreadyInUseErrorType, fullErrorType, @@ -36,7 +68,8 @@ module System.IO.Error ( permissionErrorType, userErrorType, - isAlreadyExistsErrorType, -- :: IOErrorType -> Bool + -- ** 'IOErrorType' predicates + isAlreadyExistsErrorType, -- :: IOErrorType -> Bool isDoesNotExistErrorType, isAlreadyInUseErrorType, isFullErrorType, @@ -44,44 +77,45 @@ module System.IO.Error ( isIllegalOperationErrorType, isPermissionErrorType, isUserErrorType, -#endif /* __GLASGOW_HASKELL__ */ - isAlreadyExistsError, -- :: IOError -> Bool - isDoesNotExistError, - isAlreadyInUseError, - isFullError, - isEOFError, - isIllegalOperation, - isPermissionError, - isUserError, + -- * Throwing and catching I\/O errors -#ifdef __GLASGOW_HASKELL__ - ioeGetErrorType, -- :: IOError -> IOErrorType -#endif - ioeGetErrorString, -- :: IOError -> String - ioeGetHandle, -- :: IOError -> Maybe Handle - ioeGetFileName, -- :: IOError -> Maybe FilePath + ioError, -- :: IOError -> IO a + catch, -- :: IO a -> (IOError -> IO a) -> IO a + try, -- :: IO a -> IO (Either IOError a) + +#ifndef __NHC__ + modifyIOError, -- :: (IOError -> IOError) -> IO a -> IO a +#endif ) where +#ifndef __HUGS__ +import qualified Control.Exception.Base as New (catch) +#endif + +#ifndef __HUGS__ +import Data.Either +#endif +import Data.Maybe #ifdef __GLASGOW_HASKELL__ import GHC.Base -import Data.Maybe import GHC.IOBase import Text.Show #endif #ifdef __HUGS__ -import Hugs.IO +import Hugs.Prelude(Handle, IOException(..), IOErrorType(..), IO) #endif #ifdef __NHC__ import IO ( IOError () + , try , ioError , userError - , isAlreadyExistsError -- :: IOError -> Bool + , isAlreadyExistsError -- :: IOError -> Bool , isDoesNotExistError , isAlreadyInUseError , isFullError @@ -97,18 +131,38 @@ import IO --import Control.Monad (MonadPlus(mplus)) #endif -#ifdef __GLASGOW_HASKELL__ +-- | The construct 'try' @comp@ exposes IO errors which occur within a +-- computation, and which are not fully handled. +-- +-- Non-I\/O exceptions are not caught by this variant; to catch all +-- exceptions, use 'Control.Exception.try' from "Control.Exception". + +#ifndef __NHC__ +try :: IO a -> IO (Either IOError a) +try f = catch (do r <- f + return (Right r)) + (return . Left) +#endif + +#if defined(__GLASGOW_HASKELL__) || defined(__HUGS__) -- ----------------------------------------------------------------------------- -- Constructing an IOError +-- | Construct an 'IOError' of the given type where the second argument +-- describes the error location and the third and fourth argument +-- contain the file handle and file path of the file involved in the +-- error if applicable. mkIOError :: IOErrorType -> String -> Maybe Handle -> Maybe FilePath -> IOError mkIOError t location maybe_hdl maybe_filename = - IOException IOError{ ioe_type = t, - ioe_location = location, - ioe_descr = "", - ioe_handle = maybe_hdl, - ioe_filename = maybe_filename - } + IOError{ ioe_type = t, + ioe_location = location, + ioe_description = "", +#if defined(__GLASGOW_HASKELL__) + ioe_errno = Nothing, +#endif + ioe_handle = maybe_hdl, + ioe_filename = maybe_filename + } #ifdef __NHC__ mkIOError EOF location maybe_hdl maybe_filename = EOFError location (fromJust maybe_hdl) @@ -124,126 +178,212 @@ mkIOError t location maybe_hdl maybe_filename = ioeTypeToInt IllegalOperation = fromEnum EPERM ioeTypeToInt PermissionDenied = fromEnum EACCES #endif +#endif /* __GLASGOW_HASKELL__ || __HUGS__ */ +#ifndef __NHC__ -- ----------------------------------------------------------------------------- -- IOErrorType -isAlreadyExistsError, isDoesNotExistError, isAlreadyInUseError, - isFullError, isEOFError, isIllegalOperation, isPermissionError, - isUserError :: IOError -> Bool - +-- | An error indicating that an 'IO' operation failed because +-- one of its arguments already exists. +isAlreadyExistsError :: IOError -> Bool isAlreadyExistsError = isAlreadyExistsErrorType . ioeGetErrorType + +-- | An error indicating that an 'IO' operation failed because +-- one of its arguments does not exist. +isDoesNotExistError :: IOError -> Bool isDoesNotExistError = isDoesNotExistErrorType . ioeGetErrorType + +-- | An error indicating that an 'IO' operation failed because +-- one of its arguments is a single-use resource, which is already +-- being used (for example, opening the same file twice for writing +-- might give this error). +isAlreadyInUseError :: IOError -> Bool isAlreadyInUseError = isAlreadyInUseErrorType . ioeGetErrorType + +-- | An error indicating that an 'IO' operation failed because +-- the device is full. +isFullError :: IOError -> Bool isFullError = isFullErrorType . ioeGetErrorType + +-- | An error indicating that an 'IO' operation failed because +-- the end of file has been reached. +isEOFError :: IOError -> Bool isEOFError = isEOFErrorType . ioeGetErrorType + +-- | An error indicating that an 'IO' operation failed because +-- the operation was not possible. +-- Any computation which returns an 'IO' result may fail with +-- 'isIllegalOperation'. In some cases, an implementation will not be +-- able to distinguish between the possible error causes. In this case +-- it should fail with 'isIllegalOperation'. +isIllegalOperation :: IOError -> Bool isIllegalOperation = isIllegalOperationErrorType . ioeGetErrorType + +-- | An error indicating that an 'IO' operation failed because +-- the user does not have sufficient operating system privilege +-- to perform that operation. +isPermissionError :: IOError -> Bool isPermissionError = isPermissionErrorType . ioeGetErrorType + +-- | A programmer-defined error value constructed using 'userError'. +isUserError :: IOError -> Bool isUserError = isUserErrorType . ioeGetErrorType -#endif +#endif /* __NHC__ */ -- ----------------------------------------------------------------------------- -- IOErrorTypes #ifdef __NHC__ data IOErrorType = AlreadyExists | NoSuchThing | ResourceBusy - | ResourceExhausted | EOF | IllegalOperation - | PermissionDenied | UserError + | ResourceExhausted | EOF | IllegalOperation + | PermissionDenied | UserError #endif -#ifdef __GLASGOW_HASKELL__ -alreadyExistsErrorType, doesNotExistErrorType, alreadyInUseErrorType, - fullErrorType, eofErrorType, illegalOperationErrorType, - permissionErrorType, userErrorType :: IOErrorType - +-- | I\/O error where the operation failed because one of its arguments +-- already exists. +alreadyExistsErrorType :: IOErrorType alreadyExistsErrorType = AlreadyExists + +-- | I\/O error where the operation failed because one of its arguments +-- does not exist. +doesNotExistErrorType :: IOErrorType doesNotExistErrorType = NoSuchThing + +-- | I\/O error where the operation failed because one of its arguments +-- is a single-use resource, which is already being used. +alreadyInUseErrorType :: IOErrorType alreadyInUseErrorType = ResourceBusy + +-- | I\/O error where the operation failed because the device is full. +fullErrorType :: IOErrorType fullErrorType = ResourceExhausted + +-- | I\/O error where the operation failed because the end of file has +-- been reached. +eofErrorType :: IOErrorType eofErrorType = EOF + +-- | I\/O error where the operation is not possible. +illegalOperationErrorType :: IOErrorType illegalOperationErrorType = IllegalOperation + +-- | I\/O error where the operation failed because the user does not +-- have sufficient operating system privilege to perform that operation. +permissionErrorType :: IOErrorType permissionErrorType = PermissionDenied -userErrorType = UserError -#endif + +-- | I\/O error that is programmer-defined. +userErrorType :: IOErrorType +userErrorType = UserError -- ----------------------------------------------------------------------------- -- IOErrorType predicates -#ifdef __GLASGOW_HASKELL__ -isAlreadyExistsErrorType, isDoesNotExistErrorType, isAlreadyInUseErrorType, - isFullErrorType, isEOFErrorType, isIllegalOperationErrorType, - isPermissionErrorType, isUserErrorType :: IOErrorType -> Bool -#endif - -#ifdef __GLASGOW_HASKELL__ +-- | I\/O error where the operation failed because one of its arguments +-- already exists. +isAlreadyExistsErrorType :: IOErrorType -> Bool isAlreadyExistsErrorType AlreadyExists = True isAlreadyExistsErrorType _ = False +-- | I\/O error where the operation failed because one of its arguments +-- does not exist. +isDoesNotExistErrorType :: IOErrorType -> Bool isDoesNotExistErrorType NoSuchThing = True isDoesNotExistErrorType _ = False +-- | I\/O error where the operation failed because one of its arguments +-- is a single-use resource, which is already being used. +isAlreadyInUseErrorType :: IOErrorType -> Bool isAlreadyInUseErrorType ResourceBusy = True isAlreadyInUseErrorType _ = False +-- | I\/O error where the operation failed because the device is full. +isFullErrorType :: IOErrorType -> Bool isFullErrorType ResourceExhausted = True isFullErrorType _ = False +-- | I\/O error where the operation failed because the end of file has +-- been reached. +isEOFErrorType :: IOErrorType -> Bool isEOFErrorType EOF = True isEOFErrorType _ = False +-- | I\/O error where the operation is not possible. +isIllegalOperationErrorType :: IOErrorType -> Bool isIllegalOperationErrorType IllegalOperation = True isIllegalOperationErrorType _ = False +-- | I\/O error where the operation failed because the user does not +-- have sufficient operating system privilege to perform that operation. +isPermissionErrorType :: IOErrorType -> Bool isPermissionErrorType PermissionDenied = True isPermissionErrorType _ = False +-- | I\/O error that is programmer-defined. +isUserErrorType :: IOErrorType -> Bool isUserErrorType UserError = True isUserErrorType _ = False -#endif -- ----------------------------------------------------------------------------- -- Miscellaneous -#ifdef __GLASGOW_HASKELL__ -ioeGetErrorType :: IOError -> IOErrorType -ioeGetHandle :: IOError -> Maybe Handle +#if defined(__GLASGOW_HASKELL__) || defined(__HUGS__) +ioeGetErrorType :: IOError -> IOErrorType ioeGetErrorString :: IOError -> String +ioeGetLocation :: IOError -> String +ioeGetHandle :: IOError -> Maybe Handle ioeGetFileName :: IOError -> Maybe FilePath -ioeGetErrorType (IOException ioe) = ioe_type ioe -ioeGetErrorType _ = error "System.IO.Error.ioeGetErrorType: not an IO error" - -ioeGetHandle (IOException ioe) = ioe_handle ioe -ioeGetHandle _ = error "System.IO.Error.ioeGetHandle: not an IO error" +ioeGetErrorType ioe = ioe_type ioe -ioeGetErrorString (IOException ioe) - | isUserErrorType (ioe_type ioe) = ioe_descr ioe +ioeGetErrorString ioe + | isUserErrorType (ioe_type ioe) = ioe_description ioe | otherwise = show (ioe_type ioe) -ioeGetErrorString _ = error "System.IO.Error.ioeGetErrorString: not an IO error" -ioeGetFileName (IOException ioe) = ioe_filename ioe -ioeGetFileName _ = error "System.IO.Error.ioeGetFileName: not an IO error" -#endif +ioeGetLocation ioe = ioe_location ioe + +ioeGetHandle ioe = ioe_handle ioe + +ioeGetFileName ioe = ioe_filename ioe + +ioeSetErrorType :: IOError -> IOErrorType -> IOError +ioeSetErrorString :: IOError -> String -> IOError +ioeSetLocation :: IOError -> String -> IOError +ioeSetHandle :: IOError -> Handle -> IOError +ioeSetFileName :: IOError -> FilePath -> IOError + +ioeSetErrorType ioe errtype = ioe{ ioe_type = errtype } +ioeSetErrorString ioe str = ioe{ ioe_description = str } +ioeSetLocation ioe str = ioe{ ioe_location = str } +ioeSetHandle ioe hdl = ioe{ ioe_handle = Just hdl } +ioeSetFileName ioe filename = ioe{ ioe_filename = Just filename } + +-- | Catch any 'IOError' that occurs in the computation and throw a +-- modified version. +modifyIOError :: (IOError -> IOError) -> IO a -> IO a +modifyIOError f io = catch io (\e -> ioError (f e)) -- ----------------------------------------------------------------------------- -- annotating an IOError -#ifdef __GLASGOW_HASKELL__ +-- | Adds a location description and maybe a file path and file handle +-- to an 'IOError'. If any of the file handle or file path is not given +-- the corresponding value in the 'IOError' remains unaltered. annotateIOError :: IOError -> String - -> Maybe FilePath -> Maybe Handle + -> Maybe FilePath -> IOError -annotateIOError (IOException (IOError hdl errTy _ str path)) loc opath ohdl = - IOException (IOError (hdl `mplus` ohdl) errTy loc str (path `mplus` opath)) +annotateIOError ioe loc hdl path = + ioe{ ioe_handle = hdl `mplus` ioe_handle ioe, + ioe_location = loc, ioe_filename = path `mplus` ioe_filename ioe } where Nothing `mplus` ys = ys xs `mplus` _ = xs -annotateIOError exc _ _ _ = - exc -#endif +#endif /* __GLASGOW_HASKELL__ || __HUGS__ */ -#ifdef 0 /*__NHC__*/ +#if 0 /*__NHC__*/ annotateIOError (IOError msg file hdl code) msg' file' hdl' = IOError (msg++'\n':msg') (file`mplus`file') (hdl`mplus`hdl') code annotateIOError (EOFError msg hdl) msg' file' hdl' = @@ -253,3 +393,26 @@ annotateIOError (UserError loc msg) msg' file' hdl' = annotateIOError (PatternError loc) msg' file' hdl' = PatternError (loc++'\n':msg') #endif + +#ifndef __HUGS__ +-- | The 'catch' function establishes a handler that receives any 'IOError' +-- raised in the action protected by 'catch'. An 'IOError' is caught by +-- the most recent handler established by 'catch'. These handlers are +-- not selective: all 'IOError's are caught. Exception propagation +-- must be explicitly provided in a handler by re-raising any unwanted +-- exceptions. For example, in +-- +-- > f = catch g (\e -> if IO.isEOFError e then return [] else ioError e) +-- +-- the function @f@ returns @[]@ when an end-of-file exception +-- (cf. 'System.IO.Error.isEOFError') occurs in @g@; otherwise, the +-- exception is propagated to the next outer handler. +-- +-- When an exception propagates outside the main program, the Haskell +-- system prints the associated 'IOError' value and exits the program. +-- +-- Non-I\/O exceptions are not caught by this variant; to catch all +-- exceptions, use 'Control.Exception.catch' from "Control.Exception". +catch :: IO a -> (IOError -> IO a) -> IO a +catch = New.catch +#endif /* !__HUGS__ */