[project @ 2003-08-04 10:05:32 by ross]
authorross <unknown>
Mon, 4 Aug 2003 10:05:33 +0000 (10:05 +0000)
committerross <unknown>
Mon, 4 Aug 2003 10:05:33 +0000 (10:05 +0000)
docs copied from the report

GHC/Handle.hs
GHC/IO.hs
GHC/IOBase.lhs
System/Directory.hs
System/IO.hs

index d5cada3..d51e138 100644 (file)
@@ -590,6 +590,7 @@ fd_stdin  = 0 :: FD
 fd_stdout = 1 :: FD
 fd_stderr = 2 :: FD
 
+-- | A handle managing input from the Haskell program's standard input channel.
 stdin :: Handle
 stdin = unsafePerformIO $ do
    -- ToDo: acquire lock
@@ -597,6 +598,7 @@ stdin = unsafePerformIO $ do
    (buf, bmode) <- getBuffer fd_stdin ReadBuffer
    mkStdHandle fd_stdin "<stdin>" ReadHandle buf bmode
 
+-- | A handle managing output to the Haskell program's standard output channel.
 stdout :: Handle
 stdout = unsafePerformIO $ do
    -- ToDo: acquire lock
@@ -606,6 +608,7 @@ stdout = unsafePerformIO $ do
    (buf, bmode) <- getBuffer fd_stdout WriteBuffer
    mkStdHandle fd_stdout "<stdout>" WriteHandle buf bmode
 
+-- | A handle managing output to the Haskell program's standard error channel.
 stderr :: Handle
 stderr = unsafePerformIO $ do
     -- ToDo: acquire lock
@@ -618,41 +621,48 @@ stderr = unsafePerformIO $ do
 -- ---------------------------------------------------------------------------
 -- Opening and Closing Files
 
-{-
-Computation `openFile file mode' allocates and returns a new, open
-handle to manage the file `file'.  It manages input if `mode'
-is `ReadMode', output if `mode' is `WriteMode' or `AppendMode',
-and both input and output if mode is `ReadWriteMode'.
-
-If the file does not exist and it is opened for output, it should be
-created as a new file.  If `mode' is `WriteMode' and the file
-already exists, then it should be truncated to zero length.  The
-handle is positioned at the end of the file if `mode' is
-`AppendMode', and otherwise at the beginning (in which case its
-internal position is 0).
-
-Implementations should enforce, locally to the Haskell process,
-multiple-reader single-writer locking on files, which is to say that
-there may either be many handles on the same file which manage input,
-or just one handle on the file which manages output.  If any open or
-semi-closed handle is managing a file for output, no new handle can be
-allocated for that file.  If any open or semi-closed handle is
-managing a file for input, new handles can only be allocated if they
-do not manage output.
-
-Two files are the same if they have the same absolute name.  An
-implementation is free to impose stricter conditions.
--}
-
 addFilePathToIOError fun fp (IOError h iot _ str _)
   = IOError h iot fun str (Just fp)
 
+-- | Computation 'openFile' @file mode@ allocates and returns a new, open
+-- handle to manage the file @file@.  It manages input if @mode@
+-- is 'ReadMode', output if @mode@ is 'WriteMode' or 'AppendMode',
+-- and both input and output if mode is 'ReadWriteMode'.
+--
+-- If the file does not exist and it is opened for output, it should be
+-- created as a new file.  If @mode@ is 'WriteMode' and the file
+-- already exists, then it should be truncated to zero length.
+-- Some operating systems delete empty files, so there is no guarantee
+-- that the file will exist following an 'openFile' with @mode@
+-- 'WriteMode' unless it is subsequently written to successfully.
+-- The handle is positioned at the end of the file if `mode' is
+-- `AppendMode', and otherwise at the beginning (in which case its
+-- internal position is 0).
+-- The initial buffer mode is implementation-dependent.
+--
+-- This operation may fail with:
+--
+--  * 'isAlreadyInUseError' if the file is already open and cannot be reopened;
+--
+--  * 'isDoesNotExistError' if the file does not exist; or
+--
+--  * 'isPermissionError' if the user does not have permission to open the file.
+
 openFile :: FilePath -> IOMode -> IO Handle
 openFile fp im = 
   catch 
     (openFile' fp im dEFAULT_OPEN_IN_BINARY_MODE)
     (\e -> ioError (addFilePathToIOError "openFile" fp e))
 
+-- | Like 'openFile', but open the file in binary mode.
+-- On Windows, reading a file in text mode (which is the default)
+-- will translate CRLF to LF, and writing will translate LF to CRLF.
+-- This is usually what you want with text files.  With binary files
+-- this is undesirable; also, as usual under Microsoft operating systems,
+-- text mode treats control-Z as EOF.  Binary mode turns off all special
+-- treatment of end-of-line and end-of-file characters.
+-- (See also 'hSetBinaryMode'.)
+
 openBinaryFile :: FilePath -> IOMode -> IO Handle
 openBinaryFile fp m =
   catch
@@ -827,12 +837,14 @@ initBufferState _            = WriteBuffer
 -- ---------------------------------------------------------------------------
 -- Closing a handle
 
--- Computation `hClose hdl' makes handle `hdl' closed.  Before the
--- computation finishes, any items buffered for output and not already
--- sent to the operating system are flushed as for `hFlush'.
-
--- For a duplex handle, we close&flush the write side, and just close
--- the read side.
+-- | 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 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 ()
 hClose h@(FileHandle _ m)     = hClose' h m
@@ -885,9 +897,8 @@ hClose_handle_ handle_ = do
 -----------------------------------------------------------------------------
 -- Detecting the size of a file
 
--- For a handle `hdl' which attached to a physical file, `hFileSize
--- hdl' returns the size of `hdl' in terms of the number of items
--- which can be read from `hdl'.
+-- | For a handle @hdl@ which attached to a physical file,
+-- 'hFileSize' @hdl@ returns the size of that file in 8-bit bytes.
 
 hFileSize :: Handle -> IO Integer
 hFileSize handle =
@@ -905,10 +916,10 @@ hFileSize handle =
 -- ---------------------------------------------------------------------------
 -- 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'.
+-- | 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'.
 
 hIsEOF :: Handle -> IO Bool
 hIsEOF handle =
@@ -916,15 +927,22 @@ hIsEOF handle =
      (do hLookAhead handle; return False)
      (\e -> if isEOFError e then return True else ioError e)
 
+-- | The computation 'isEOF' is identical to 'hIsEOF',
+-- except that it works only on 'stdin'.
+
 isEOF :: IO Bool
 isEOF = hIsEOF stdin
 
 -- ---------------------------------------------------------------------------
 -- Looking ahead
 
--- hLookahead returns the next character from the handle without
--- removing it from the input buffer, blocking until a character is
--- available.
+-- | 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 -> IO Char
 hLookAhead handle = do
@@ -951,23 +969,21 @@ hLookAhead handle = do
 -- block-buffering or no-buffering.  See GHC.IOBase for definition and
 -- further explanation of what the type represent.
 
--- Computation `hSetBuffering hdl mode' sets the mode of buffering for
+-- | Computation 'hSetBuffering' @hdl mode@ sets the mode of buffering for
 -- handle hdl on subsequent reads and writes.
 --
---   * If mode is LineBuffering, line-buffering should be enabled if possible.
+-- If the buffer mode is changed from 'BlockBuffering' or
+-- 'LineBuffering' to 'NoBuffering', then
 --
---   * If mode is `BlockBuffering size', then block-buffering
---     should be enabled if possible.  The size of the buffer is n items
---     if size is `Just n' and is otherwise implementation-dependent.
+--  * if @hdl@ is writable, the buffer is flushed as for 'hFlush';
 --
---   * If mode is NoBuffering, then buffering is disabled if possible.
-
--- If the buffer mode is changed from BlockBuffering or
--- LineBuffering to NoBuffering, then any items in the output
--- buffer are written to the device, and any items in the input buffer
--- are discarded.  The default buffering mode when a handle is opened
--- is implementation-dependent and may depend on the object which is
--- attached to that handle.
+--  * 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 ()
 hSetBuffering handle mode =
@@ -1020,9 +1036,16 @@ hSetBuffering handle mode =
 -- -----------------------------------------------------------------------------
 -- hFlush
 
--- The action `hFlush hdl' causes any items buffered for output
--- in handle `hdl' to be sent immediately to the operating
--- system.
+-- | 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 () 
 hFlush handle =
@@ -1052,40 +1075,38 @@ instance Show HandlePosn where
   -- that reports the position back via (merely) an Int.
 type HandlePosition = Integer
 
--- Computation `hGetPosn hdl' returns the current I/O position of
--- `hdl' as an abstract position.  Computation `hSetPosn p' sets the
--- position of `hdl' to a previously obtained position `p'.
+-- | Computation 'hGetPosn' @hdl@ returns the current I\/O position of
+-- @hdl@ as a value of the abstract type 'HandlePosn'.
 
 hGetPosn :: Handle -> IO HandlePosn
 hGetPosn handle = do
     posn <- hTell handle
     return (HandlePosn handle posn)
 
+-- | 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 (HandlePosn h i) = hSeek h AbsoluteSeek i
 
 -- ---------------------------------------------------------------------------
 -- hSeek
 
-{-
-The action `hSeek hdl mode i' sets the position of handle
-`hdl' depending on `mode'.  If `mode' is
-
- * AbsoluteSeek - The position of `hdl' is set to `i'.
- * RelativeSeek - The position of `hdl' is set to offset `i' from
-                  the current position.
- * SeekFromEnd  - The position of `hdl' is set to offset `i' from
-                  the end of the file.
-
-Some handles may not be seekable (see `hIsSeekable'), or only
-support a subset of the possible positioning operations (e.g. it may
-only be possible to seek to the end of a tape, or to a positive
-offset from the beginning or current position).
+-- | A mode that determines the effect of 'hSeek' @hdl mode i@, as follows:
+data SeekMode
+  = AbsoluteSeek       -- ^ the position of @hdl@ is set to @i@.
+  | RelativeSeek       -- ^ the position of @hdl@ is set to offset @i@
+                       -- from the current position.
+  | SeekFromEnd                -- ^ the position of @hdl@ is set to offset @i@
+                       -- from the end of the file.
+    deriving (Eq, Ord, Ix, Enum, Read, Show)
 
-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. 
-
-Note: 
+{- Note: 
  - when seeking using `SeekFromEnd', positive offsets (>=0) means
    seeking at or past EOF.
 
@@ -1094,8 +1115,23 @@ Note:
    clear here.
 -}
 
-data SeekMode    =  AbsoluteSeek | RelativeSeek | SeekFromEnd
-                    deriving (Eq, Ord, Ix, Enum, Read, Show)
+-- | 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:
+--
+--  * 'isPermissionError' if a system resource limit would be exceeded.
 
 hSeek :: Handle -> SeekMode -> Integer -> IO () 
 hSeek handle mode offset =
@@ -1211,7 +1247,8 @@ hIsWritable handle =
       SemiClosedHandle            -> ioe_closedHandle
       htype               -> return (isWritableHandleType htype)
 
--- Querying how a handle buffers its data:
+-- | Computation 'hGetBuffering' @hdl@ returns the current buffering mode
+-- for @hdl@.
 
 hGetBuffering :: Handle -> IO BufferMode
 hGetBuffering handle = 
@@ -1276,14 +1313,9 @@ hIsTerminalDevice handle = do
 -- -----------------------------------------------------------------------------
 -- hSetBinaryMode
 
--- | On Windows, reading a file in text mode (which is the default) will
--- translate CRLF to LF, and writing will translate LF to CRLF. This
--- is usually what you want with text files. With binary files this is
--- undesirable; also, as usual under Microsoft operating systems, text
--- mode treats control-Z as EOF.  Setting binary mode using
--- 'hSetBinaryMode' turns off all special treatment of end-of-line and
--- end-of-file characters.
---
+-- | Select binary mode ('True') or text mode ('False') on a open handle.
+-- (GHC only; see also 'openBinaryFile'.)
+
 hSetBinaryMode :: Handle -> Bool -> IO ()
 hSetBinaryMode handle bin =
   withAllHandles__ "hSetBinaryMode" handle $ \ handle_ ->
@@ -1359,8 +1391,8 @@ hDuplicateTo h1 _ =
 -- ---------------------------------------------------------------------------
 -- showing Handles.
 --
--- hShow is in the IO monad, and gives more comprehensive output
--- than the (pure) instance of Show for Handle.
+-- | 'hShow' is in the 'IO' monad, and gives more comprehensive output
+-- than the (pure) instance of 'Show' for 'Handle'.
 
 hShow :: Handle -> IO String
 hShow h@(FileHandle path _) = showHandle' path False h
index 914a55a..1dee43a 100644 (file)
--- a/GHC/IO.hs
+++ b/GHC/IO.hs
@@ -49,14 +49,20 @@ import GHC.Conc
 -- ---------------------------------------------------------------------------
 -- Simple input operations
 
--- Computation "hReady hdl" indicates whether at least
--- one item is available for input from handle "hdl".
-
 -- If hWaitForInput finds anything in the Handle's buffer, it
 -- immediately returns.  If not, it tries to read from the underlying
 -- OS handle. Notice that for buffered Handles connected to terminals
 -- this means waiting until a complete line is available.
 
+-- | Computation 'hWaitForInput' @hdl t@
+-- waits until input is available on handle @hdl@.
+-- It returns 'True' as soon as input is available on @hdl@,
+-- or 'False' if no input is available within @t@ milliseconds.
+--
+-- This operation may fail with:
+--
+--  * 'isEOFError' if the end of file has been reached.
+
 hWaitForInput :: Handle -> Int -> IO Bool
 hWaitForInput h msecs = do
   wantReadableHandle "hWaitForInput" h $ \ handle_ -> do
@@ -77,8 +83,12 @@ foreign import ccall unsafe "inputReady"
 -- ---------------------------------------------------------------------------
 -- hGetChar
 
--- hGetChar reads the next character from a handle,
--- blocking until a character is available.
+-- | Computation 'hGetChar' @hdl@ reads a character from the file or
+-- channel managed by @hdl@, blocking until a character is available.
+--
+-- This operation may fail with:
+--
+--  * 'isEOFError' if the end of file has been reached.
 
 hGetChar :: Handle -> IO Char
 hGetChar handle =
@@ -121,12 +131,21 @@ hGetcBuffered fd ref buf@Buffer{ bufBuf=b, bufRPtr=r, bufWPtr=w }
 -- ---------------------------------------------------------------------------
 -- hGetLine
 
--- If EOF is reached before EOL is encountered, ignore the EOF and
--- return the partial line. Next attempt at calling hGetLine on the
--- handle will yield an EOF IO exception though.
-
 -- ToDo: the unbuffered case is wrong: it doesn't lock the handle for
 -- the duration.
+
+-- | Computation 'hGetLine' @hdl@ reads a line from the file or
+-- channel managed by @hdl@.
+--
+-- This operation may fail with:
+--
+--  * 'isEOFError' if the end of file is encountered when reading
+--    the /first/ character of the line.
+--
+-- If 'hGetLine' encounters end-of-file at any other point while reading
+-- in a line, it is treated as a line terminator and the (partial)
+-- line is returned.
+
 hGetLine :: Handle -> IO String
 hGetLine h = do
   m <- wantReadableHandle "hGetLine" h $ \ handle_ -> do
@@ -240,13 +259,38 @@ hGetLineUnBuffered h = do
 -- -----------------------------------------------------------------------------
 -- hGetContents
 
--- hGetContents returns the list of characters corresponding to the
--- unread portion of the channel or file managed by the handle, which
--- is made semi-closed.
-
 -- hGetContents on a DuplexHandle only affects the read side: you can
 -- carry on writing to it afterwards.
 
+-- | Computation 'hGetContents' @hdl@ returns the list of characters
+-- corresponding to the unread portion of the channel or file managed
+-- by @hdl@, which is put into an intermediate state, /semi-closed/.
+-- In this state, @hdl@ is effectively closed,
+-- but items are read from @hdl@ on demand and accumulated in a special
+-- list returned by 'hGetContents' @hdl@.
+--
+-- Any operation that fails because a handle is closed,
+-- also fails if a handle is semi-closed.  The only exception is 'hClose'.
+-- A semi-closed handle becomes closed:
+--
+--  * if 'hClose' is applied to it;
+--
+--  * if an I\/O error occurs when reading an item from the handle;
+--
+--  * or once the entire contents of the handle has been read.
+--
+-- Once a semi-closed handle becomes closed, the contents of the
+-- associated list becomes fixed.  The contents of this final list is
+-- only partially specified: it will contain at least all the items of
+-- the stream that were evaluated prior to the handle becoming closed.
+--
+-- Any I\/O errors encountered while a handle is semi-closed are simply
+-- discarded.
+--
+-- This operation may fail with:
+--
+--  * 'isEOFError' if the end of file has been reached.
+
 hGetContents :: Handle -> IO String
 hGetContents handle = 
     withHandle "hGetContents" handle $ \handle_ ->
@@ -331,9 +375,15 @@ unpackAcc buf (I# r) (I# len) acc = IO $ \s -> unpack acc (len -# 1#) s
 -- ---------------------------------------------------------------------------
 -- hPutChar
 
--- `hPutChar hdl ch' writes the character `ch' to the file or channel
--- managed by `hdl'.  Characters may be buffered if buffering is
--- enabled for `hdl'.
+-- | Computation 'hPutChar' @hdl ch@ writes the character @ch@ to the
+-- file or channel managed by @hdl@.  Characters may be buffered if
+-- buffering is enabled for @hdl@.
+--
+-- This operation may fail with:
+--
+--  * 'isFullError' if the device is full; or
+--
+--  * 'isPermissionError' if another system resource limit would be exceeded.
 
 hPutChar :: Handle -> Char -> IO ()
 hPutChar handle c = 
@@ -369,9 +419,6 @@ hPutChars handle (c:cs) = hPutChar handle c >> hPutChars handle cs
 -- ---------------------------------------------------------------------------
 -- hPutStr
 
--- `hPutStr hdl s' writes the string `s' to the file or
--- hannel managed by `hdl', buffering the output if needs be.
-
 -- We go to some trouble to avoid keeping the handle locked while we're
 -- evaluating the string argument to hPutStr, in case doing so triggers another
 -- I/O operation on the same handle which would lead to deadlock.  The classic
@@ -389,6 +436,15 @@ hPutChars handle (c:cs) = hPutChar handle c >> hPutChars handle cs
 -- maybe just swapping the buffers over (if the handle's buffer was
 -- empty).  See commitBuffer below.
 
+-- | Computation 'hPutStr' @hdl s@ writes the string
+-- @s@ to the file or channel managed by @hdl@.
+--
+-- This operation may fail with:
+--
+--  * 'isFullError' if the device is full; or
+--
+--  * 'isPermissionError' if another system resource limit would be exceeded.
+
 hPutStr :: Handle -> String -> IO ()
 hPutStr handle str = do
     buffer_mode <- wantWritableHandle "hPutStr" handle 
@@ -573,36 +629,19 @@ commitBuffer' hdl raw sz@(I# _) count@(I# _) flush release
 -- ---------------------------------------------------------------------------
 -- Reading/writing sequences of bytes.
 
-{-
-Semantics of hGetBuf:
-
-   - hGetBuf reads data into the buffer until either
-
-       (a) EOF is reached
-       (b) the buffer is full
-     
-     It returns the amount of data actually read.  This may
-     be zero in case (a).  hGetBuf never raises
-     an EOF exception, it always returns zero instead.
-
-     If the handle is a pipe or socket, and the writing end
-     is closed, hGetBuf will behave as for condition (a).
-
-Semantics of hPutBuf:
-
-    - hPutBuf writes data from the buffer to the handle 
-      until the buffer is empty.  It returns ().
-
-      If the handle is a pipe or socket, and the reading end is
-      closed, hPutBuf will raise a ResourceVanished exception.
-      (If this is a POSIX system, and the program has not 
-      asked to ignore SIGPIPE, then a SIGPIPE may be delivered
-      instead, whose default action is to terminate the program).
--}
-
 -- ---------------------------------------------------------------------------
 -- hPutBuf
 
+-- | 'hPutBuf' @hdl buf count@ writes @count@ 8-bit bytes from the
+-- buffer @buf@ to the handle @hdl@.  It returns ().
+--
+-- This operation may fail with:
+--
+--  * 'ResourceVanished' if the handle is a pipe or socket, and the
+--    reading end is closed.  (If this is a POSIX system, and the program
+--    has not asked to ignore SIGPIPE, then a SIGPIPE may be delivered
+--    instead, whose default action is to terminate the program).
+
 hPutBuf :: Handle                      -- handle to write to
        -> Ptr a                        -- address of buffer
        -> Int                          -- number of bytes of data in buffer
@@ -646,6 +685,18 @@ writeChunk fd is_stream ptr bytes = loop 0 bytes
 -- ---------------------------------------------------------------------------
 -- hGetBuf
 
+-- | 'hGetBuf' @hdl buf count@ reads data from the handle @hdl@
+-- into the buffer @buf@ until either EOF is reached or
+-- @count@ 8-bit bytes have been read.
+-- It returns the number of bytes actually read.  This may be zero if
+-- EOF was reached before any data was read (or if @count@ is zero).
+--
+-- 'hGetBuf' never raises an EOF exception, instead it returns a value
+-- smaller than @count@.
+--
+-- If the handle is a pipe or socket, and the writing end
+-- is closed, 'hGetBuf' will behave as if EOF was reached.
+
 hGetBuf :: Handle -> Ptr a -> Int -> IO Int
 hGetBuf handle ptr count
   | count == 0 = return 0
index cbad7db..1870146 100644 (file)
@@ -220,6 +220,34 @@ instance Eq (MVar a) where
 -- Note: when a Handle is garbage collected, we want to flush its buffer
 -- and close the OS file handle, so as to free up a (precious) resource.
 
+-- | Haskell defines operations to read and write characters from and to files,
+-- represented by values of type @Handle@.  Each value of this type is a
+-- /handle/: a record used by the Haskell run-time system to /manage/ I\/O
+-- with file system objects.  A handle has at least the following properties:
+-- 
+--  * whether it manages input or output or both;
+--
+--  * whether it is /open/, /closed/ or /semi-closed/;
+--
+--  * whether the object is seekable;
+--
+--  * whether buffering is disabled, or enabled on a line or block basis;
+--
+--  * a buffer (whose length may be zero).
+--
+-- Most handles will also have a current I\/O position indicating where the next
+-- input or output operation will occur.  A handle is /readable/ if it
+-- manages only input or both input and output; likewise, it is /writable/ if
+-- it manages only output or both input and output.  A handle is /open/ when
+-- first allocated.
+-- Once it is closed it can no longer be used for either input or output,
+-- though an implementation cannot re-use its storage while references
+-- remain to it.  Handles are in the 'Show' and 'Eq' classes.  The string
+-- produced by showing a handle is system dependent; it should include
+-- enough information to identify the handle for debugging.  A handle is
+-- equal according to '==' only to itself; no attempt
+-- is made to compare the internal state of different handles for equality.
+
 data Handle 
   = FileHandle                         -- A normal handle to a file
        FilePath                        -- the file (invariant)
@@ -340,53 +368,63 @@ isWritableHandleType WriteHandle     = True
 isWritableHandleType ReadWriteHandle = True
 isWritableHandleType _              = False
 
--- File names are specified using @FilePath@, a OS-dependent
--- string that (hopefully, I guess) maps to an accessible file/object.
+-- | File and directory names are values of type 'String', whose precise
+-- meaning is operating system dependent. Files can be opened, yielding a
+-- handle which can then be used to operate on the contents of that file.
 
 type FilePath = String
 
 -- ---------------------------------------------------------------------------
 -- Buffering modes
 
--- Three kinds of buffering are supported: line-buffering, 
+-- | Three kinds of buffering are supported: line-buffering, 
 -- block-buffering or no-buffering.  These modes have the following
--- effects. For output, items are written out from the internal
--- buffer according to the buffer mode:
+-- effects. For output, items are written out, or /flushed/,
+-- from the internal buffer according to the buffer mode:
 --
--- o line-buffering  the entire output buffer is written
---   out whenever a newline is output, the output buffer overflows, 
---   a flush is issued, or the handle is closed.
+--  * /line-buffering/: the entire output buffer is flushed
+--    whenever a newline is output, the buffer overflows, 
+--    a 'System.IO.hFlush' is issued, or the handle is closed.
 --
--- o block-buffering the entire output buffer is written out whenever 
---   it overflows, a flush is issued, or the handle
---   is closed.
+--  * /block-buffering/: the entire buffer is written out whenever it
+--    overflows, a 'System.IO.hFlush' is issued, or the handle is closed.
 --
--- o no-buffering output is written immediately, and never stored
---   in the output buffer.
+--  * /no-buffering/: output is written immediately, and never stored
+--    in the buffer.
 --
+-- An implementation is free to flush the buffer more frequently,
+-- but not less frequently, than specified above.
 -- The output buffer is emptied as soon as it has been written out.
-
+--
 -- Similarly, input occurs according to the buffer mode for handle {\em hdl}.
-
--- o line-buffering when the input buffer for the handle is not empty,
---   the next item is obtained from the buffer;
---   otherwise, when the input buffer is empty,
---   characters up to and including the next newline
---   character are read into the buffer.  No characters
---   are available until the newline character is
---   available.
 --
--- o block-buffering when the input buffer for the handle becomes empty,
---   the next block of data is read into this buffer.
+--  * /line-buffering/: when the buffer for the handle is not empty,
+--    the next item is obtained from the buffer; otherwise, when the
+--    buffer is empty, characters up to and including the next newline
+--    character are read into the buffer.  No characters are available
+--    until the newline character is available or the buffer is full.
 --
--- o no-buffering the next input item is read and returned.
-
+--  * /block-buffering/: when the buffer for the handle becomes empty,
+--    the next block of data is read into the buffer.
+--
+--  * /no-buffering/: the next input item is read and returned.
+--    The 'hLookAhead' operation implies that even a no-buffered handle
+--    may require a one-character buffer.
+--
+-- The default buffering mode when a handle is opened is
+-- implementation-dependent and may depend on the file system object
+-- which is attached to that handle.
 -- For most implementations, physical files will normally be block-buffered 
--- and terminals will normally be line-buffered. (the IO interface provides
--- operations for changing the default buffering of a handle tho.)
+-- and terminals will normally be line-buffered.
 
 data BufferMode  
- = NoBuffering | LineBuffering | BlockBuffering (Maybe Int)
+ = NoBuffering -- ^ buffering is disabled if possible.
+ | LineBuffering
+               -- ^ line-buffering should be enabled if possible.
+ | BlockBuffering (Maybe Int)
+               -- ^ block-buffering should be enabled if possible.
+               -- The size of the buffer is @n@ items if the argument
+               -- is 'Just' @n@ and is otherwise implementation-dependent.
    deriving (Eq, Ord, Read, Show)
 
 -- ---------------------------------------------------------------------------
index abccc68..872334a 100644 (file)
 
 module System.Directory 
    ( 
-     -- $intro
-
-     -- * Permissions
-
-     -- $permissions
-
-     Permissions(
-       Permissions,
-       readable,               -- :: Permissions -> Bool 
-       writable,               -- :: Permissions -> Bool
-       executable,             -- :: Permissions -> Bool
-       searchable              -- :: Permissions -> Bool
-     )
+    -- $intro
 
     -- * Actions on directories
-    , createDirectory          -- :: FilePath -> IO ()
+      createDirectory          -- :: FilePath -> IO ()
     , removeDirectory          -- :: FilePath -> IO ()
     , renameDirectory          -- :: FilePath -> FilePath -> IO ()
 
@@ -45,7 +33,17 @@ module System.Directory
     , doesFileExist            -- :: FilePath -> IO Bool
     , doesDirectoryExist        -- :: FilePath -> IO Bool
 
-    -- * Setting and retrieving permissions
+    -- * Permissions
+
+    -- $permissions
+
+    , Permissions(
+       Permissions,
+       readable,               -- :: Permissions -> Bool
+       writable,               -- :: Permissions -> Bool
+       executable,             -- :: Permissions -> Bool
+       searchable              -- :: Permissions -> Bool
+      )
 
     , getPermissions            -- :: FilePath -> IO Permissions
     , setPermissions           -- :: FilePath -> Permissions -> IO ()
@@ -120,6 +118,18 @@ data Permissions
     executable, searchable :: Bool 
    } deriving (Eq, Ord, Read, Show)
 
+{- |The 'getPermissions' operation returns the
+permissions for the file or directory.
+
+The operation may fail with:
+
+* 'isPermissionError' if the user is not permitted to access
+  the permissions; or
+
+* 'isDoesNotExistError' if the file or directory does not exist.
+
+-}
+
 getPermissions :: FilePath -> IO Permissions
 getPermissions name = do
   withCString name $ \s -> do
@@ -137,6 +147,18 @@ getPermissions name = do
     }
    )
 
+{- |The 'setPermissions' operation sets the
+permissions for the file or directory.
+
+The operation may fail with:
+
+* 'isPermissionError' if the user is not permitted to set
+  the permissions; or
+
+* 'isDoesNotExistError' if the file or directory does not exist.
+
+-}
+
 setPermissions :: FilePath -> Permissions -> IO ()
 setPermissions name (Permissions r w e s) = do
     let
@@ -549,10 +571,8 @@ setCurrentDirectory path = do
        throwErrnoIfMinus1Retry_ "setCurrentDirectory" (c_chdir s)
        -- ToDo: add path to error
 
-{- |To clarify, 'doesDirectoryExist' returns 'True' if a file system object
-exist, and it's a directory. 'doesFileExist' returns 'True' if the file
-system object exist, but it's not a directory (i.e., for every other 
-file system object that is not a directory.) 
+{- |The operation 'doesDirectoryExist' returns 'True' if the argument file
+exists and is a directory, and 'False' otherwise.
 -}
 
 doesDirectoryExist :: FilePath -> IO Bool
@@ -561,12 +581,28 @@ doesDirectoryExist name =
    (withFileStatus name $ \st -> isDirectory st)
    (\ _ -> return False)
 
+{- |The operation 'doesFileExist' returns 'True'
+if the argument file exists and is not a directory, and 'False' otherwise.
+-}
+
 doesFileExist :: FilePath -> IO Bool
 doesFileExist name = do 
  catch
    (withFileStatus name $ \st -> do b <- isDirectory st; return (not b))
    (\ _ -> return False)
 
+{- |The 'getModificationTime' operation returns the
+clock time at which the file or directory was last modified.
+
+The operation may fail with:
+
+* 'isPermissionError' if the user is not permitted to access
+  the modification time; or
+
+* 'isDoesNotExistError' if the file or directory does not exist.
+
+-}
+
 getModificationTime :: FilePath -> IO ClockTime
 getModificationTime name =
  withFileStatus name $ \ st ->
index f936a56..eee562c 100644 (file)
 -----------------------------------------------------------------------------
 
 module System.IO (
+    -- * The IO monad
+
+    IO,                               -- instance MonadFix
+    fixIO,                    -- :: (a -> IO a) -> IO a
+
+    -- * Files and handles
+
+    FilePath,                 -- :: String
+
     Handle,            -- abstract, instance of: Eq, Show.
-    HandlePosn(..),     -- abstract, instance of: Eq, Show.
 
-    IOMode(ReadMode,WriteMode,AppendMode,ReadWriteMode),
-    BufferMode(NoBuffering,LineBuffering,BlockBuffering),
-    SeekMode(AbsoluteSeek,RelativeSeek,SeekFromEnd),
+    -- ** Standard handles
+
+    -- | Three handles are allocated during program initialisation,
+    -- and are initially open.
 
     stdin, stdout, stderr,   -- :: Handle
 
+    -- * Opening and closing files
+
+    -- ** Opening files
+
     openFile,                 -- :: FilePath -> IOMode -> IO Handle
-#if !defined(__NHC__)
-    openBinaryFile,           -- :: FilePath -> IOMode -> IO Handle
-#endif
+    IOMode(ReadMode,WriteMode,AppendMode,ReadWriteMode),
+
+    -- ** Closing files
+
     hClose,                   -- :: Handle -> IO ()
+
+    -- ** Special cases
+
+    -- | These functions are also exported by the "Prelude".
+
+    readFile,                 -- :: FilePath -> IO String
+    writeFile,                -- :: FilePath -> String -> IO ()
+    appendFile,                       -- :: FilePath -> String -> IO ()
+
+    -- ** File locking
+
+    -- $locking
+
+    -- * Operations on handles
+
+    -- ** Determining the size of a file
+
     hFileSize,                -- :: Handle -> IO Integer
+
+    -- ** Detecting the end of input
+
     hIsEOF,                   -- :: Handle -> IO Bool
     isEOF,                    -- :: IO Bool
 
+    -- ** Buffering operations
+
+    BufferMode(NoBuffering,LineBuffering,BlockBuffering),
     hSetBuffering,            -- :: Handle -> BufferMode -> IO ()
     hGetBuffering,            -- :: Handle -> IO BufferMode
-#if !defined(__HUGS__) && !defined(__NHC__)
-    hSetBinaryMode,           -- :: Handle -> Bool -> IO ()
-#endif
     hFlush,                   -- :: Handle -> IO ()
+
+    -- ** Repositioning handles
+
     hGetPosn,                 -- :: Handle -> IO HandlePosn
     hSetPosn,                 -- :: HandlePosn -> IO ()
+    HandlePosn,                -- abstract, instance of: Eq, Show.
+
     hSeek,                    -- :: Handle -> SeekMode -> Integer -> IO ()
+    SeekMode(AbsoluteSeek,RelativeSeek,SeekFromEnd),
 #if !defined(__NHC__)
     hTell,                    -- :: Handle -> IO Integer
 #endif
+
+    -- ** Handle properties
+
+    hIsOpen, hIsClosed,        -- :: Handle -> IO Bool
+    hIsReadable, hIsWritable,  -- :: Handle -> IO Bool
+    hIsSeekable,               -- :: Handle -> IO Bool
+
+    -- ** Terminal operations
+
+#if !defined(__HUGS__) && !defined(__NHC__)
+    hIsTerminalDevice,         -- :: Handle -> IO Bool
+
+    hSetEcho,                  -- :: Handle -> Bool -> IO ()
+    hGetEcho,                  -- :: Handle -> IO Bool
+#endif
+
+    -- ** Showing handle state
+
+#ifdef __GLASGOW_HASKELL__
+    hShow,                     -- :: Handle -> IO String
+#endif
+
+    -- * Text input and output
+
+    -- ** Text input
+
     hWaitForInput,            -- :: Handle -> Int -> IO Bool
     hReady,                   -- :: Handle -> IO Bool
     hGetChar,                 -- :: Handle -> IO Char
     hGetLine,                 -- :: Handle -> IO [Char]
     hLookAhead,                       -- :: Handle -> IO Char
     hGetContents,             -- :: Handle -> IO [Char]
+
+    -- ** Text output
+
     hPutChar,                 -- :: Handle -> Char -> IO ()
     hPutStr,                  -- :: Handle -> [Char] -> IO ()
     hPutStrLn,                -- :: Handle -> [Char] -> IO ()
     hPrint,                   -- :: Show a => Handle -> a -> IO ()
-    hIsOpen, hIsClosed,        -- :: Handle -> IO Bool
-    hIsReadable, hIsWritable,  -- :: Handle -> IO Bool
-    hIsSeekable,               -- :: Handle -> IO Bool
 
-    isAlreadyExistsError, isDoesNotExistError,  -- :: IOError -> Bool
-    isAlreadyInUseError, isFullError, 
-    isEOFError, isIllegalOperation, 
-    isPermissionError, isUserError, 
+    -- ** Special cases for standard input and output
 
-    ioeGetErrorString,        -- :: IOError -> String
-    ioeGetHandle,             -- :: IOError -> Maybe Handle
-    ioeGetFileName,           -- :: IOError -> Maybe FilePath
+    -- | These functions are also exported by the "Prelude".
 
-    try,                      -- :: IO a -> IO (Either IOError a)
-
-    -- re-exports of Prelude names
-    IO,                               -- instance MonadFix
-    FilePath,                 -- :: String
-    IOError,
-    ioError,                  -- :: IOError -> IO a
-    userError,                -- :: String  -> IOError
-    catch,                    -- :: IO a    -> (IOError -> IO a) -> IO a
     interact,                 -- :: (String -> String) -> IO ()
-
     putChar,                  -- :: Char   -> IO ()
     putStr,                   -- :: String -> IO () 
     putStrLn,                 -- :: String -> IO ()
@@ -85,29 +136,22 @@ module System.IO (
     getChar,                  -- :: IO Char
     getLine,                  -- :: IO String
     getContents,              -- :: IO String
-    readFile,                 -- :: FilePath -> IO String
-    writeFile,                -- :: FilePath -> String -> IO ()
-    appendFile,                       -- :: FilePath -> String -> IO ()
     readIO,                   -- :: Read a => String -> IO a
     readLn,                   -- :: Read a => IO a
 
-#if !defined(__HUGS__) && !defined(__NHC__)
-    hPutBuf,                  -- :: Handle -> Ptr a -> Int -> IO ()
-    hGetBuf,                  -- :: Handle -> Ptr a -> Int -> IO Int
+    -- * Binary input and output
+
+#if !defined(__NHC__)
+    openBinaryFile,           -- :: FilePath -> IOMode -> IO Handle
 #endif
-    fixIO,                    -- :: (a -> IO a) -> IO a
 
 #if !defined(__HUGS__) && !defined(__NHC__)
-    hSetEcho,                  -- :: Handle -> Bool -> IO ()
-    hGetEcho,                  -- :: Handle -> IO Bool
-
-    hIsTerminalDevice,         -- :: Handle -> IO Bool
+    hSetBinaryMode,           -- :: Handle -> Bool -> IO ()
+    hPutBuf,                  -- :: Handle -> Ptr a -> Int -> IO ()
+    hGetBuf,                  -- :: Handle -> Ptr a -> Int -> IO Int
 #endif
 
-#ifdef __GLASGOW_HASKELL__
-    hShow,                     -- :: Handle -> IO String
-#endif
+    module System.IO.Error,
   ) where
 
 #ifdef __GLASGOW_HASKELL__
@@ -156,77 +200,137 @@ import IO
   , hIsOpen, hIsClosed        -- :: Handle -> IO Bool
   , hIsReadable, hIsWritable  -- :: Handle -> IO Bool
   , hIsSeekable               -- :: Handle -> IO Bool
-  , isAlreadyExistsError, isDoesNotExistError  -- :: IOError -> Bool
-  , isAlreadyInUseError, isFullError
-  , isEOFError, isIllegalOperation
-  , isPermissionError, isUserError
-  , ioeGetErrorString         -- :: IOError -> String
-  , ioeGetHandle              -- :: IOError -> Maybe Handle
-  , ioeGetFileName            -- :: IOError -> Maybe FilePath
 
   , IO ()
   , FilePath                  -- :: String
-  , IOError
-  , ioError                   -- :: IOError -> IO a
-  , userError                 -- :: String  -> IOError
-  , catch                     -- :: IO a    -> (IOError -> IO a) -> IO a
   )
 import NHC.Internal (unsafePerformIO)
 #endif
 
-import System.IO.Error
+import System.IO.Error (
+    isAlreadyExistsError, isDoesNotExistError,  -- :: IOError -> Bool
+    isAlreadyInUseError, isFullError, 
+    isEOFError, isIllegalOperation, 
+    isPermissionError, isUserError, 
+    ioeGetErrorString,         -- :: IOError -> String
+    ioeGetHandle,              -- :: IOError -> Maybe Handle
+    ioeGetFileName,            -- :: IOError -> Maybe FilePath
+    try,                       -- :: IO a -> IO (Either IOError a)
+    -- re-exports of Prelude names
+    IOError,
+    ioError,                   -- :: IOError -> IO a
+    userError,                 -- :: String  -> IOError
+    catch                      -- :: IO a    -> (IOError -> IO a) -> IO a
+  )
 
 -- -----------------------------------------------------------------------------
 -- Standard IO
 
 #ifndef __HUGS__
+-- | Write a character to the standard output device
+-- (same as 'hPutChar' 'stdout').
+
 putChar         :: Char -> IO ()
 putChar c       =  hPutChar stdout c
 
+-- | Write a string to the standard output device
+-- (same as 'hPutStr' 'stdout').
+
 putStr          :: String -> IO ()
 putStr s        =  hPutStr stdout s
 
+-- | The same as 'putStrLn', but adds a newline character.
+
 putStrLn        :: String -> IO ()
 putStrLn s      =  do putStr s
                       putChar '\n'
 
+-- | The 'print' function outputs a value of any printable type to the
+-- standard output device.
+-- Printable types are those that are instances of class 'Show'; 'print'
+-- converts values to strings for output using the 'show' operation and
+-- adds a newline.
+--
+-- For example, a program to print the first 20 integers and their
+-- powers of 2 could be written as:
+--
+-- > main = print ([(n, 2^n) | n <- [0..19]])
+
 print           :: Show a => a -> IO ()
 print x         =  putStrLn (show x)
 
+-- | Read a character from the standard input device
+-- (same as 'hGetChar' 'stdin').
+
 getChar         :: IO Char
 getChar         =  hGetChar stdin
 
+-- | Read a line from the standard input device
+-- (same as 'hGetLine' 'stdin').
+
 getLine         :: IO String
 getLine         =  hGetLine stdin
 
+-- | The 'getContents' operation returns all user input as a single string,
+-- which is read lazily as it is needed
+-- (same as 'hGetContents' 'stdin').
+
 getContents     :: IO String
 getContents     =  hGetContents stdin
 
+-- | The 'interact' function takes a function of type @String->String@
+-- as its argument.  The entire input from the standard input device is
+-- passed to this function as its argument, and the resulting string is
+-- output on the standard output device.
+
 interact        ::  (String -> String) -> IO ()
 interact f      =   do s <- getContents
                        putStr (f s)
 
+-- | The 'readFile' function reads a file and
+-- returns the contents of the file as a string.
+-- The file is read lazily, on demand, as with 'getContents'.
+
 readFile        :: FilePath -> IO String
 readFile name  =  openFile name ReadMode >>= hGetContents
 
+-- | The computation 'writeFile' @file str@ function writes the string @str@,
+-- to the file @file@.
+
 writeFile       :: FilePath -> String -> IO ()
 writeFile name str = do
     hdl <- openFile name WriteMode
     hPutStr hdl str
     hClose hdl
 
+-- | The computation 'appendFile' @file str@ function appends the string @str@,
+-- to the file @file@.
+--
+-- Note that 'writeFile' and 'appendFile' write a literal string
+-- to a file.  To write a value of any printable type, as with 'print',
+-- use the 'show' function to convert the value to a string first.
+--
+-- > main = appendFile "squares" (show [(x,x*x) | x <- [0,0.1..2]])
+
 appendFile      :: FilePath -> String -> IO ()
 appendFile name str = do
     hdl <- openFile name AppendMode
     hPutStr hdl str
     hClose hdl
 
+-- | The 'readLn' function combines 'getLine' and 'readIO'.
+
 readLn          :: Read a => IO a
 readLn          =  do l <- getLine
                       r <- readIO l
                       return r
 
--- raises an exception instead of an error
+-- | The 'readIO' function is similar to 'read' except that it signals
+-- parse failure to the 'IO' monad instead of terminating the program.
+
 readIO          :: Read a => String -> IO a
 readIO s        =  case (do { (x,t) <- reads s ;
                              ("","") <- lex t ;
@@ -236,14 +340,33 @@ readIO s        =  case (do { (x,t) <- reads s ;
                        _      -> ioError (userError "Prelude.readIO: ambiguous parse")
 #endif  /* __HUGS__ */
 
+-- | Computation 'hReady' @hdl@ indicates whether at least one item is
+-- available for input from handle "hdl".
+-- 
+-- This operation may fail with:
+--
+--  * 'isEOFError' if the end of file has been reached.
+
 hReady         :: Handle -> IO Bool
 hReady h       =  hWaitForInput h 0
 
+-- | The same as 'hPutStr', but adds a newline character.
+
 hPutStrLn      :: Handle -> String -> IO ()
 hPutStrLn hndl str = do
  hPutStr  hndl str
  hPutChar hndl '\n'
 
+-- | Computation 'hPrint' @hdl t@ writes the string representation of @t@
+-- given by the 'shows' function to the file or channel managed by @hdl@
+-- and appends a newline.
+--
+-- This operation may fail with:
+--
+--  * 'isFullError' if the device is full; or
+--
+--  * 'isPermissionError' if another system resource limit would be exceeded.
+
 hPrint         :: Show a => Handle -> a -> IO ()
 hPrint hdl     =  hPutStrLn hdl . show
 
@@ -258,3 +381,22 @@ fixIO m         = stToIO (fixST (ioToST . m))
 fixIO           :: (a -> IO a) -> IO a
 fixIO f         = let x = unsafePerformIO (f x) in return x
 #endif
+
+-- $locking
+-- Implementations should enforce as far as possible, at least locally to the
+-- Haskell process, multiple-reader single-writer locking on files.
+-- That is, /there may either be many handles on the same file which manage
+-- input, or just one handle on the file which manages output/.  If any
+-- open or semi-closed handle is managing a file for output, no new
+-- handle can be allocated for that file.  If any open or semi-closed
+-- handle is managing a file for input, new handles can only be allocated
+-- if they do not manage output.  Whether two files are the same is
+-- implementation-dependent, but they should normally be the same if they
+-- have the same absolute path name and neither has been renamed, for
+-- example.
+--
+-- /Warning/: the 'readFile' operation holds a semi-closed handle on
+-- the file until the entire contents of the file have been consumed.
+-- It follows that an attempt to write to a file (using 'writeFile', for
+-- example) that was earlier opened by 'readFile' will usually result in
+-- failure with 'isAlreadyInUseError'.