PageRenderTime 104ms CodeModel.GetById 28ms RepoModel.GetById 4ms app.codeStats 1ms

/packages/text-0.11.0.6/Data/Text/Lazy/IO.hs

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