1 {-# LANGUAGE BangPatterns, CPP, RecordWildCards #-} 2 -- | 3 -- Module : Data.Text.Lazy.IO 4 -- Copyright : (c) 2009, 2010 Bryan O'Sullivan, 5 -- (c) 2009 Simon Marlow 6 -- License : BSD-style 7 -- Maintainer : bos@serpentine.com 8 -- Stability : experimental 9 -- Portability : GHC 10 -- 11 -- Efficient locale-sensitive support for lazy text I\/O. 12 13 module Data.Text.Lazy.IO 14 ( 15 -- * Locale support 16 -- $locale 17 -- * File-at-a-time operations 18 readFile 19 , writeFile 20 , appendFile 21 -- * Operations on handles 22 , hGetContents 23 , hGetLine 24 , hPutStr 25 , hPutStrLn 26 -- * Special cases for standard input and output 27 , interact 28 , getContents 29 , getLine 30 , putStr 31 , putStrLn 32 ) where 33 34 import Data.Text.Lazy (Text) 35 import Prelude hiding (appendFile, getContents, getLine, interact, putStr, 36 putStrLn, readFile, writeFile) 37 import System.IO (Handle, IOMode(..), hPutChar, openFile, stdin, stdout, 38 withFile) 39 import qualified Data.Text.IO as T 40 import qualified Data.Text.Lazy as L 41 #if __GLASGOW_HASKELL__ <= 610 42 import Data.Text.Lazy.Encoding (decodeUtf8) 43 import qualified Data.ByteString.Char8 as S8 44 import qualified Data.ByteString.Lazy.Char8 as L8 45 #else 46 import Control.Exception (throw) 47 import Control.Monad (when) 48 import Data.IORef (readIORef) 49 import Data.Text.IO.Internal (hGetLineWith, readChunk) 50 import Data.Text.Lazy.Internal (chunk, empty) 51 import GHC.IO.Buffer (isEmptyBuffer) 52 import GHC.IO.Exception (IOException(..), IOErrorType(..), ioException) 53 import GHC.IO.Handle.Internals (augmentIOError, hClose_help, 54 wantReadableHandle, withHandle) 55 import GHC.IO.Handle.Types (Handle__(..), HandleType(..)) 56 import System.IO (BufferMode(..), hGetBuffering, hSetBuffering) 57 import System.IO.Error (isEOFError) 58 import System.IO.Unsafe (unsafeInterleaveIO) 59 #endif 60 61 -- | Read a file and return its contents as a string. The file is 62 -- read lazily, as with 'getContents'. 63 readFile :: FilePath -> IO Text 64 -- never enteredreadFile name = openFile name ReadMode >>= hGetContents 65 66 -- | Write a string to a file. The file is truncated to zero length 67 -- before writing begins. 68 writeFile :: FilePath -> Text -> IO () 69 -- never enteredwriteFile p = withFile p WriteMode . flip hPutStr 70 71 -- | Write a string the end of a file. 72 appendFile :: FilePath -> Text -> IO () 73 -- never enteredappendFile p = withFile p AppendMode . flip hPutStr 74 75 -- | Lazily read the remaining contents of a 'Handle'. The 'Handle' 76 -- will be closed after the read completes, or on error. 77 hGetContents :: Handle -> IO Text 78 #if __GLASGOW_HASKELL__ <= 610 79 hGetContents = fmap decodeUtf8 . L8.hGetContents 80 #else 81 -- entered 100 timeshGetContents h = do 82 chooseGoodBuffering h 83 wantReadableHandle "hGetContents" h $ \hh -> do 84 ts <- lazyRead h 85 return (hh{haType=SemiClosedHandle}, ts) 86 87 -- | Use a more efficient buffer size if we're reading in 88 -- block-buffered mode with the default buffer size. 89 chooseGoodBuffering :: Handle -> IO () 90 -- entered 100 timeschooseGoodBuffering h = do 91 bufMode <- hGetBuffering h 92 when (bufMode == BlockBuffering Nothing) $ 93 hSetBuffering h (BlockBuffering (Just 16384)) 94 95 lazyRead :: Handle -> IO Text 96 -- entered 100 timeslazyRead h = unsafeInterleaveIO $ 97 withHandle "hGetContents" h $ \hh -> do 98 case haType hh of 99 ClosedHandle -> return (hh, L.empty) 100 SemiClosedHandle -> lazyReadBuffered h hh 101 _ -> ioException 102 (IOError (Just h) IllegalOperation "hGetContents" 103 "illegal handle type" Nothing Nothing) 104 105 lazyReadBuffered :: Handle -> Handle__ -> IO (Handle__, Text) 106 -- entered 203 timeslazyReadBuffered h hh@Handle__{..} = do 107 buf <- readIORef haCharBuffer 108 (do t <- readChunk hh buf 109 ts <- lazyRead h 110 return (hh, chunk t ts)) `catch` \e -> do 111 (hh', _) <- hClose_help hh 112 if isEOFError e 113 then return $ if isEmptyBuffer buf 114 then (hh', empty) 115 else (hh', L.singleton '\r') 116 else throw (augmentIOError e "hGetContents" h) 117 #endif 118 119 -- | Read a single line from a handle. 120 hGetLine :: Handle -> IO Text 121 #if __GLASGOW_HASKELL__ <= 610 122 hGetLine = fmap (decodeUtf8 . L8.fromChunks . (:[])) . S8.hGetLine 123 #else 124 -- entered oncehGetLine = hGetLineWith L.fromChunks 125 #endif 126 127 -- | Write a string to a handle. 128 hPutStr :: Handle -> Text -> IO () 129 -- entered 200 timeshPutStr h = mapM_ (T.hPutStr h) . L.toChunks 130 131 -- | Write a string to a handle, followed by a newline. 132 hPutStrLn :: Handle -> Text -> IO () 133 -- entered 100 timeshPutStrLn h t = hPutStr h t >> hPutChar h '\n' 134 135 -- | The 'interact' function takes a function of type @Text -> Text@ 136 -- as its argument. The entire input from the standard input device is 137 -- passed (lazily) to this function as its argument, and the resulting 138 -- string is output on the standard output device. 139 interact :: (Text -> Text) -> IO () 140 -- never enteredinteract f = putStr . f =<< getContents 141 142 -- | Lazily read all user input on 'stdin' as a single string. 143 getContents :: IO Text 144 -- never enteredgetContents = hGetContents stdin 145 146 -- | Read a single line of user input from 'stdin'. 147 getLine :: IO Text 148 -- never enteredgetLine = hGetLine stdin 149 150 -- | Write a string to 'stdout'. 151 putStr :: Text -> IO () 152 -- never enteredputStr = hPutStr stdout 153 154 -- | Write a string to 'stdout', followed by a newline. 155 putStrLn :: Text -> IO () 156 -- never enteredputStrLn = hPutStrLn stdout 157 158 -- $locale 159 -- 160 -- /Note/: The behaviour of functions in this module depends on the 161 -- version of GHC you are using. 162 -- 163 -- Beginning with GHC 6.12, text I\/O is performed using the system or 164 -- handle's current locale and line ending conventions. 165 -- 166 -- Under GHC 6.10 and earlier, the system I\/O libraries /do not 167 -- support/ locale-sensitive I\/O or line ending conversion. On these 168 -- versions of GHC, functions in this library all use UTF-8. What 169 -- does this mean in practice? 170 -- 171 -- * All data that is read will be decoded as UTF-8. 172 -- 173 -- * Before data is written, it is first encoded as UTF-8. 174 -- 175 -- * On both reading and writing, the platform's native newline 176 -- conversion is performed. 177 -- 178 -- If you must use a non-UTF-8 locale on an older version of GHC, you 179 -- will have to perform the transcoding yourself, e.g. as follows: 180 -- 181 -- > import qualified Data.ByteString.Lazy as B 182 -- > import Data.Text.Lazy (Text) 183 -- > import Data.Text.Lazy.Encoding (encodeUtf16) 184 -- > 185 -- > putStr_Utf16LE :: Text -> IO () 186 -- > putStr_Utf16LE t = B.putStr (encodeUtf16LE t)