Commits

Bryan O'Sullivan committed 841ae46

Implement lazy hGetContents.

Comments (0)

Files changed (1)

Data/Text/Lazy/IO.hs

     , putStrLn
     ) where
 
-import Data.Text.Lazy (Text)
+import Data.Text.Lazy.Internal (Text(..))
 import Prelude hiding (appendFile, getContents, getLine, interact, putStr,
                        putStrLn, readFile, writeFile)
 import System.IO (Handle, IOMode(..), hPutChar, openFile, stdin, stdout,
 import qualified Data.ByteString.Char8 as S8
 import qualified Data.ByteString.Lazy.Char8 as L8
 #else
-import Data.Text.IO.Internal (hGetLineWith)
+import Control.Exception (throw)
+import Data.IORef (readIORef, writeIORef)
+import Data.Text.IO.Internal (hGetLineWith, readChunk)
+import GHC.IO.Buffer (Buffer(..), BufferState(..), CharBufElem, CharBuffer,
+                      RawCharBuffer, bufferAdjustL, bufferElems, charSize,
+                      emptyBuffer, isEmptyBuffer, newCharBuffer, readCharBuf,
+                      withRawBuffer, writeCharBuf)
+import GHC.IO.Exception (IOException(..), IOErrorType(..), ioException)
+import GHC.IO.Handle.Internals (augmentIOError, ioe_EOF, readTextDevice,
+                                wantReadableHandle_, hClose_help,
+                                wantReadableHandle, wantWritableHandle,
+                                withHandle)
+import GHC.IO.Handle.Text (commitBuffer')
+import GHC.IO.Handle.Types (BufferList(..), BufferMode(..), Handle__(..),
+                            HandleType(..), Newline(..))
+import System.IO.Error (isEOFError)
+import System.IO.Unsafe (unsafeInterleaveIO)
 #endif
 
 -- | The 'readFile' function reads a file and returns the contents of
 #if __GLASGOW_HASKELL__ <= 610
 hGetContents = fmap decodeUtf8 . L8.hGetContents
 #else
-hGetContents = undefined
+hGetContents h =
+    wantReadableHandle "hGetContents" h $ \hh -> do
+      ts <- lazyRead h
+      return (hh{haType=SemiClosedHandle}, ts)
+
+lazyRead :: Handle -> IO Text
+lazyRead h = unsafeInterleaveIO $
+  withHandle "hGetContents" h $ \hh -> do
+    case haType hh of
+      ClosedHandle     -> return (hh, L.empty)
+      SemiClosedHandle -> lazyReadBuffered h hh
+      _                -> ioException 
+                          (IOError (Just h) IllegalOperation "hGetContents"
+                           "illegal handle type" Nothing Nothing)
+
+lazyReadBuffered :: Handle -> Handle__ -> IO (Handle__, Text)
+lazyReadBuffered h hh@Handle__{..} = do
+   buf <- readIORef haCharBuffer
+   (do t <- readChunk hh buf
+       ts <- lazyRead h
+       return (hh, Chunk t ts)) `catch` \e -> do
+         (hh', _) <- hClose_help hh
+         if isEOFError e
+           then return $ if isEmptyBuffer buf
+                         then (hh', Empty)
+                         else (hh', L.singleton '\r')
+           else throw (augmentIOError e "hGetContents" h)
 #endif
 
 -- | Read a single line from a handle.
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.