on builder help sign in
text/Data/Text/IO.hs
334 lines 12 kB history raw
1{-# LANGUAGE BangPatterns, CPP, RecordWildCards, ScopedTypeVariables #-}
2-- |
3-- Module : Data.Text.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 text I\/O.
12--
13-- Skip past the synopsis for some important notes on performance and
14-- portability across different versions of GHC.
16module Data.Text.IO
17 (
18 -- * Performance
19 -- $performance
21 -- * Locale support
22 -- $locale
23 -- * File-at-a-time operations
24 readFile
25 , writeFile
26 , appendFile
27 -- * Operations on handles
28 , hGetContents
29 , hGetLine
30 , hPutStr
31 , hPutStrLn
32 -- * Special cases for standard input and output
33 , interact
34 , getContents
35 , getLine
36 , putStr
37 , putStrLn
38 ) where
40import Data.Text (Text)
41import Prelude hiding (appendFile, catch, getContents, getLine, interact,
42 putStr, putStrLn, readFile, writeFile)
43import System.IO (Handle, IOMode(..), hPutChar, openFile, stdin, stdout,
44 withFile)
45#if __GLASGOW_HASKELL__ <= 610
46import qualified Data.ByteString.Char8 as B
47import Data.Text.Encoding (decodeUtf8, encodeUtf8)
48#else
49import Control.Exception (catch, throwIO)
50import Control.Monad (liftM2, when)
51import Data.IORef (readIORef, writeIORef)
52import qualified Data.Text as T
53import Data.Text.Fusion (stream)
54import Data.Text.Fusion.Internal (Step(..), Stream(..))
55import Data.Text.IO.Internal (hGetLineWith, readChunk)
56import GHC.IO.Buffer (Buffer(..), BufferState(..), CharBufElem, CharBuffer,
57 RawCharBuffer, emptyBuffer, isEmptyBuffer, newCharBuffer,
58 writeCharBuf)
59import GHC.IO.Exception (IOException(ioe_type), IOErrorType(InappropriateType))
60import GHC.IO.Handle.Internals (augmentIOError, hClose_help, wantReadableHandle,
61 wantWritableHandle)
62import GHC.IO.Handle.Text (commitBuffer')
63import GHC.IO.Handle.Types (BufferList(..), BufferMode(..), Handle__(..),
64 HandleType(..), Newline(..))
65import System.IO (hGetBuffering, hFileSize, hSetBuffering, hTell)
66import System.IO.Error (isEOFError)
67#endif
69-- $performance
70-- #performance#
71--
72-- The functions in this module obey the runtime system's locale,
73-- character set encoding, and line ending conversion settings.
74--
75-- If you know in advance that you will be working with data that has
76-- a specific encoding (e.g. UTF-8), and your application is highly
77-- performance sensitive, you may find that it is faster to perform
78-- I\/O with bytestrings and to encode and decode yourself than to use
79-- the functions in this module.
80--
81-- Whether this will hold depends on the version of GHC you are using,
82-- the platform you are working on, the data you are working with, and
83-- the encodings you are using, so be sure to test for yourself.
85-- | The 'readFile' function reads a file and returns the contents of
86-- the file as a string. The entire file is read strictly, as with
87-- 'getContents'.
88readFile :: FilePath -> IO Text
89readFile name = openFile name ReadMode >>= hGetContents
91-- | Write a string to a file. The file is truncated to zero length
92-- before writing begins.
93writeFile :: FilePath -> Text -> IO ()
94writeFile p = withFile p WriteMode . flip hPutStr
96-- | Write a string the end of a file.
97appendFile :: FilePath -> Text -> IO ()
98appendFile p = withFile p AppendMode . flip hPutStr
100-- | Read the remaining contents of a 'Handle' as a string. The
101-- 'Handle' is closed once the contents have been read, or if an
102-- exception is thrown.
103--
104-- Internally, this function reads a chunk at a time from the
105-- lower-level buffering abstraction, and concatenates the chunks into
106-- a single string once the entire file has been read.
107--
108-- As a result, it requires approximately twice as much memory as its
109-- result to construct its result. For files more than a half of
110-- available RAM in size, this may result in memory exhaustion.
111hGetContents :: Handle -> IO Text
112#if __GLASGOW_HASKELL__ <= 610
113hGetContents = fmap decodeUtf8 . B.hGetContents
114#else
115hGetContents h = do
116 chooseGoodBuffering h
117 wantReadableHandle "hGetContents" h readAll
118 where
119 readAll hh@Handle__{..} = do
120 let catchError e
121 | isEOFError e = do
122 buf <- readIORef haCharBuffer
123 return $ if isEmptyBuffer buf
124 then T.empty
125 else T.singleton '\r'
126 | otherwise = throwIO (augmentIOError e "hGetContents" h)
127 readChunks = do
128 buf <- readIORef haCharBuffer
129 t <- readChunk hh buf `catch` catchError
130 if T.null t
131 then return [t]
132 else (t:) `fmap` readChunks
133 ts <- readChunks
134 (hh', _) <- hClose_help hh
135 return (hh'{haType=ClosedHandle}, T.concat ts)
137-- | Use a more efficient buffer size if we're reading in
138-- block-buffered mode with the default buffer size. When we can
139-- determine the size of the handle we're reading, set the buffer size
140-- to that, so that we can read the entire file in one chunk.
141-- Otherwise, use a buffer size of at least 16KB.
142chooseGoodBuffering :: Handle -> IO ()
143chooseGoodBuffering h = do
144 bufMode <- hGetBuffering h
145 case bufMode of
146 BlockBuffering Nothing -> do
147 d <- catch (liftM2 (-) (hFileSize h) (hTell h)) $ \(e::IOException) ->
148 if ioe_type e == InappropriateType
149 then return 16384 -- faster than the 2KB default
150 else throwIO e
151 when (d > 0) . hSetBuffering h . BlockBuffering . Just . fromIntegral $ d
152 _ -> return ()
153#endif
155-- | Read a single line from a handle.
156hGetLine :: Handle -> IO Text
157#if __GLASGOW_HASKELL__ <= 610
158hGetLine = fmap decodeUtf8 . B.hGetLine
159#else
160hGetLine = hGetLineWith T.concat
161#endif
163-- | Write a string to a handle.
164hPutStr :: Handle -> Text -> IO ()
165#if __GLASGOW_HASKELL__ <= 610
166hPutStr h = B.hPutStr h . encodeUtf8
167#else
168-- This function is lifted almost verbatim from GHC.IO.Handle.Text.
169hPutStr h t = do
170 (buffer_mode, nl) <-
171 wantWritableHandle "hPutStr" h $ \h_ -> do
172 bmode <- getSpareBuffer h_
173 return (bmode, haOutputNL h_)
174 let str = stream t
175 case buffer_mode of
176 (NoBuffering, _) -> hPutChars h str
177 (LineBuffering, buf) -> writeLines h nl buf str
178 (BlockBuffering _, buf)
179 | nl == CRLF -> writeBlocksCRLF h buf str
180 | otherwise -> writeBlocksRaw h buf str
182hPutChars :: Handle -> Stream Char -> IO ()
183hPutChars h (Stream next0 s0 _len) = loop s0
184 where
185 loop !s = case next0 s of
186 Done -> return ()
187 Skip s' -> loop s'
188 Yield x s' -> hPutChar h x >> loop s'
190-- The following functions are largely lifted from GHC.IO.Handle.Text,
191-- but adapted to a coinductive stream of data instead of an inductive
192-- list.
193--
194-- We have several variations of more or less the same code for
195-- performance reasons. Splitting the original buffered write
196-- function into line- and block-oriented versions gave us a 2.1x
197-- performance improvement. Lifting out the raw/cooked newline
198-- handling gave a few more percent on top.
200writeLines :: Handle -> Newline -> Buffer CharBufElem -> Stream Char -> IO ()
201writeLines h nl buf0 (Stream next0 s0 _len) = outer s0 buf0
202 where
203 outer s1 Buffer{bufRaw=raw, bufSize=len} = inner s1 (0::Int)
204 where
205 inner !s !n =
206 case next0 s of
207 Done -> commit n False{-no flush-} True{-release-} >> return ()
208 Skip s' -> inner s' n
209 Yield x s'
210 | n + 1 >= len -> commit n True{-needs flush-} False >>= outer s
211 | x == '\n' -> do
212 n' <- if nl == CRLF
213 then do n1 <- writeCharBuf raw n '\r'
214 writeCharBuf raw n1 '\n'
215 else writeCharBuf raw n x
216 commit n' True{-needs flush-} False >>= outer s'
217 | otherwise -> writeCharBuf raw n x >>= inner s'
218 commit = commitBuffer h raw len
220writeBlocksCRLF :: Handle -> Buffer CharBufElem -> Stream Char -> IO ()
221writeBlocksCRLF h buf0 (Stream next0 s0 _len) = outer s0 buf0
222 where
223 outer s1 Buffer{bufRaw=raw, bufSize=len} = inner s1 (0::Int)
224 where
225 inner !s !n =
226 case next0 s of
227 Done -> commit n False{-no flush-} True{-release-} >> return ()
228 Skip s' -> inner s' n
229 Yield x s'
230 | n + 1 >= len -> commit n True{-needs flush-} False >>= outer s
231 | x == '\n' -> do n1 <- writeCharBuf raw n '\r'
232 writeCharBuf raw n1 '\n' >>= inner s'
233 | otherwise -> writeCharBuf raw n x >>= inner s'
234 commit = commitBuffer h raw len
236writeBlocksRaw :: Handle -> Buffer CharBufElem -> Stream Char -> IO ()
237writeBlocksRaw h buf0 (Stream next0 s0 _len) = outer s0 buf0
238 where
239 outer s1 Buffer{bufRaw=raw, bufSize=len} = inner s1 (0::Int)
240 where
241 inner !s !n =
242 case next0 s of
243 Done -> commit n False{-no flush-} True{-release-} >> return ()
244 Skip s' -> inner s' n
245 Yield x s'
246 | n + 1 >= len -> commit n True{-needs flush-} False >>= outer s
247 | otherwise -> writeCharBuf raw n x >>= inner s'
248 commit = commitBuffer h raw len
250-- This function is completely lifted from GHC.IO.Handle.Text.
251getSpareBuffer :: Handle__ -> IO (BufferMode, CharBuffer)
252getSpareBuffer Handle__{haCharBuffer=ref,
253 haBuffers=spare_ref,
254 haBufferMode=mode}
255 = do
256 case mode of
257 NoBuffering -> return (mode, error "no buffer!")
258 _ -> do
259 bufs <- readIORef spare_ref
260 buf <- readIORef ref
261 case bufs of
262 BufferListCons b rest -> do
263 writeIORef spare_ref rest
264 return ( mode, emptyBuffer b (bufSize buf) WriteBuffer)
265 BufferListNil -> do
266 new_buf <- newCharBuffer (bufSize buf) WriteBuffer
267 return (mode, new_buf)
270-- This function is completely lifted from GHC.IO.Handle.Text.
271commitBuffer :: Handle -> RawCharBuffer -> Int -> Int -> Bool -> Bool
272 -> IO CharBuffer
273commitBuffer hdl !raw !sz !count flush release =
274 wantWritableHandle "commitAndReleaseBuffer" hdl $
275 commitBuffer' raw sz count flush release
276{-# INLINE commitBuffer #-}
277#endif
279-- | Write a string to a handle, followed by a newline.
280hPutStrLn :: Handle -> Text -> IO ()
281hPutStrLn h t = hPutStr h t >> hPutChar h '\n'
283-- | The 'interact' function takes a function of type @Text -> Text@
284-- as its argument. The entire input from the standard input device is
285-- passed to this function as its argument, and the resulting string
286-- is output on the standard output device.
287interact :: (Text -> Text) -> IO ()
288interact f = putStr . f =<< getContents
290-- | Read all user input on 'stdin' as a single string.
291getContents :: IO Text
292getContents = hGetContents stdin
294-- | Read a single line of user input from 'stdin'.
295getLine :: IO Text
296getLine = hGetLine stdin
298-- | Write a string to 'stdout'.
299putStr :: Text -> IO ()
300putStr = hPutStr stdout
302-- | Write a string to 'stdout', followed by a newline.
303putStrLn :: Text -> IO ()
304putStrLn = hPutStrLn stdout
306-- $locale
307--
308-- /Note/: The behaviour of functions in this module depends on the
309-- version of GHC you are using.
310--
311-- Beginning with GHC 6.12, text I\/O is performed using the system or
312-- handle's current locale and line ending conventions.
313--
314-- Under GHC 6.10 and earlier, the system I\/O libraries do not
315-- support locale-sensitive I\/O or line ending conversion. On these
316-- versions of GHC, functions in this library all use UTF-8. What
317-- does this mean in practice?
318--
319-- * All data that is read will be decoded as UTF-8.
320--
321-- * Before data is written, it is first encoded as UTF-8.
322--
323-- * On both reading and writing, the platform's native newline
324-- conversion is performed.
325--
326-- If you must use a non-UTF-8 locale on an older version of GHC, you
327-- will have to perform the transcoding yourself, e.g. as follows:
328--
329-- > import qualified Data.ByteString as B
330-- > import Data.Text (Text)
331-- > import Data.Text.Encoding (encodeUtf16)
332-- >
333-- > putStr_Utf16LE :: Text -> IO ()
334-- > putStr_Utf16LE t = B.putStr (encodeUtf16LE t)