{-# OPTIONS_GHC -fno-warn-unused-matches #-}{-# LANGUAGE NoImplicitPrelude, RecordWildCards #-}------------------------------------------------------------------------------- |-- Module : GHC.IO.Handle-- Copyright : (c) The University of Glasgow, 1994-2009-- License : see libraries/base/LICENSE-- -- Maintainer : libraries@haskell.org-- Stability : provisional-- Portability : non-portable---- External API for GHC's Handle implementation-------------------------------------------------------------------------------moduleGHC.IO.Handle(Handle,BufferMode(..),mkFileHandle,mkDuplexHandle,hFileSize,hSetFileSize,hIsEOF,hLookAhead,hSetBuffering,hSetBinaryMode,hSetEncoding,hGetEncoding,hFlush,hFlushAll,hDuplicate,hDuplicateTo,hClose,hClose_help,HandlePosition,HandlePosn(..),hGetPosn,hSetPosn,SeekMode(..),hSeek,hTell,hIsOpen,hIsClosed,hIsReadable,hIsWritable,hGetBuffering,hIsSeekable,hSetEcho,hGetEcho,hIsTerminalDevice,hSetNewlineMode,Newline(..),NewlineMode(..),nativeNewline,noNewlineTranslation,universalNewlineMode,nativeNewlineMode,hShow,hWaitForInput,hGetChar,hGetLine,hGetContents,hPutChar,hPutStr,hGetBuf,hGetBufNonBlocking,hPutBuf,hPutBufNonBlocking)whereimportGHC.IOimportGHC.IO.ExceptionimportGHC.IO.EncodingimportGHC.IO.BufferimportGHC.IO.BufferedIO(BufferedIO)importGHC.IO.DeviceasIODeviceimportGHC.IO.Handle.TypesimportGHC.IO.Handle.InternalsimportGHC.IO.Handle.TextimportqualifiedGHC.IO.BufferedIOasBufferedimportGHC.BaseimportGHC.ExceptionimportGHC.MVarimportGHC.IORefimportGHC.ShowimportGHC.NumimportGHC.RealimportData.MaybeimportData.TypeableimportControl.Monad-- ----------------------------------------------------------------------------- Closing a handle-- | Computation 'hClose' @hdl@ makes handle @hdl@ closed. Before the-- computation finishes, if @hdl@ is writable its buffer is flushed as-- for 'hFlush'.-- Performing 'hClose' on a handle that has already been closed has no effect; -- doing so is not an error. All other operations on a closed handle will fail.-- If 'hClose' fails for any reason, any further operations (apart from-- 'hClose') on the handle will still fail as if @hdl@ had been successfully-- closed.hClose::Handle->IO()hCloseh@(FileHandle_m)=domb_exc<-hClose'hmhClose_maybethrowmb_exchhCloseh@(DuplexHandle_rw)=doexcs<-mapM(hClose'h)[r,w]hClose_maybethrow(listToMaybe(catMaybesexcs))hhClose_maybethrow::MaybeSomeException->Handle->IO()hClose_maybethrowNothingh=return()hClose_maybethrow(Juste)h=hClose_rethrowehhClose_rethrow::SomeException->Handle->IO()hClose_rethroweh=casefromExceptioneofJustioe->ioError(augmentIOErrorioe"hClose"h)Nothing->throwIOehClose'::Handle->MVarHandle__->IO(MaybeSomeException)hClose'hm=withHandle'"hClose"hm$hClose_help------------------------------------------------------------------------------- Detecting and changing the size of a file-- | For a handle @hdl@ which attached to a physical file,-- 'hFileSize' @hdl@ returns the size of that file in 8-bit bytes.hFileSize::Handle->IOIntegerhFileSizehandle=withHandle_"hFileSize"handle$\handle_@Handle__{haDevice=dev}->docasehaTypehandle_ofClosedHandle->ioe_closedHandleSemiClosedHandle->ioe_closedHandle_->doflushWriteBufferhandle_r<-IODevice.getSizedevifr/=-1thenreturnrelseioException(IOErrorNothingInappropriateType"hFileSize""not a regular file"NothingNothing)-- | 'hSetFileSize' @hdl@ @size@ truncates the physical file with handle @hdl@ to @size@ bytes.hSetFileSize::Handle->Integer->IO()hSetFileSizehandlesize=withHandle_"hSetFileSize"handle$\handle_@Handle__{haDevice=dev}->docasehaTypehandle_ofClosedHandle->ioe_closedHandleSemiClosedHandle->ioe_closedHandle_->doflushWriteBufferhandle_IODevice.setSizedevsizereturn()-- ----------------------------------------------------------------------------- Detecting the End of Input-- | For a readable handle @hdl@, 'hIsEOF' @hdl@ returns-- 'True' if no further input can be taken from @hdl@ or for a-- physical file, if the current I\/O position is equal to the length of-- the file. Otherwise, it returns 'False'.---- NOTE: 'hIsEOF' may block, because it has to attempt to read from-- the stream to determine whether there is any more data to be read.hIsEOF::Handle->IOBoolhIsEOFhandle=wantReadableHandle_"hIsEOF"handle$\Handle__{..}->docbuf<-readIORefhaCharBufferifnot(isEmptyBuffercbuf)thenreturnFalseelsedobbuf<-readIORefhaByteBufferifnot(isEmptyBufferbbuf)thenreturnFalseelsedo-- NB. do no decoding, just fill the byte buffer; see #3808(r,bbuf')<-Buffered.fillReadBufferhaDevicebbufifr==0thenreturnTrueelsedowriteIORefhaByteBufferbbuf'returnFalse-- ----------------------------------------------------------------------------- Looking ahead-- | Computation 'hLookAhead' returns the next character from the handle-- without removing it from the input buffer, blocking until a character-- is available.---- This operation may fail with:---- * 'isEOFError' if the end of file has been reached.hLookAhead::Handle->IOCharhLookAheadhandle=wantReadableHandle_"hLookAhead"handlehLookAhead_-- ----------------------------------------------------------------------------- Buffering Operations-- Three kinds of buffering are supported: line-buffering,-- block-buffering or no-buffering. See GHC.IO.Handle for definition and-- further explanation of what the type represent.-- | Computation 'hSetBuffering' @hdl mode@ sets the mode of buffering for-- handle @hdl@ on subsequent reads and writes.---- If the buffer mode is changed from 'BlockBuffering' or-- 'LineBuffering' to 'NoBuffering', then---- * if @hdl@ is writable, the buffer is flushed as for 'hFlush';---- * if @hdl@ is not writable, the contents of the buffer is discarded.---- This operation may fail with:---- * 'isPermissionError' if the handle has already been used for reading-- or writing and the implementation does not allow the buffering mode-- to be changed.hSetBuffering::Handle->BufferMode->IO()hSetBufferinghandlemode=withAllHandles__"hSetBuffering"handle$\handle_@Handle__{..}->docasehaTypeofClosedHandle->ioe_closedHandle_->doifmode==haBufferModethenreturnhandle_elsedo-- See [note Buffer Sizing] in GHC.IO.Handle.Types-- check for errors:casemodeofBlockBuffering(Justn)|n<=0->ioe_bufsizn_->return()-- for input terminals we need to put the terminal into-- cooked or raw mode depending on the type of buffering.is_tty<-IODevice.isTerminalhaDevicewhen(is_tty&&isReadableHandleTypehaType)$casemodeof#ifndef mingw32_HOST_OS-- 'raw' mode under win32 is a bit too specialised (and troublesome-- for most common uses), so simply disable its use here.NoBuffering->IODevice.setRawhaDeviceTrue#elseNoBuffering->return()#endif_->IODevice.setRawhaDeviceFalse-- throw away spare buffers, they might be the wrong sizewriteIORefhaBuffersBufferListNilreturnHandle__{haBufferMode=mode,..}-- ------------------------------------------------------------------------------- hSetEncoding-- | The action 'hSetEncoding' @hdl@ @encoding@ changes the text encoding-- for the handle @hdl@ to @encoding@. The default encoding when a 'Handle' is-- created is 'localeEncoding', namely the default encoding for the current-- locale.---- To create a 'Handle' with no encoding at all, use 'openBinaryFile'. To-- stop further encoding or decoding on an existing 'Handle', use-- 'hSetBinaryMode'.---- 'hSetEncoding' may need to flush buffered data in order to change-- the encoding.--hSetEncoding::Handle->TextEncoding->IO()hSetEncodinghdlencoding=dowithAllHandles__"hSetEncoding"hdl$\h_@Handle__{..}->doflushCharBufferh_closeTextCodecsh_openTextEncoding(Justencoding)haType$\mb_encodermb_decoder->dobbuf<-readIORefhaByteBufferref<-newIORef(error"last_decode")return(Handle__{haLastDecode=ref,haDecoder=mb_decoder,haEncoder=mb_encoder,haCodec=Justencoding,..})-- | Return the current 'TextEncoding' for the specified 'Handle', or-- 'Nothing' if the 'Handle' is in binary mode.---- Note that the 'TextEncoding' remembers nothing about the state of-- the encoder/decoder in use on this 'Handle'. For example, if the-- encoding in use is UTF-16, then using 'hGetEncoding' and-- 'hSetEncoding' to save and restore the encoding may result in an-- extra byte-order-mark being written to the file.--hGetEncoding::Handle->IO(MaybeTextEncoding)hGetEncodinghdl=withHandle_"hGetEncoding"hdl$\h_@Handle__{..}->returnhaCodec-- ------------------------------------------------------------------------------- hFlush-- | The action 'hFlush' @hdl@ causes any items buffered for output-- in handle @hdl@ to be sent immediately to the operating system.---- This operation may fail with:---- * 'isFullError' if the device is full;---- * 'isPermissionError' if a system resource limit would be exceeded.-- It is unspecified whether the characters in the buffer are discarded-- or retained under these circumstances.hFlush::Handle->IO()hFlushhandle=wantWritableHandle"hFlush"handleflushWriteBuffer-- | The action 'hFlushAll' @hdl@ flushes all buffered data in @hdl@,-- including any buffered read data. Buffered read data is flushed-- by seeking the file position back to the point before the bufferred-- data was read, and hence only works if @hdl@ is seekable (see-- 'hIsSeekable').---- This operation may fail with:---- * 'isFullError' if the device is full;---- * 'isPermissionError' if a system resource limit would be exceeded.-- It is unspecified whether the characters in the buffer are discarded-- or retained under these circumstances;---- * 'isIllegalOperation' if @hdl@ has buffered read data, and is not-- seekable.hFlushAll::Handle->IO()hFlushAllhandle=withHandle_"hFlushAll"handleflushBuffer-- ------------------------------------------------------------------------------- Repositioning HandlesdataHandlePosn=HandlePosnHandleHandlePositioninstanceEqHandlePosnwhere(HandlePosnh1p1)==(HandlePosnh2p2)=p1==p2&&h1==h2instanceShowHandlePosnwhereshowsPrecp(HandlePosnhpos)=showsPrecph.showString" at position ".showspos-- HandlePosition is the Haskell equivalent of POSIX' off_t.-- We represent it as an Integer on the Haskell side, but-- cheat slightly in that hGetPosn calls upon a C helper-- that reports the position back via (merely) an Int.typeHandlePosition=Integer-- | Computation 'hGetPosn' @hdl@ returns the current I\/O position of-- @hdl@ as a value of the abstract type 'HandlePosn'.hGetPosn::Handle->IOHandlePosnhGetPosnhandle=doposn<-hTellhandlereturn(HandlePosnhandleposn)-- | If a call to 'hGetPosn' @hdl@ returns a position @p@,-- then computation 'hSetPosn' @p@ sets the position of @hdl@-- to the position it held at the time of the call to 'hGetPosn'.---- This operation may fail with:---- * 'isPermissionError' if a system resource limit would be exceeded.hSetPosn::HandlePosn->IO()hSetPosn(HandlePosnhi)=hSeekhAbsoluteSeeki-- ----------------------------------------------------------------------------- hSeek{- Note:
- when seeking using `SeekFromEnd', positive offsets (>=0) means
seeking at or past EOF.
- we possibly deviate from the report on the issue of seeking within
the buffer and whether to flush it or not. The report isn't exactly
clear here.
-}-- | Computation 'hSeek' @hdl mode i@ sets the position of handle-- @hdl@ depending on @mode@.-- The offset @i@ is given in terms of 8-bit bytes.---- If @hdl@ is block- or line-buffered, then seeking to a position which is not-- in the current buffer will first cause any items in the output buffer to be-- written to the device, and then cause the input buffer to be discarded.-- Some handles may not be seekable (see 'hIsSeekable'), or only support a-- subset of the possible positioning operations (for instance, it may only-- be possible to seek to the end of a tape, or to a positive offset from-- the beginning or current position).-- It is not possible to set a negative I\/O position, or for-- a physical file, an I\/O position beyond the current end-of-file.---- This operation may fail with:---- * 'isIllegalOperationError' if the Handle is not seekable, or does-- not support the requested seek mode.---- * 'isPermissionError' if a system resource limit would be exceeded.hSeek::Handle->SeekMode->Integer->IO()hSeekhandlemodeoffset=wantSeekableHandle"hSeek"handle$\handle_@Handle__{..}->dodebugIO("hSeek "++show(mode,offset))buf<-readIORefhaCharBufferifisWriteBufferbufthendoflushWriteBufferhandle_IODevice.seekhaDevicemodeoffsetelsedoletr=bufLbuf;w=bufRbufifmode==RelativeSeek&&isNothinghaDecoder&&offset>=0&&offset<fromIntegral(w-r)thenwriteIORefhaCharBufferbuf{bufL=r+fromIntegraloffset}elsedoflushCharReadBufferhandle_flushByteReadBufferhandle_IODevice.seekhaDevicemodeoffset-- | Computation 'hTell' @hdl@ returns the current position of the-- handle @hdl@, as the number of bytes from the beginning of-- the file. The value returned may be subsequently passed to-- 'hSeek' to reposition the handle to the current position.-- -- This operation may fail with:---- * 'isIllegalOperationError' if the Handle is not seekable.--hTell::Handle->IOIntegerhTellhandle=wantSeekableHandle"hGetPosn"handle$\handle_@Handle__{..}->doposn<-IODevice.tellhaDevice-- we can't tell the real byte offset if there are buffered-- Chars, so must flush first:flushCharBufferhandle_bbuf<-readIORefhaByteBufferletreal_posn|isWriteBufferbbuf=posn+fromIntegral(bufferElemsbbuf)|otherwise=posn-fromIntegral(bufferElemsbbuf)cbuf<-readIORefhaCharBufferdebugIO("\nhGetPosn: (posn, real_posn) = "++show(posn,real_posn))debugIO(" cbuf: "++summaryBuffercbuf++" bbuf: "++summaryBufferbbuf)returnreal_posn-- ------------------------------------------------------------------------------- Handle Properties-- A number of operations return information about the properties of a-- handle. Each of these operations returns `True' if the handle has-- the specified property, and `False' otherwise.hIsOpen::Handle->IOBoolhIsOpenhandle=withHandle_"hIsOpen"handle$\handle_->docasehaTypehandle_ofClosedHandle->returnFalseSemiClosedHandle->returnFalse_->returnTruehIsClosed::Handle->IOBoolhIsClosedhandle=withHandle_"hIsClosed"handle$\handle_->docasehaTypehandle_ofClosedHandle->returnTrue_->returnFalse{- not defined, nor exported, but mentioned
here for documentation purposes:
hSemiClosed :: Handle -> IO Bool
hSemiClosed h = do
ho <- hIsOpen h
hc <- hIsClosed h
return (not (ho || hc))
-}hIsReadable::Handle->IOBoolhIsReadable(DuplexHandle___)=returnTruehIsReadablehandle=withHandle_"hIsReadable"handle$\handle_->docasehaTypehandle_ofClosedHandle->ioe_closedHandleSemiClosedHandle->ioe_closedHandlehtype->return(isReadableHandleTypehtype)hIsWritable::Handle->IOBoolhIsWritable(DuplexHandle___)=returnTruehIsWritablehandle=withHandle_"hIsWritable"handle$\handle_->docasehaTypehandle_ofClosedHandle->ioe_closedHandleSemiClosedHandle->ioe_closedHandlehtype->return(isWritableHandleTypehtype)-- | Computation 'hGetBuffering' @hdl@ returns the current buffering mode-- for @hdl@.hGetBuffering::Handle->IOBufferModehGetBufferinghandle=withHandle_"hGetBuffering"handle$\handle_->docasehaTypehandle_ofClosedHandle->ioe_closedHandle_->-- We're being non-standard here, and allow the buffering-- of a semi-closed handle to be queried. -- sof 6/98return(haBufferModehandle_)-- could be stricter..hIsSeekable::Handle->IOBoolhIsSeekablehandle=withHandle_"hIsSeekable"handle$\handle_@Handle__{..}->docasehaTypeofClosedHandle->ioe_closedHandleSemiClosedHandle->ioe_closedHandleAppendHandle->returnFalse_->IODevice.isSeekablehaDevice-- ------------------------------------------------------------------------------- Changing echo status (Non-standard GHC extensions)-- | Set the echoing status of a handle connected to a terminal.hSetEcho::Handle->Bool->IO()hSetEchohandleon=doisT<-hIsTerminalDevicehandleifnotisTthenreturn()elsewithHandle_"hSetEcho"handle$\Handle__{..}->docasehaTypeofClosedHandle->ioe_closedHandle_->IODevice.setEchohaDeviceon-- | Get the echoing status of a handle connected to a terminal.hGetEcho::Handle->IOBoolhGetEchohandle=doisT<-hIsTerminalDevicehandleifnotisTthenreturnFalseelsewithHandle_"hGetEcho"handle$\Handle__{..}->docasehaTypeofClosedHandle->ioe_closedHandle_->IODevice.getEchohaDevice-- | Is the handle connected to a terminal?hIsTerminalDevice::Handle->IOBoolhIsTerminalDevicehandle=dowithHandle_"hIsTerminalDevice"handle$\Handle__{..}->docasehaTypeofClosedHandle->ioe_closedHandle_->IODevice.isTerminalhaDevice-- ------------------------------------------------------------------------------- hSetBinaryMode-- | Select binary mode ('True') or text mode ('False') on a open handle.-- (See also 'openBinaryFile'.)---- This has the same effect as calling 'hSetEncoding' with 'latin1', together-- with 'hSetNewlineMode' with 'noNewlineTranslation'.--hSetBinaryMode::Handle->Bool->IO()hSetBinaryModehandlebin=withAllHandles__"hSetBinaryMode"handle$\h_@Handle__{..}->doflushCharBufferh_closeTextCodecsh_letmb_te|bin=Nothing|otherwise=JustlocaleEncodingopenTextEncodingmb_tehaType$\mb_encodermb_decoder->do-- should match the default newline mode, whatever that isletnl|bin=noNewlineTranslation|otherwise=nativeNewlineModebbuf<-readIORefhaByteBufferref<-newIORef(error"codec_state",bbuf)returnHandle__{haLastDecode=ref,haEncoder=mb_encoder,haDecoder=mb_decoder,haCodec=mb_te,haInputNL=inputNLnl,haOutputNL=outputNLnl,..}-- ------------------------------------------------------------------------------- hSetNewlineMode-- | Set the 'NewlineMode' on the specified 'Handle'. All buffered-- data is flushed first.hSetNewlineMode::Handle->NewlineMode->IO()hSetNewlineModehandleNewlineMode{inputNL=i,outputNL=o}=withAllHandles__"hSetNewlineMode"handle$\h_@Handle__{..}->doflushBufferh_returnh_{haInputNL=i,haOutputNL=o}-- ------------------------------------------------------------------------------- Duplicating a Handle-- | Returns a duplicate of the original handle, with its own buffer.-- The two Handles will share a file pointer, however. The original-- handle's buffer is flushed, including discarding any input data,-- before the handle is duplicated.hDuplicate::Handle->IOHandlehDuplicateh@(FileHandlepathm)=dowithHandle_'"hDuplicate"hm$\h_->dupHandlepathhNothingh_(JusthandleFinalizer)hDuplicateh@(DuplexHandlepathrw)=dowrite_side@(FileHandle_write_m)<-withHandle_'"hDuplicate"hw$\h_->dupHandlepathhNothingh_(JusthandleFinalizer)read_side@(FileHandle_read_m)<-withHandle_'"hDuplicate"hr$\h_->dupHandlepathh(Justwrite_m)h_Nothingreturn(DuplexHandlepathread_mwrite_m)dupHandle::FilePath->Handle->Maybe(MVarHandle__)->Handle__->MaybeHandleFinalizer->IOHandledupHandlefilepathhother_sideh_@Handle__{..}mb_finalizer=do-- flush the buffer first, so we don't have to copy its contentsflushBufferh_caseother_sideofNothing->donew_dev<-IODevice.duphaDevicedupHandle_new_devfilepathother_sideh_mb_finalizerJustr->withHandle_'"dupHandle"hr$\Handle__{haDevice=dev}->dodupHandle_devfilepathother_sideh_mb_finalizerdupHandle_::(IODevicedev,BufferedIOdev,Typeabledev)=>dev->FilePath->Maybe(MVarHandle__)->Handle__->MaybeHandleFinalizer->IOHandledupHandle_new_devfilepathother_sideh_@Handle__{..}mb_finalizer=do-- XXX wrong!letmb_codec=ifisJusthaEncoderthenJustlocaleEncodingelseNothingmkHandlenew_devfilepathhaTypeTrue{-buffered-}mb_codecNewlineMode{inputNL=haInputNL,outputNL=haOutputNL}mb_finalizerother_side-- ------------------------------------------------------------------------------- Replacing a Handle{- |
Makes the second handle a duplicate of the first handle. The second
handle will be closed first, if it is not already.
This can be used to retarget the standard Handles, for example:
> do h <- openFile "mystdout" WriteMode
> hDuplicateTo h stdout
-}hDuplicateTo::Handle->Handle->IO()hDuplicateToh1@(FileHandlepathm1)h2@(FileHandle_m2)=dowithHandle__'"hDuplicateTo"h2m2$\h2_->do_<-hClose_helph2_withHandle_'"hDuplicateTo"h1m1$\h1_->dodupHandleTopathh1Nothingh2_h1_(JusthandleFinalizer)hDuplicateToh1@(DuplexHandlepathr1w1)h2@(DuplexHandle_r2w2)=dowithHandle__'"hDuplicateTo"h2w2$\w2_->do_<-hClose_helpw2_withHandle_'"hDuplicateTo"h1w1$\w1_->dodupHandleTopathh1Nothingw2_w1_(JusthandleFinalizer)withHandle__'"hDuplicateTo"h2r2$\r2_->do_<-hClose_helpr2_withHandle_'"hDuplicateTo"h1r1$\r1_->dodupHandleTopathh1(Justw1)r2_r1_NothinghDuplicateToh1_=ioe_dupHandlesNotCompatibleh1ioe_dupHandlesNotCompatible::Handle->IOaioe_dupHandlesNotCompatibleh=ioException(IOError(Justh)IllegalOperation"hDuplicateTo""handles are incompatible"NothingNothing)dupHandleTo::FilePath->Handle->Maybe(MVarHandle__)->Handle__->Handle__->MaybeHandleFinalizer->IOHandle__dupHandleTofilepathhother_sidehto_@Handle__{haDevice=devTo,..}h_@Handle__{haDevice=dev}mb_finalizer=doflushBufferh_casecastdevToofNothing->ioe_dupHandlesNotCompatiblehJustdev'->do_<-IODevice.dup2devdev'FileHandle_m<-dupHandle_dev'filepathother_sideh_mb_finalizertakeMVarm-- ----------------------------------------------------------------------------- showing Handles.---- | 'hShow' is in the 'IO' monad, and gives more comprehensive output-- than the (pure) instance of 'Show' for 'Handle'.hShow::Handle->IOStringhShowh@(FileHandlepath_)=showHandle'pathFalsehhShowh@(DuplexHandlepath__)=showHandle'pathTruehshowHandle'::String->Bool->Handle->IOStringshowHandle'filepathis_duplexh=withHandle_"showHandle"h$\hdl_->letshowType|is_duplex=showString"duplex (read-write)"|otherwise=shows(haTypehdl_)inreturn((showChar'{'.showHdl(haTypehdl_)(showString"loc=".showStringfilepath.showChar','.showString"type=".showType.showChar','.showString"buffering=".showBufMode(unsafePerformIO(readIORef(haCharBufferhdl_)))(haBufferModehdl_).showString"}"))"")whereshowHdl::HandleType->ShowS->ShowSshowHdlhtcont=casehtofClosedHandle->showsht.showString"}"_->contshowBufMode::Buffere->BufferMode->ShowSshowBufModebufbmo=casebmoofNoBuffering->showString"none"LineBuffering->showString"line"BlockBuffering(Justn)->showString"block ".showParenTrue(showsn)BlockBufferingNothing->showString"block ".showParenTrue(showsdef)wheredef::Intdef=bufSizebuf