mark System.IO.openTempFile as non-portable in haddocks
[haskell-directory.git] / GHC / IO.hs
index c4c9143..0a7416f 100644 (file)
--- a/GHC/IO.hs
+++ b/GHC/IO.hs
@@ -1,4 +1,4 @@
-{-# OPTIONS -fno-implicit-prelude -#include "HsBase.h" #-}
+{-# OPTIONS_GHC -fno-implicit-prelude -#include "HsBase.h" #-}
 
 #undef DEBUG_DUMP
 
@@ -16,6 +16,7 @@
 --
 -----------------------------------------------------------------------------
 
+-- #hide
 module GHC.IO ( 
    hWaitForInput, hGetChar, hGetLine, hGetContents, hPutChar, hPutStr,
    commitBuffer',      -- hack, see below
@@ -27,8 +28,6 @@ module GHC.IO (
    memcpy_baoff_ptr,
  ) where
 
-#include "config.h"
-
 import Foreign
 import Foreign.C
 
@@ -47,6 +46,10 @@ import GHC.Show
 import GHC.List
 import GHC.Exception    ( ioError, catch )
 
+#ifdef mingw32_HOST_OS
+import GHC.Conc
+#endif
+
 -- ---------------------------------------------------------------------------
 -- Simple input operations
 
@@ -61,13 +64,15 @@ import GHC.Exception    ( ioError, catch )
 -- or 'False' if no input is available within @t@ milliseconds.
 --
 -- If @t@ is less than zero, then @hWaitForInput@ waits indefinitely.
--- NOTE: in the current implementation, this is the only case that works
--- correctly (if @t@ is non-zero, then all other concurrent threads are
--- blocked until data is available).
 --
 -- This operation may fail with:
 --
 --  * 'isEOFError' if the end of file has been reached.
+--
+-- NOTE for GHC users: unless you use the @-threaded@ flag,
+-- @hWaitForInput t@ where @t >= 0@ will block all other Haskell
+-- threads for the duration of the call.  It behaves like a
+-- @safe@ foreign call in this respect.
 
 hWaitForInput :: Handle -> Int -> IO Bool
 hWaitForInput h msecs = do
@@ -85,12 +90,13 @@ hWaitForInput h msecs = do
                writeIORef ref buf'
                return True
        else do r <- throwErrnoIfMinus1Retry "hWaitForInput" $
-                       inputReady (fromIntegral (haFD handle_)) 
-                          (fromIntegral msecs) (haIsStream handle_)
+                    inputReady (haFD handle_)
+                               (fromIntegral msecs)
+                                (fromIntegral $ fromEnum $ haIsStream handle_)
                return (r /= 0)
 
-foreign import ccall unsafe "inputReady"
-  inputReady :: CInt -> CInt -> Bool -> IO CInt
+foreign import ccall safe "inputReady"
+  inputReady :: CInt -> CInt -> CInt -> IO CInt
 
 -- ---------------------------------------------------------------------------
 -- hGetChar
@@ -127,7 +133,7 @@ hGetChar handle =
     NoBuffering -> do
        -- make use of the minimal buffer we already have
        let raw = bufBuf buf
-       r <- readRawBuffer "hGetChar" (fromIntegral fd) (haIsStream handle_) raw 0 1
+       r <- readRawBuffer "hGetChar" fd (haIsStream handle_) raw 0 1
        if r == 0
           then ioe_EOF
           else do (c,_) <- readCharFromBuffer raw 0
@@ -173,24 +179,25 @@ hGetLine h = do
        Nothing -> hGetLineUnBuffered h
        Just l  -> return l
 
-
+hGetLineBuffered :: Handle__ -> IO String
 hGetLineBuffered handle_ = do
   let ref = haBuffer handle_
   buf <- readIORef ref
   hGetLineBufferedLoop handle_ ref buf []
 
-
-hGetLineBufferedLoop handle_ ref 
-       buf@Buffer{ bufRPtr=r, bufWPtr=w, bufBuf=raw } xss =
-  let 
-       -- find the end-of-line character, if there is one
-       loop raw r
-          | r == w = return (False, w)
-          | otherwise =  do
-               (c,r') <- readCharFromBuffer raw r
-               if c == '\n' 
-                  then return (True, r) -- NB. not r': don't include the '\n'
-                  else loop raw r'
+hGetLineBufferedLoop :: Handle__ -> IORef Buffer -> Buffer -> [String]
+                     -> IO String
+hGetLineBufferedLoop handle_ ref
+        buf@Buffer{ bufRPtr=r, bufWPtr=w, bufBuf=raw } xss =
+  let
+        -- find the end-of-line character, if there is one
+        loop raw r
+           | r == w = return (False, w)
+           | otherwise =  do
+                (c,r') <- readCharFromBuffer raw r
+                if c == '\n'
+                   then return (True, r) -- NB. not r': don't include the '\n'
+                   else loop raw r'
   in do
   (eol, off) <- loop raw r
 
@@ -203,24 +210,24 @@ hGetLineBufferedLoop handle_ ref
   -- if eol == True, then off is the offset of the '\n'
   -- otherwise off == w and the buffer is now empty.
   if eol
-       then do if (w == off + 1)
-                       then writeIORef ref buf{ bufRPtr=0, bufWPtr=0 }
-                       else writeIORef ref buf{ bufRPtr = off + 1 }
-               return (concat (reverse (xs:xss)))
-       else do
-            maybe_buf <- maybeFillReadBuffer (haFD handle_) True (haIsStream handle_)
-                               buf{ bufWPtr=0, bufRPtr=0 }
-            case maybe_buf of
-               -- Nothing indicates we caught an EOF, and we may have a
-               -- partial line to return.
-               Nothing -> do
-                    writeIORef ref buf{ bufRPtr=0, bufWPtr=0 }
-                    let str = concat (reverse (xs:xss))
-                    if not (null str)
-                       then return str
-                       else ioe_EOF
-               Just new_buf -> 
-                    hGetLineBufferedLoop handle_ ref new_buf (xs:xss)
+        then do if (w == off + 1)
+                        then writeIORef ref buf{ bufRPtr=0, bufWPtr=0 }
+                        else writeIORef ref buf{ bufRPtr = off + 1 }
+                return (concat (reverse (xs:xss)))
+        else do
+             maybe_buf <- maybeFillReadBuffer (haFD handle_) True (haIsStream handle_)
+                                buf{ bufWPtr=0, bufRPtr=0 }
+             case maybe_buf of
+                -- Nothing indicates we caught an EOF, and we may have a
+                -- partial line to return.
+                Nothing -> do
+                     writeIORef ref buf{ bufRPtr=0, bufWPtr=0 }
+                     let str = concat (reverse (xs:xss))
+                     if not (null str)
+                        then return str
+                        else ioe_EOF
+                Just new_buf ->
+                     hGetLineBufferedLoop handle_ ref new_buf (xs:xss)
 
 
 maybeFillReadBuffer fd is_line is_stream buf
@@ -344,7 +351,7 @@ lazyRead' h handle_ = do
      NoBuffering      -> do
        -- make use of the minimal buffer we already have
        let raw = bufBuf buf
-       r <- readRawBuffer "lazyRead" (fromIntegral fd) (haIsStream handle_) raw 0 1
+       r <- readRawBuffer "lazyRead" fd (haIsStream handle_) raw 0 1
        if r == 0
           then do handle_ <- hClose_help handle_ 
                   return (handle_, "")
@@ -398,16 +405,16 @@ unpackAcc buf (I# r) (I# len) acc = IO $ \s -> unpack acc (len -# 1#) s
 --  * 'isPermissionError' if another system resource limit would be exceeded.
 
 hPutChar :: Handle -> Char -> IO ()
-hPutChar handle c = 
-    c `seq` do   -- must evaluate c before grabbing the handle lock
+hPutChar handle c = do
+    c `seq` return ()
     wantWritableHandle "hPutChar" handle $ \ handle_  -> do
     let fd = haFD handle_
     case haBufferMode handle_ of
        LineBuffering    -> hPutcBuffered handle_ True  c
        BlockBuffering _ -> hPutcBuffered handle_ False c
        NoBuffering      ->
-               withObject (castCharToCChar c) $ \buf -> do
-                 writeRawBufferPtr "hPutChar" (fromIntegral fd) (haIsStream handle_) buf 0 1
+               with (castCharToCChar c) $ \buf -> do
+                 writeRawBufferPtr "hPutChar" fd (haIsStream handle_) buf 0 1
                  return ()
 
 hPutcBuffered handle_ is_line c = do
@@ -559,7 +566,7 @@ commitBuffer
 
 commitBuffer hdl raw sz@(I# _) count@(I# _) flush release = do
   wantWritableHandle "commitAndReleaseBuffer" hdl $
-     commitBuffer' hdl raw sz count flush release
+     commitBuffer' raw sz count flush release
 
 -- Explicitly lambda-lift this function to subvert GHC's full laziness
 -- optimisations, which otherwise tends to float out subexpressions
@@ -572,7 +579,7 @@ commitBuffer hdl raw sz@(I# _) count@(I# _) flush release = do
 --
 -- This hack is a fairly big win for hPutStr performance.  --SDM 18/9/2001
 --
-commitBuffer' hdl raw sz@(I# _) count@(I# _) flush release
+commitBuffer' raw sz@(I# _) count@(I# _) flush release
   handle_@Handle__{ haFD=fd, haBuffer=ref, haBuffers=spare_buf_ref } = do
 
 #ifdef DEBUG_DUMP
@@ -595,7 +602,7 @@ commitBuffer' hdl raw sz@(I# _) count@(I# _) flush release
 
                -- not flushing, and there's enough room in the buffer:
                -- just copy the data in and update bufWPtr.
-           then do memcpy_baoff_ba old_raw w raw (fromIntegral count)
+           then do memcpy_baoff_ba old_raw (fromIntegral w) raw (fromIntegral count)
                    writeIORef ref old_buf{ bufWPtr = w + count }
                    return (newEmptyBuffer raw WriteBuffer sz)
 
@@ -689,7 +696,7 @@ bufWrite fd ref is_stream ptr count can_block =
   if (size - w > count)
        -- There's enough room in the buffer:
        -- just copy the data in and update bufWPtr.
-       then do memcpy_baoff_ptr old_raw w ptr (fromIntegral count)
+       then do memcpy_baoff_ptr old_raw (fromIntegral w) ptr (fromIntegral count)
                writeIORef ref old_buf{ bufWPtr = w + count }
                return count
 
@@ -712,7 +719,7 @@ writeChunk fd is_stream ptr bytes = loop 0 bytes
   loop _   bytes | bytes <= 0 = return ()
   loop off bytes = do
     r <- fromIntegral `liftM`
-          writeRawBufferPtr "writeChunk" (fromIntegral fd) is_stream ptr
+          writeRawBufferPtr "writeChunk" fd is_stream ptr
                             off (fromIntegral bytes)
     -- write can't return 0
     loop (off + r) (bytes - r)
@@ -723,8 +730,8 @@ writeChunkNonBlocking fd is_stream ptr bytes = loop 0 bytes
   loop :: Int -> Int -> IO Int
   loop off bytes | bytes <= 0 = return off
   loop off bytes = do
-#ifndef mingw32_TARGET_OS
-    ssize <- c_write (fromIntegral fd) (ptr `plusPtr` off) (fromIntegral bytes)
+#ifndef mingw32_HOST_OS
+    ssize <- c_write fd (ptr `plusPtr` off) (fromIntegral bytes)
     let r = fromIntegral ssize :: Int
     if (r == -1)
       then do errno <- getErrno
@@ -733,7 +740,8 @@ writeChunkNonBlocking fd is_stream ptr bytes = loop 0 bytes
                 else throwErrno "writeChunk"
       else loop (off + r) (bytes - r)
 #else
-    (ssize, rc) <- asyncWrite fd (fromIntegral $ fromEnum is_stream)
+    (ssize, rc) <- asyncWrite (fromIntegral fd)
+                              (fromIntegral $ fromEnum is_stream)
                                 (fromIntegral bytes)
                                 (ptr `plusPtr` off)
     let r = fromIntegral ssize :: Int
@@ -779,24 +787,26 @@ bufRead fd ref is_stream ptr so_far count =
                else do mb_buf <- maybeFillReadBuffer fd True is_stream buf
                        case mb_buf of
                          Nothing -> return so_far -- got nothing, we're done
-                         Just new_buf -> do 
-                           writeIORef ref new_buf
-                           bufRead fd ref is_stream ptr so_far count
+                         Just buf' -> do
+                               writeIORef ref buf'
+                               bufRead fd ref is_stream ptr so_far count
      else do 
        let avail = w - r
        if (count == avail)
           then do 
-               memcpy_ptr_baoff ptr raw r (fromIntegral count)
+               memcpy_ptr_baoff ptr raw (fromIntegral r) (fromIntegral count)
                writeIORef ref buf{ bufWPtr=0, bufRPtr=0 }
                return (so_far + count)
           else do
        if (count < avail)
           then do 
-               memcpy_ptr_baoff ptr raw r (fromIntegral count)
+               memcpy_ptr_baoff ptr raw (fromIntegral r) (fromIntegral count)
                writeIORef ref buf{ bufRPtr = r + count }
                return (so_far + count)
           else do
   
+       memcpy_ptr_baoff ptr raw (fromIntegral r) (fromIntegral avail)
+       writeIORef ref buf{ bufWPtr=0, bufRPtr=0 }
        let remaining = count - avail
            so_far' = so_far + avail
            ptr' = ptr `plusPtr` avail
@@ -815,7 +825,7 @@ readChunk fd is_stream ptr bytes = loop 0 bytes
   loop off bytes | bytes <= 0 = return off
   loop off bytes = do
     r <- fromIntegral `liftM`
-           readRawBufferPtr "readChunk" (fromIntegral fd) is_stream 
+           readRawBufferPtr "readChunk" fd is_stream 
                            (castPtr ptr) off (fromIntegral bytes)
     if r == 0
        then return off
@@ -867,17 +877,19 @@ bufReadNonBlocking fd ref is_stream ptr so_far count =
        let avail = w - r
        if (count == avail)
           then do 
-               memcpy_ptr_baoff ptr raw r (fromIntegral count)
+               memcpy_ptr_baoff ptr raw (fromIntegral r) (fromIntegral count)
                writeIORef ref buf{ bufWPtr=0, bufRPtr=0 }
                return (so_far + count)
           else do
        if (count < avail)
           then do 
-               memcpy_ptr_baoff ptr raw r (fromIntegral count)
+               memcpy_ptr_baoff ptr raw (fromIntegral r) (fromIntegral count)
                writeIORef ref buf{ bufRPtr = r + count }
                return (so_far + count)
           else do
 
+       memcpy_ptr_baoff ptr raw (fromIntegral r) (fromIntegral avail)
+       writeIORef ref buf{ bufWPtr=0, bufRPtr=0 }
        let remaining = count - avail
            so_far' = so_far + avail
            ptr' = ptr `plusPtr` avail
@@ -893,8 +905,8 @@ bufReadNonBlocking fd ref is_stream ptr so_far count =
 
 readChunkNonBlocking :: FD -> Bool -> Ptr a -> Int -> IO Int
 readChunkNonBlocking fd is_stream ptr bytes = do
-#ifndef mingw32_TARGET_OS
-    ssize <- c_read (fromIntegral fd) (castPtr ptr) (fromIntegral bytes)
+#ifndef mingw32_HOST_OS
+    ssize <- c_read fd (castPtr ptr) (fromIntegral bytes)
     let r = fromIntegral ssize :: Int
     if (r == -1)
       then do errno <- getErrno
@@ -903,12 +915,13 @@ readChunkNonBlocking fd is_stream ptr bytes = do
                 else throwErrno "readChunk"
       else return r
 #else
-    (ssize, rc) <- asyncRead fd (fromIntegral $ fromEnum is_stream)
-                              (fromIntegral bytes) ptr
-    let r = fromIntegral ssize :: Int
-    if r == (-1)
-     then ioError (errnoToIOError "hGetBufNonBlocking" (Errno (fromIntegral rc)) Nothing Nothing)
-     else return r
+    fromIntegral `liftM`
+        readRawBufferPtr "readChunkNonBlocking" fd is_stream 
+                           (castPtr ptr) 0 (fromIntegral bytes)
+
+    -- we don't have non-blocking read support on Windows, so just invoke
+    -- the ordinary low-level read which will block until data is available,
+    -- but won't wait for the whole buffer to fill.
 #endif
 
 slurpFile :: FilePath -> IO (Ptr (), Int)
@@ -929,13 +942,13 @@ slurpFile fname = do
 -- memcpy wrappers
 
 foreign import ccall unsafe "__hscore_memcpy_src_off"
-   memcpy_ba_baoff :: RawBuffer -> RawBuffer -> Int -> CSize -> IO (Ptr ())
+   memcpy_ba_baoff :: RawBuffer -> RawBuffer -> CInt -> CSize -> IO (Ptr ())
 foreign import ccall unsafe "__hscore_memcpy_src_off"
-   memcpy_ptr_baoff :: Ptr a -> RawBuffer -> Int -> CSize -> IO (Ptr ())
+   memcpy_ptr_baoff :: Ptr a -> RawBuffer -> CInt -> CSize -> IO (Ptr ())
 foreign import ccall unsafe "__hscore_memcpy_dst_off"
-   memcpy_baoff_ba :: RawBuffer -> Int -> RawBuffer -> CSize -> IO (Ptr ())
+   memcpy_baoff_ba :: RawBuffer -> CInt -> RawBuffer -> CSize -> IO (Ptr ())
 foreign import ccall unsafe "__hscore_memcpy_dst_off"
-   memcpy_baoff_ptr :: RawBuffer -> Int -> Ptr a -> CSize -> IO (Ptr ())
+   memcpy_baoff_ptr :: RawBuffer -> CInt -> Ptr a -> CSize -> IO (Ptr ())
 
 -----------------------------------------------------------------------------
 -- Internal Utils