Wolfgang Jeltsch pushed to branch wip/jeltsch/system-io-implementation-into-base at Glasgow Haskell Compiler / GHC

Commits:

9 changed files:

Changes:

  • libraries/base/src/GHC/IO/Handle.hs
    ... ... @@ -53,6 +53,7 @@ module GHC.IO.Handle
    53 53
          hGetEcho,
    
    54 54
          hIsTerminalDevice,
    
    55 55
          hSetNewlineMode,
    
    56
    +     hGetNewlineMode,
    
    56 57
          Newline(..),
    
    57 58
          NewlineMode(..),
    
    58 59
          nativeNewline,
    

  • libraries/base/src/Prelude.hs
    ... ... @@ -165,7 +165,7 @@ module Prelude (
    165 165
       ) where
    
    166 166
     
    
    167 167
     import GHC.Internal.Control.Monad
    
    168
    -import GHC.Internal.System.IO
    
    168
    +import System.IO
    
    169 169
     import GHC.Internal.System.IO.Error
    
    170 170
     import qualified GHC.Internal.Data.List as List
    
    171 171
     import GHC.Internal.Data.Either
    

  • libraries/base/src/System/IO.hs
    1
    -{-# LANGUAGE Safe #-}
    
    1
    +{-# LANGUAGE Trustworthy #-}
    
    2
    +{-# LANGUAGE CPP #-}
    
    2 3
     
    
    3 4
     -- |
    
    4 5
     --
    
    ... ... @@ -184,8 +185,666 @@ module System.IO
    184 185
          nativeNewlineMode
    
    185 186
          ) where
    
    186 187
     
    
    187
    -import GHC.Internal.System.IO
    
    188
    +import GHC.Internal.System.IO (putStrLn, print)
    
    189
    +
    
    190
    +import GHC.Base (Bool (False, True), otherwise, failIO)
    
    191
    +import GHC.Err (errorWithoutStackTrace)
    
    192
    +import GHC.List (null, elem, last, (++), reverse, break)
    
    193
    +import GHC.Num ((+))
    
    194
    +import GHC.IO (IO, FilePath)
    
    195
    +import GHC.IO.IOMode (IOMode (ReadMode, WriteMode, ReadWriteMode, AppendMode))
    
    196
    +import qualified GHC.Internal.IO.FD as FD
    
    197
    +import GHC.IO.Encoding
    
    198
    +       (
    
    199
    +           TextEncoding,
    
    200
    +           mkTextEncoding,
    
    201
    +           getLocaleEncoding,
    
    202
    +           initLocaleEncoding,
    
    203
    +           utf8,
    
    204
    +           utf8_bom,
    
    205
    +           utf16,
    
    206
    +           utf16be,
    
    207
    +           utf16le,
    
    208
    +           utf32,
    
    209
    +           utf32be,
    
    210
    +           utf32le,
    
    211
    +           latin1,
    
    212
    +           char8
    
    213
    +       )
    
    214
    +import GHC.IO.Handle
    
    215
    +       (
    
    216
    +           Handle,
    
    217
    +           hLookAhead,
    
    218
    +           hFlush,
    
    219
    +           hClose,
    
    220
    +           hSetBinaryMode,
    
    221
    +           hSetEncoding,
    
    222
    +           hSetNewlineMode,
    
    223
    +           hSetEcho,
    
    224
    +           hSetFileSize,
    
    225
    +           hGetEncoding,
    
    226
    +           hGetNewlineMode,
    
    227
    +           hGetEcho,
    
    228
    +           hFileSize,
    
    229
    +           hIsOpen,
    
    230
    +           hIsReadable,
    
    231
    +           hIsSeekable,
    
    232
    +           hIsWritable,
    
    233
    +           hIsTerminalDevice,
    
    234
    +           hIsEOF,
    
    235
    +           hIsClosed,
    
    236
    +           hShow,
    
    237
    +           BufferMode (NoBuffering, LineBuffering, BlockBuffering),
    
    238
    +           hSetBuffering,
    
    239
    +           hGetBuffering,
    
    240
    +           HandlePosn,
    
    241
    +           hSetPosn,
    
    242
    +           hGetPosn,
    
    243
    +           SeekMode (AbsoluteSeek, RelativeSeek, SeekFromEnd),
    
    244
    +           hSeek,
    
    245
    +           hTell,
    
    246
    +           Newline (LF, CRLF),
    
    247
    +           nativeNewline,
    
    248
    +           NewlineMode (NewlineMode, inputNL, outputNL),
    
    249
    +           noNewlineTranslation,
    
    250
    +           nativeNewlineMode,
    
    251
    +           universalNewlineMode,
    
    252
    +           isEOF
    
    253
    +       )
    
    254
    +import GHC.IO.Handle.Text
    
    255
    +       (
    
    256
    +           hPutChar,
    
    257
    +           hPutStr,
    
    258
    +           hPutStrLn,
    
    259
    +           hPutBuf,
    
    260
    +           hPutBufNonBlocking,
    
    261
    +           hGetChar,
    
    262
    +           hGetContents,
    
    263
    +           hGetContents',
    
    264
    +           hGetLine,
    
    265
    +           hGetBuf,
    
    266
    +           hGetBufNonBlocking,
    
    267
    +           hGetBufSome,
    
    268
    +           hWaitForInput
    
    269
    +       )
    
    270
    +import qualified GHC.Internal.IO.Handle.FD as POSIX
    
    271
    +import GHC.IO.StdHandles
    
    272
    +       (
    
    273
    +           openBinaryFile,
    
    274
    +           withBinaryFile,
    
    275
    +           openFile,
    
    276
    +           withFile,
    
    277
    +           stdin,
    
    278
    +           stdout,
    
    279
    +           stderr
    
    280
    +       )
    
    281
    +import GHC.IORef (atomicModifyIORef'_)
    
    188 282
     import GHC.Internal.Control.Monad.Fix (fixIO)
    
    283
    +import Control.Monad (return, (>>=))
    
    284
    +import Control.Exception (ioError)
    
    285
    +import Data.Eq ((==))
    
    286
    +import Data.Ord ((<))
    
    287
    +import Data.Bits ((.|.))
    
    288
    +import Data.Function (($), (.))
    
    289
    +import Data.Maybe (Maybe (Nothing, Just))
    
    290
    +import Data.Char (Char)
    
    291
    +import Data.String (String)
    
    292
    +import Data.Int (Int)
    
    293
    +import Data.IORef (IORef, newIORef)
    
    294
    +import System.IO.Error (userError)
    
    295
    +import System.IO.Unsafe (unsafePerformIO)
    
    296
    +import System.Posix.Internals
    
    297
    +       (
    
    298
    +           c_getpid,
    
    299
    +           c_open,
    
    300
    +           o_CREAT,
    
    301
    +           o_EXCL,
    
    302
    +           o_BINARY,
    
    303
    +           o_NONBLOCK,
    
    304
    +           o_RDWR,
    
    305
    +           o_NOCTTY,
    
    306
    +           withFilePath
    
    307
    +       )
    
    308
    +import System.Posix.Types (CMode)
    
    309
    +import Text.Read (lex, Read, reads)
    
    310
    +import Text.Show (Show, show)
    
    311
    +import Foreign.C.Types (CInt)
    
    312
    +import Foreign.C.Error (Errno, eEXIST, getErrno, errnoToIOError)
    
    313
    +
    
    314
    +#if defined(mingw32_HOST_OS)
    
    315
    +import GHC.IO.SubSystem
    
    316
    +import GHC.IO.Windows.Handle (openFileAsTemp)
    
    317
    +import GHC.IO.Handle.Windows (mkHandleFromHANDLE)
    
    318
    +import GHC.IO.Device as IODevice
    
    319
    +import GHC.Internal.Real (fromIntegral)
    
    320
    +import Foreign.C.String
    
    321
    +import Foreign.Ptr
    
    322
    +import Foreign.Marshal.Alloc
    
    323
    +import Foreign.Marshal.Utils (with)
    
    324
    +import Foreign.Storable
    
    325
    +#endif
    
    326
    +
    
    327
    +-----------------------------------------------------------------------------
    
    328
    +-- Standard IO
    
    329
    +
    
    330
    +-- | Write a character to the standard output device
    
    331
    +--
    
    332
    +-- 'putChar' is implemented as @'hPutChar' 'stdout'@.
    
    333
    +--
    
    334
    +-- This operation may fail with the same errors as 'hPutChar'.
    
    335
    +--
    
    336
    +-- ==== __Examples__
    
    337
    +--
    
    338
    +-- Note that the following do not put a newline.
    
    339
    +--
    
    340
    +-- >>> putChar 'x'
    
    341
    +-- x
    
    342
    +--
    
    343
    +-- >>> putChar '\0042'
    
    344
    +-- *
    
    345
    +putChar         :: Char -> IO ()
    
    346
    +putChar c       =  hPutChar stdout c
    
    347
    +
    
    348
    +-- | Write a string to the standard output device
    
    349
    +--
    
    350
    +-- 'putStr' is implemented as @'hPutStr' 'stdout'@.
    
    351
    +--
    
    352
    +-- This operation may fail with the same errors, and has the same issues with concurrency, as 'hPutStr'!
    
    353
    +--
    
    354
    +-- ==== __Examples__
    
    355
    +--
    
    356
    +-- Note that the following do not put a newline.
    
    357
    +--
    
    358
    +-- >>> putStr "Hello, World!"
    
    359
    +-- Hello, World!
    
    360
    +--
    
    361
    +-- >>> putStr "\0052\0042\0050"
    
    362
    +-- 4*2
    
    363
    +--
    
    364
    +putStr          :: String -> IO ()
    
    365
    +putStr s        =  hPutStr stdout s
    
    366
    +
    
    367
    +-- | Read a single character from the standard input device.
    
    368
    +--
    
    369
    +-- 'getChar' is implemented as @'hGetChar' 'stdin'@.
    
    370
    +--
    
    371
    +-- This operation may fail with the same errors as 'hGetChar'.
    
    372
    +--
    
    373
    +-- ==== __Examples__
    
    374
    +--
    
    375
    +-- >>> getChar
    
    376
    +-- a'a'
    
    377
    +--
    
    378
    +-- >>> getChar
    
    379
    +-- >
    
    380
    +-- '\n'
    
    381
    +getChar         :: IO Char
    
    382
    +getChar         =  hGetChar stdin
    
    383
    +
    
    384
    +-- | Read a line from the standard input device.
    
    385
    +--
    
    386
    +-- 'getLine' is implemented as @'hGetLine' 'stdin'@.
    
    387
    +--
    
    388
    +-- This operation may fail with the same errors as 'hGetLine'.
    
    389
    +--
    
    390
    +-- ==== __Examples__
    
    391
    +--
    
    392
    +-- >>> getLine
    
    393
    +-- > Hello World!
    
    394
    +-- "Hello World!"
    
    395
    +--
    
    396
    +-- >>> getLine
    
    397
    +-- >
    
    398
    +-- ""
    
    399
    +getLine         :: IO String
    
    400
    +getLine         =  hGetLine stdin
    
    401
    +
    
    402
    +-- | The 'getContents' operation returns all user input as a single string,
    
    403
    +-- which is read lazily as it is needed.
    
    404
    +--
    
    405
    +-- 'getContents' is implemented as @'hGetContents' 'stdin'@.
    
    406
    +--
    
    407
    +-- This operation may fail with the same errors as 'hGetContents'.
    
    408
    +--
    
    409
    +-- ==== __Examples__
    
    410
    +--
    
    411
    +-- >>> getContents >>= putStr
    
    412
    +-- > aaabbbccc :D
    
    413
    +-- aaabbbccc :D
    
    414
    +-- > I hope you have a great day
    
    415
    +-- I hope you have a great day
    
    416
    +-- > ^D
    
    417
    +--
    
    418
    +-- >>> getContents >>= print . length
    
    419
    +-- > abc
    
    420
    +-- > <3
    
    421
    +-- > def ^D
    
    422
    +-- 11
    
    423
    +getContents     :: IO String
    
    424
    +getContents     =  hGetContents stdin
    
    425
    +
    
    426
    +-- | The 'getContents'' operation returns all user input as a single string,
    
    427
    +-- which is fully read before being returned
    
    428
    +--
    
    429
    +-- 'getContents'' is implemented as @'hGetContents'' 'stdin'@.
    
    430
    +--
    
    431
    +-- This operation may fail with the same errors as 'hGetContents''.
    
    432
    +--
    
    433
    +-- ==== __Examples__
    
    434
    +--
    
    435
    +-- >>> getContents' >>= putStr
    
    436
    +-- > aaabbbccc :D
    
    437
    +-- > I hope you have a great day
    
    438
    +-- aaabbbccc :D
    
    439
    +-- I hope you have a great day
    
    440
    +--
    
    441
    +-- >>> getContents' >>= print . length
    
    442
    +-- > abc
    
    443
    +-- > <3
    
    444
    +-- > def ^D
    
    445
    +-- 11
    
    446
    +--
    
    447
    +-- @since base-4.15.0.0
    
    448
    +getContents'    :: IO String
    
    449
    +getContents'    =  hGetContents' stdin
    
    450
    +
    
    451
    +-- | @'interact' f@ takes the entire input from 'stdin' and applies @f@ to it.
    
    452
    +-- The resulting string is written to the 'stdout' device.
    
    453
    +--
    
    454
    +-- Note that this operation is lazy, which allows to produce output
    
    455
    +-- even before all input has been consumed.
    
    456
    +--
    
    457
    +-- This operation may fail with the same errors as 'getContents' and 'putStr'.
    
    458
    +--
    
    459
    +-- If it doesn't produce output the buffering settings may not be
    
    460
    +-- correct, use ^D (ctrl+D) to close stdin which forces
    
    461
    +-- the buffer to be consumed.
    
    462
    +--
    
    463
    +-- You may wish to set the buffering style appropriate to your program's
    
    464
    +-- needs before using this function, for example:
    
    465
    +--
    
    466
    +-- @
    
    467
    +-- main :: IO ()
    
    468
    +-- main = do
    
    469
    +--   hSetBuffering stdin LineBuffering
    
    470
    +--   hSetBuffering stdout NoBuffering
    
    471
    +--   interact (concatMap (\str -> str ++ str) . L.lines)
    
    472
    +-- @
    
    473
    +--
    
    474
    +-- ==== __Examples__
    
    475
    +--
    
    476
    +-- >>> interact (\str -> str ++ str)
    
    477
    +-- > hi :)
    
    478
    +-- hi :)
    
    479
    +-- > ^D
    
    480
    +-- hi :)
    
    481
    +--
    
    482
    +-- >>> interact (const ":D")
    
    483
    +-- :D
    
    484
    +--
    
    485
    +-- >>> interact (show . words)
    
    486
    +-- > hello world!
    
    487
    +-- > I hope you have a great day
    
    488
    +-- > ^D
    
    489
    +-- ["hello","world!","I","hope","you","have","a","great","day"]
    
    490
    +interact        ::  (String -> String) -> IO ()
    
    491
    +interact f      =   do s <- getContents
    
    492
    +                       putStr (f s)
    
    493
    +
    
    494
    +-- | The 'readFile' function reads a file and
    
    495
    +-- returns the contents of the file as a string.
    
    496
    +--
    
    497
    +-- The file is read lazily, on demand, as with 'getContents'.
    
    498
    +--
    
    499
    +-- This operation may fail with the same errors as 'hGetContents' and 'openFile'.
    
    500
    +--
    
    501
    +-- ==== __Examples__
    
    502
    +--
    
    503
    +-- >>> readFile "~/hello_world"
    
    504
    +-- "Greetings!"
    
    505
    +--
    
    506
    +-- >>> take 5 <$> readFile "/dev/zero"
    
    507
    +-- "\NUL\NUL\NUL\NUL\NUL"
    
    508
    +readFile        :: FilePath -> IO String
    
    509
    +readFile name   =  openFile name ReadMode >>= hGetContents
    
    510
    +
    
    511
    +-- | The 'readFile'' function reads a file and
    
    512
    +-- returns the contents of the file as a string.
    
    513
    +--
    
    514
    +-- This is identical to 'readFile', but the file is fully read before being returned,
    
    515
    +-- as with 'getContents''.
    
    516
    +--
    
    517
    +-- @since base-4.15.0.0
    
    518
    +readFile'       :: FilePath -> IO String
    
    519
    +-- There's a bit of overkill here—both withFile and
    
    520
    +-- hGetContents' will close the file in the end.
    
    521
    +readFile' name  =  withFile name ReadMode hGetContents'
    
    522
    +
    
    523
    +-- | The computation @'writeFile' file str@ function writes the string @str@,
    
    524
    +-- to the file @file@.
    
    525
    +--
    
    526
    +-- This operation may fail with the same errors as 'hPutStr' and 'withFile'.
    
    527
    +--
    
    528
    +-- ==== __Examples__
    
    529
    +--
    
    530
    +-- >>> writeFile "hello" "world" >> readFile "hello"
    
    531
    +-- "world"
    
    532
    +--
    
    533
    +-- >>> writeFile "~/" "D:"
    
    534
    +-- *** Exception: ~/: withFile: inappropriate type (Is a directory)
    
    535
    +writeFile :: FilePath -> String -> IO ()
    
    536
    +writeFile f txt = withFile f WriteMode (\ hdl -> hPutStr hdl txt)
    
    537
    +
    
    538
    +-- | The computation @'appendFile' file str@ function appends the string @str@,
    
    539
    +-- to the file @file@.
    
    540
    +--
    
    541
    +-- Note that 'writeFile' and 'appendFile' write a literal string
    
    542
    +-- to a file.  To write a value of any printable type, as with 'print',
    
    543
    +-- use the 'show' function to convert the value to a string first.
    
    544
    +--
    
    545
    +-- This operation may fail with the same errors as 'hPutStr' and 'withFile'.
    
    546
    +--
    
    547
    +-- ==== __Examples__
    
    548
    +--
    
    549
    +-- The following example could be more efficently written by acquiring a handle
    
    550
    +-- instead with 'openFile' and using the computations capable of writing to handles
    
    551
    +-- such as 'hPutStr'.
    
    552
    +--
    
    553
    +-- >>> let fn = "hello_world"
    
    554
    +-- >>> in writeFile fn "hello" >> appendFile fn " world!" >> (readFile fn >>= putStrLn)
    
    555
    +-- "hello world!"
    
    556
    +--
    
    557
    +-- >>> let fn = "foo"; output = readFile' fn >>= putStrLn
    
    558
    +-- >>> in output >> appendFile fn (show [1,2,3]) >> output
    
    559
    +-- this is what's in the file
    
    560
    +-- this is what's in the file[1,2,3]
    
    561
    +appendFile      :: FilePath -> String -> IO ()
    
    562
    +appendFile f txt = withFile f AppendMode (\ hdl -> hPutStr hdl txt)
    
    563
    +
    
    564
    +-- | The 'readLn' function combines 'getLine' and 'readIO'.
    
    565
    +--
    
    566
    +-- This operation may fail with the same errors as 'getLine' and 'readIO'.
    
    567
    +--
    
    568
    +-- ==== __Examples__
    
    569
    +--
    
    570
    +-- >>> fmap (+ 5) readLn
    
    571
    +-- > 25
    
    572
    +-- 30
    
    573
    +--
    
    574
    +-- >>> readLn :: IO String
    
    575
    +-- > this is not a string literal
    
    576
    +-- *** Exception: user error (Prelude.readIO: no parse)
    
    577
    +readLn :: Read a => IO a
    
    578
    +readLn = getLine >>= readIO
    
    579
    +
    
    580
    +-- | The 'readIO' function is similar to 'read' except that it signals
    
    581
    +-- parse failure to the 'IO' monad instead of terminating the program.
    
    582
    +--
    
    583
    +-- This operation may fail with:
    
    584
    +--
    
    585
    +--  * 'GHC.Internal.System.IO.Error.isUserError' if there is no unambiguous parse.
    
    586
    +--
    
    587
    +-- ==== __Examples__
    
    588
    +--
    
    589
    +-- >>> fmap (+ 1) (readIO "1")
    
    590
    +-- 2
    
    591
    +--
    
    592
    +-- >>> readIO "not quite ()" :: IO ()
    
    593
    +-- *** Exception: user error (Prelude.readIO: no parse)
    
    594
    +readIO          :: Read a => String -> IO a
    
    595
    +readIO s        =  case (do { (x,t) <- reads s ;
    
    596
    +                              ("","") <- lex t ;
    
    597
    +                              return x }) of
    
    598
    +                        [x]    -> return x
    
    599
    +                        []     -> ioError (userError "Prelude.readIO: no parse")
    
    600
    +                        _      -> ioError (userError "Prelude.readIO: ambiguous parse")
    
    601
    +
    
    602
    +-- | The encoding of the current locale.
    
    603
    +--
    
    604
    +-- This is the initial locale encoding: if it has been subsequently changed by
    
    605
    +-- 'GHC.Internal.IO.Encoding.setLocaleEncoding' this value will not reflect that change.
    
    606
    +localeEncoding :: TextEncoding
    
    607
    +localeEncoding = initLocaleEncoding
    
    608
    +
    
    609
    +-- | Computation 'hReady' @hdl@ indicates whether at least one item is
    
    610
    +-- available for input from handle @hdl@.
    
    611
    +--
    
    612
    +-- This operation may fail with:
    
    613
    +--
    
    614
    +--  * 'GHC.Internal.System.IO.Error.isEOFError' if the end of file has been reached.
    
    615
    +hReady          :: Handle -> IO Bool
    
    616
    +hReady h        =  hWaitForInput h 0
    
    617
    +
    
    618
    +-- | Computation 'hPrint' @hdl t@ writes the string representation of @t@
    
    619
    +-- given by the 'show' function to the file or channel managed by @hdl@
    
    620
    +-- and appends a newline.
    
    621
    +--
    
    622
    +-- This operation may fail with the same errors as 'hPutStrLn'
    
    623
    +--
    
    624
    +-- ==== __Examples__
    
    625
    +--
    
    626
    +-- >>> hPrint stdout [1,2,3]
    
    627
    +-- [1,2,3]
    
    628
    +--
    
    629
    +-- >>> hPrint stdin [4,5,6]
    
    630
    +-- *** Exception: <stdin>: hPutStr: illegal operation (handle is not open for writing)
    
    631
    +hPrint          :: Show a => Handle -> a -> IO ()
    
    632
    +hPrint hdl      =  hPutStrLn hdl . show
    
    633
    +
    
    634
    +-- | The function creates a temporary file in ReadWrite mode.
    
    635
    +-- The created file isn\'t deleted automatically, so you need to delete it manually.
    
    636
    +--
    
    637
    +-- The file is created with permissions such that only the current
    
    638
    +-- user can read\/write it.
    
    639
    +--
    
    640
    +-- With some exceptions (see below), the file will be created securely
    
    641
    +-- in the sense that an attacker should not be able to cause
    
    642
    +-- openTempFile to overwrite another file on the filesystem using your
    
    643
    +-- credentials, by putting symbolic links (on Unix) in the place where
    
    644
    +-- the temporary file is to be created.  On Unix the @O_CREAT@ and
    
    645
    +-- @O_EXCL@ flags are used to prevent this attack, but note that
    
    646
    +-- @O_EXCL@ is sometimes not supported on NFS filesystems, so if you
    
    647
    +-- rely on this behaviour it is best to use local filesystems only.
    
    648
    +openTempFile :: FilePath   -- ^ Directory in which to create the file
    
    649
    +             -> String     -- ^ File name template. If the template is \"foo.ext\" then
    
    650
    +                           -- the created file will be \"fooXXX.ext\" where XXX is some
    
    651
    +                           -- random number. Note that this should not contain any path
    
    652
    +                           -- separator characters. On Windows, the template prefix may
    
    653
    +                           -- be truncated to 3 chars, e.g. \"foobar.ext\" will be
    
    654
    +                           -- \"fooXXX.ext\".
    
    655
    +             -> IO (FilePath, Handle)
    
    656
    +openTempFile tmp_dir template
    
    657
    +    = openTempFile' "openTempFile" tmp_dir template False 0o600
    
    658
    +
    
    659
    +-- | Like 'openTempFile', but opens the file in binary mode. See 'openBinaryFile' for more comments.
    
    660
    +openBinaryTempFile :: FilePath -> String -> IO (FilePath, Handle)
    
    661
    +openBinaryTempFile tmp_dir template
    
    662
    +    = openTempFile' "openBinaryTempFile" tmp_dir template True 0o600
    
    663
    +
    
    664
    +-- | Like 'openTempFile', but uses the default file permissions
    
    665
    +openTempFileWithDefaultPermissions :: FilePath -> String
    
    666
    +                                   -> IO (FilePath, Handle)
    
    667
    +openTempFileWithDefaultPermissions tmp_dir template
    
    668
    +    = openTempFile' "openTempFileWithDefaultPermissions" tmp_dir template False 0o666
    
    669
    +
    
    670
    +-- | Like 'openBinaryTempFile', but uses the default file permissions
    
    671
    +openBinaryTempFileWithDefaultPermissions :: FilePath -> String
    
    672
    +                                         -> IO (FilePath, Handle)
    
    673
    +openBinaryTempFileWithDefaultPermissions tmp_dir template
    
    674
    +    = openTempFile' "openBinaryTempFileWithDefaultPermissions" tmp_dir template True 0o666
    
    675
    +
    
    676
    +openTempFile' :: String -> FilePath -> String -> Bool -> CMode
    
    677
    +              -> IO (FilePath, Handle)
    
    678
    +openTempFile' loc tmp_dir template binary mode
    
    679
    +    | pathSeparator template
    
    680
    +    = failIO $ "openTempFile': Template string must not contain path separator characters: "++template
    
    681
    +    | otherwise = findTempName
    
    682
    +  where
    
    683
    +    -- We split off the last extension, so we can use .foo.ext files
    
    684
    +    -- for temporary files (hidden on Unix OSes). Unfortunately we're
    
    685
    +    -- below filepath in the hierarchy here.
    
    686
    +    (prefix, suffix) =
    
    687
    +       case break (== '.') $ reverse template of
    
    688
    +         -- First case: template contains no '.'s. Just re-reverse it.
    
    689
    +         (rev_suffix, "")       -> (reverse rev_suffix, "")
    
    690
    +         -- Second case: template contains at least one '.'. Strip the
    
    691
    +         -- dot from the prefix and prepend it to the suffix (if we don't
    
    692
    +         -- do this, the unique number will get added after the '.' and
    
    693
    +         -- thus be part of the extension, which is wrong.)
    
    694
    +         (rev_suffix, '.':rest) -> (reverse rest, '.':reverse rev_suffix)
    
    695
    +         -- Otherwise, something is wrong, because (break (== '.')) should
    
    696
    +         -- always return a pair with either the empty string or a string
    
    697
    +         -- beginning with '.' as the second component.
    
    698
    +         _                      -> errorWithoutStackTrace "bug in GHC.Internal.System.IO.openTempFile"
    
    699
    +#if defined(mingw32_HOST_OS)
    
    700
    +    findTempName = findTempNamePosix <!> findTempNameWinIO
    
    701
    +
    
    702
    +    findTempNameWinIO = do
    
    703
    +      let label = if null prefix then "ghc" else prefix
    
    704
    +      withCWString tmp_dir $ \c_tmp_dir ->
    
    705
    +        withCWString label $ \c_template ->
    
    706
    +          withCWString suffix $ \c_suffix ->
    
    707
    +            with nullPtr $ \c_ptr -> do
    
    708
    +              res <- c_createUUIDTempFileErrNo c_tmp_dir c_template c_suffix c_ptr
    
    709
    +              if not res
    
    710
    +                 then do errno <- getErrno
    
    711
    +                         ioError (errnoToIOError loc errno Nothing (Just tmp_dir))
    
    712
    +                 else do c_p <- peek c_ptr
    
    713
    +                         filename <- peekCWString c_p
    
    714
    +                         free c_p
    
    715
    +                         let flags = fromIntegral mode .&. o_EXCL
    
    716
    +                         handleResultsWinIO filename (flags == o_EXCL)
    
    717
    +
    
    718
    +    findTempNamePosix = do
    
    719
    +      let label = if null prefix then "ghc" else prefix
    
    720
    +      withCWString tmp_dir $ \c_tmp_dir ->
    
    721
    +        withCWString label $ \c_template ->
    
    722
    +          withCWString suffix $ \c_suffix ->
    
    723
    +            allocaBytes (sizeOf (undefined :: CWchar) * 260) $ \c_str -> do
    
    724
    +            res <- c_getTempFileNameErrorNo c_tmp_dir c_template c_suffix 0
    
    725
    +                                            c_str
    
    726
    +            if not res
    
    727
    +               then do errno <- getErrno
    
    728
    +                       ioError (errnoToIOError loc errno Nothing (Just tmp_dir))
    
    729
    +               else do filename <- peekCWString c_str
    
    730
    +                       handleResultsPosix filename
    
    731
    +
    
    732
    +    handleResultsPosix filename = do
    
    733
    +      let oflags1 = rw_flags .|. o_EXCL
    
    734
    +          binary_flags
    
    735
    +              | binary    = o_BINARY
    
    736
    +              | otherwise = 0
    
    737
    +          oflags = oflags1 .|. binary_flags
    
    738
    +      fd <- withFilePath filename $ \ f -> c_open f oflags mode
    
    739
    +      case fd < 0 of
    
    740
    +        True -> do errno <- getErrno
    
    741
    +                   ioError (errnoToIOError loc errno Nothing (Just tmp_dir))
    
    742
    +        False ->
    
    743
    +          do (fD,fd_type) <- FD.mkFD fd ReadWriteMode Nothing{-no stat-}
    
    744
    +                                     False{-is_socket-}
    
    745
    +                                     True{-is_nonblock-}
    
    746
    +
    
    747
    +             enc <- getLocaleEncoding
    
    748
    +             h <- POSIX.mkHandleFromFD fD fd_type filename ReadWriteMode
    
    749
    +                                 False{-set non-block-} (Just enc)
    
    750
    +
    
    751
    +             return (filename, h)
    
    752
    +
    
    753
    +    handleResultsWinIO filename excl = do
    
    754
    +      (hwnd, hwnd_type) <- openFileAsTemp filename True excl
    
    755
    +      mb_codec <- if binary then return Nothing else fmap Just getLocaleEncoding
    
    756
    +
    
    757
    +      -- then use it to make a Handle
    
    758
    +      h <- mkHandleFromHANDLE hwnd hwnd_type filename ReadWriteMode mb_codec
    
    759
    +                `onException` IODevice.close hwnd
    
    760
    +      return (filename, h)
    
    761
    +
    
    762
    +foreign import ccall "getTempFileNameErrorNo" c_getTempFileNameErrorNo
    
    763
    +  :: CWString -> CWString -> CWString -> CUInt -> Ptr CWchar -> IO Bool
    
    764
    +
    
    765
    +foreign import ccall "__createUUIDTempFileErrNo" c_createUUIDTempFileErrNo
    
    766
    +  :: CWString -> CWString -> CWString -> Ptr CWString -> IO Bool
    
    767
    +
    
    768
    +pathSeparator :: String -> Bool
    
    769
    +pathSeparator template = any (\x-> x == '/' || x == '\\') template
    
    770
    +
    
    771
    +output_flags = std_flags
    
    772
    +#else /* else mingw32_HOST_OS */
    
    773
    +    findTempName = do
    
    774
    +      rs <- rand_string
    
    775
    +      let filename = prefix ++ rs ++ suffix
    
    776
    +          filepath = tmp_dir `combine` filename
    
    777
    +      r <- openNewFile filepath binary mode
    
    778
    +      case r of
    
    779
    +        FileExists -> findTempName
    
    780
    +        OpenNewError errno -> ioError (errnoToIOError loc errno Nothing (Just tmp_dir))
    
    781
    +        NewFileCreated fd -> do
    
    782
    +          (fD,fd_type) <- FD.mkFD fd ReadWriteMode Nothing{-no stat-}
    
    783
    +                               False{-is_socket-}
    
    784
    +                               True{-is_nonblock-}
    
    785
    +
    
    786
    +          enc <- getLocaleEncoding
    
    787
    +          h <- POSIX.mkHandleFromFD fD fd_type filepath ReadWriteMode False{-set non-block-} (Just enc)
    
    788
    +
    
    789
    +          return (filepath, h)
    
    790
    +
    
    791
    +      where
    
    792
    +        -- XXX bits copied from System.FilePath, since that's not available here
    
    793
    +        combine a b
    
    794
    +                  | null b = a
    
    795
    +                  | null a = b
    
    796
    +                  | pathSeparator [last a] = a ++ b
    
    797
    +                  | otherwise = a ++ [pathSeparatorChar] ++ b
    
    798
    +
    
    799
    +tempCounter :: IORef Int
    
    800
    +tempCounter = unsafePerformIO $ newIORef 0
    
    801
    +{-# NOINLINE tempCounter #-}
    
    802
    +
    
    803
    +-- build large digit-alike number
    
    804
    +rand_string :: IO String
    
    805
    +rand_string = do
    
    806
    +  r1 <- c_getpid
    
    807
    +  (r2, _) <- atomicModifyIORef'_ tempCounter (+1)
    
    808
    +  return $ show r1 ++ "-" ++ show r2
    
    809
    +
    
    810
    +data OpenNewFileResult
    
    811
    +  = NewFileCreated CInt
    
    812
    +  | FileExists
    
    813
    +  | OpenNewError Errno
    
    814
    +
    
    815
    +openNewFile :: FilePath -> Bool -> CMode -> IO OpenNewFileResult
    
    816
    +openNewFile filepath binary mode = do
    
    817
    +  let oflags1 = rw_flags .|. o_EXCL
    
    818
    +
    
    819
    +      binary_flags
    
    820
    +        | binary    = o_BINARY
    
    821
    +        | otherwise = 0
    
    822
    +
    
    823
    +      oflags = oflags1 .|. binary_flags
    
    824
    +  fd <- withFilePath filepath $ \ f ->
    
    825
    +          c_open f oflags mode
    
    826
    +  if fd < 0
    
    827
    +    then do
    
    828
    +      errno <- getErrno
    
    829
    +      case errno of
    
    830
    +        _ | errno == eEXIST -> return FileExists
    
    831
    +        _ -> return (OpenNewError errno)
    
    832
    +    else return (NewFileCreated fd)
    
    833
    +
    
    834
    +-- XXX Should use filepath library
    
    835
    +pathSeparatorChar :: Char
    
    836
    +pathSeparatorChar = '/'
    
    837
    +
    
    838
    +pathSeparator :: String -> Bool
    
    839
    +pathSeparator template = pathSeparatorChar `elem` template
    
    840
    +
    
    841
    +output_flags = std_flags    .|. o_CREAT
    
    842
    +#endif /* mingw32_HOST_OS */
    
    843
    +
    
    844
    +-- XXX Copied from GHC.Handle
    
    845
    +std_flags, output_flags, rw_flags :: CInt
    
    846
    +std_flags    = o_NONBLOCK   .|. o_NOCTTY
    
    847
    +rw_flags     = output_flags .|. o_RDWR
    
    189 848
     
    
    190 849
     -- $locking
    
    191 850
     -- Implementations should enforce as far as possible, at least locally to the
    

  • libraries/base/src/Text/Printf.hs
    ... ... @@ -99,7 +99,7 @@ import GHC.Internal.Data.List (stripPrefix)
    99 99
     import GHC.Internal.Word
    
    100 100
     import GHC.Internal.Numeric
    
    101 101
     import GHC.Internal.Numeric.Natural
    
    102
    -import GHC.Internal.System.IO
    
    102
    +import System.IO
    
    103 103
     
    
    104 104
     -- $setup
    
    105 105
     -- >>> import Prelude
    

  • libraries/ghc-internal/src/GHC/Internal/System/IO.hs
    1 1
     {-# LANGUAGE Trustworthy #-}
    
    2
    -{-# LANGUAGE CPP, NoImplicitPrelude, CApiFFI #-}
    
    3
    -{-# OPTIONS_GHC -Wno-x-partial #-}
    
    4 2
     
    
    5 3
     -----------------------------------------------------------------------------
    
    6 4
     -- |
    
    ... ... @@ -16,286 +14,13 @@
    16 14
     --
    
    17 15
     -----------------------------------------------------------------------------
    
    18 16
     
    
    19
    -module GHC.Internal.System.IO (
    
    20
    -    -- * The IO monad
    
    17
    +module GHC.Internal.System.IO (putStrLn, print) where
    
    21 18
     
    
    22
    -    IO,
    
    23
    -
    
    24
    -    -- * Files and handles
    
    25
    -
    
    26
    -    FilePath,
    
    27
    -
    
    28
    -    Handle,             -- abstract, instance of: Eq, Show.
    
    29
    -
    
    30
    -    -- | GHC note: a 'Handle' will be automatically closed when the garbage
    
    31
    -    -- collector detects that it has become unreferenced by the program.
    
    32
    -    -- However, relying on this behaviour is not generally recommended:
    
    33
    -    -- the garbage collector is unpredictable.  If possible, use
    
    34
    -    -- an explicit 'hClose' to close 'Handle's when they are no longer
    
    35
    -    -- required.  GHC does not currently attempt to free up file
    
    36
    -    -- descriptors when they have run out, it is your responsibility to
    
    37
    -    -- ensure that this doesn't happen.
    
    38
    -
    
    39
    -    -- ** Standard handles
    
    40
    -
    
    41
    -    -- | Three handles are allocated during program initialisation,
    
    42
    -    -- and are initially open.
    
    43
    -
    
    44
    -    stdin, stdout, stderr,
    
    45
    -
    
    46
    -    -- * Opening and closing files
    
    47
    -
    
    48
    -    -- ** Opening files
    
    49
    -
    
    50
    -    withFile,
    
    51
    -    openFile,
    
    52
    -    IOMode(ReadMode,WriteMode,AppendMode,ReadWriteMode),
    
    53
    -
    
    54
    -    -- ** Closing files
    
    55
    -
    
    56
    -    hClose,
    
    57
    -
    
    58
    -    -- ** Special cases
    
    59
    -
    
    60
    -    -- | These functions are also exported by the "Prelude".
    
    61
    -
    
    62
    -    readFile,
    
    63
    -    readFile',
    
    64
    -    writeFile,
    
    65
    -    appendFile,
    
    66
    -
    
    67
    -    -- * Operations on handles
    
    68
    -
    
    69
    -    -- ** Determining and changing the size of a file
    
    70
    -
    
    71
    -    hFileSize,
    
    72
    -    hSetFileSize,
    
    73
    -
    
    74
    -    -- ** Detecting the end of input
    
    75
    -
    
    76
    -    hIsEOF,
    
    77
    -    isEOF,
    
    78
    -
    
    79
    -    -- ** Buffering operations
    
    80
    -
    
    81
    -    BufferMode(NoBuffering,LineBuffering,BlockBuffering),
    
    82
    -    hSetBuffering,
    
    83
    -    hGetBuffering,
    
    84
    -    hFlush,
    
    85
    -
    
    86
    -    -- ** Repositioning handles
    
    87
    -
    
    88
    -    hGetPosn,
    
    89
    -    hSetPosn,
    
    90
    -    HandlePosn,                -- abstract, instance of: Eq, Show.
    
    91
    -
    
    92
    -    hSeek,
    
    93
    -    SeekMode(AbsoluteSeek,RelativeSeek,SeekFromEnd),
    
    94
    -    hTell,
    
    95
    -
    
    96
    -    -- ** Handle properties
    
    97
    -
    
    98
    -    hIsOpen, hIsClosed,
    
    99
    -    hIsReadable, hIsWritable,
    
    100
    -    hIsSeekable,
    
    101
    -
    
    102
    -    -- ** Terminal operations (not portable: GHC only)
    
    103
    -
    
    104
    -    hIsTerminalDevice,
    
    105
    -
    
    106
    -    hSetEcho,
    
    107
    -    hGetEcho,
    
    108
    -
    
    109
    -    -- ** Showing handle state (not portable: GHC only)
    
    110
    -
    
    111
    -    hShow,
    
    112
    -
    
    113
    -    -- * Text input and output
    
    114
    -
    
    115
    -    -- ** Text input
    
    116
    -
    
    117
    -    hWaitForInput,
    
    118
    -    hReady,
    
    119
    -    hGetChar,
    
    120
    -    hGetLine,
    
    121
    -    hLookAhead,
    
    122
    -    hGetContents,
    
    123
    -    hGetContents',
    
    124
    -
    
    125
    -    -- ** Text output
    
    126
    -
    
    127
    -    hPutChar,
    
    128
    -    hPutStr,
    
    129
    -    hPutStrLn,
    
    130
    -    hPrint,
    
    131
    -
    
    132
    -    -- ** Special cases for standard input and output
    
    133
    -
    
    134
    -    -- | These functions are also exported by the "Prelude".
    
    135
    -
    
    136
    -    interact,
    
    137
    -    putChar,
    
    138
    -    putStr,
    
    139
    -    putStrLn,
    
    140
    -    print,
    
    141
    -    getChar,
    
    142
    -    getLine,
    
    143
    -    getContents,
    
    144
    -    getContents',
    
    145
    -    readIO,
    
    146
    -    readLn,
    
    147
    -
    
    148
    -    -- * Binary input and output
    
    149
    -
    
    150
    -    withBinaryFile,
    
    151
    -    openBinaryFile,
    
    152
    -    hSetBinaryMode,
    
    153
    -    hPutBuf,
    
    154
    -    hGetBuf,
    
    155
    -    hGetBufSome,
    
    156
    -    hPutBufNonBlocking,
    
    157
    -    hGetBufNonBlocking,
    
    158
    -
    
    159
    -    -- * Temporary files
    
    160
    -
    
    161
    -    openTempFile,
    
    162
    -    openBinaryTempFile,
    
    163
    -    openTempFileWithDefaultPermissions,
    
    164
    -    openBinaryTempFileWithDefaultPermissions,
    
    165
    -
    
    166
    -    -- * Unicode encoding\/decoding
    
    167
    -
    
    168
    -    -- | A text-mode 'Handle' has an associated 'TextEncoding', which
    
    169
    -    -- is used to decode bytes into Unicode characters when reading,
    
    170
    -    -- and encode Unicode characters into bytes when writing.
    
    171
    -    --
    
    172
    -    -- The default 'TextEncoding' is the same as the default encoding
    
    173
    -    -- on your system, which is also available as 'localeEncoding'.
    
    174
    -    -- (GHC note: on Windows, we currently do not support double-byte
    
    175
    -    -- encodings; if the console\'s code page is unsupported, then
    
    176
    -    -- 'localeEncoding' will be 'latin1'.)
    
    177
    -    --
    
    178
    -    -- Encoding and decoding errors are always detected and reported,
    
    179
    -    -- except during lazy I/O ('hGetContents', 'getContents', and
    
    180
    -    -- 'readFile'), where a decoding error merely results in
    
    181
    -    -- termination of the character stream, as with other I/O errors.
    
    182
    -
    
    183
    -    hSetEncoding,
    
    184
    -    hGetEncoding,
    
    185
    -
    
    186
    -    -- ** Unicode encodings
    
    187
    -    TextEncoding,
    
    188
    -    latin1,
    
    189
    -    utf8, utf8_bom,
    
    190
    -    utf16, utf16le, utf16be,
    
    191
    -    utf32, utf32le, utf32be,
    
    192
    -    localeEncoding,
    
    193
    -    char8,
    
    194
    -    mkTextEncoding,
    
    195
    -
    
    196
    -    -- * Newline conversion
    
    197
    -
    
    198
    -    -- | In Haskell, a newline is always represented by the character
    
    199
    -    -- @\'\\n\'@.  However, in files and external character streams, a
    
    200
    -    -- newline may be represented by another character sequence, such
    
    201
    -    -- as @\'\\r\\n\'@.
    
    202
    -    --
    
    203
    -    -- A text-mode 'Handle' has an associated 'NewlineMode' that
    
    204
    -    -- specifies how to translate newline characters.  The
    
    205
    -    -- 'NewlineMode' specifies the input and output translation
    
    206
    -    -- separately, so that for instance you can translate @\'\\r\\n\'@
    
    207
    -    -- to @\'\\n\'@ on input, but leave newlines as @\'\\n\'@ on output.
    
    208
    -    --
    
    209
    -    -- The default 'NewlineMode' for a 'Handle' is
    
    210
    -    -- 'nativeNewlineMode', which does no translation on Unix systems,
    
    211
    -    -- but translates @\'\\r\\n\'@ to @\'\\n\'@ and back on Windows.
    
    212
    -    --
    
    213
    -    -- Binary-mode 'Handle's do no newline translation at all.
    
    214
    -    --
    
    215
    -    hSetNewlineMode,
    
    216
    -    hGetNewlineMode,
    
    217
    -    Newline(..), nativeNewline,
    
    218
    -    NewlineMode(..),
    
    219
    -    noNewlineTranslation, universalNewlineMode, nativeNewlineMode,
    
    220
    -  ) where
    
    221
    -
    
    222
    -import GHC.Internal.Control.Exception.Base
    
    223
    -
    
    224
    -import GHC.Internal.Data.Bits
    
    225
    -import GHC.Internal.Data.Maybe
    
    226
    -import GHC.Internal.Foreign.C.Error
    
    227
    -#if defined(mingw32_HOST_OS)
    
    228
    -import GHC.Internal.Foreign.C.String
    
    229
    -import GHC.Internal.Foreign.Ptr
    
    230
    -import GHC.Internal.Foreign.Marshal.Alloc
    
    231
    -import GHC.Internal.Foreign.Marshal.Utils (with)
    
    232
    -import GHC.Internal.Foreign.Storable
    
    233
    -import GHC.Internal.IO.SubSystem
    
    234
    -import GHC.Internal.IO.Windows.Handle (openFileAsTemp)
    
    235
    -import GHC.Internal.IO.Handle.Windows (mkHandleFromHANDLE)
    
    236
    -import GHC.Internal.IO.Device as IODevice
    
    237
    -import GHC.Internal.Real (fromIntegral)
    
    238
    -#endif
    
    239
    -import GHC.Internal.Foreign.C.Types
    
    240
    -import GHC.Internal.System.Posix.Internals
    
    241
    -import GHC.Internal.System.Posix.Types
    
    242
    -
    
    243
    -import GHC.Internal.Base
    
    244
    -import GHC.Internal.List
    
    245
    -#if !defined(mingw32_HOST_OS)
    
    246
    -import GHC.Internal.IORef
    
    247
    -#endif
    
    248
    -import GHC.Internal.Num
    
    249
    -import GHC.Internal.IO hiding ( bracket, onException )
    
    250
    -import GHC.Internal.IO.IOMode
    
    251
    -import qualified GHC.Internal.IO.FD as FD
    
    252
    -import GHC.Internal.IO.Handle
    
    253
    -import qualified GHC.Internal.IO.Handle.FD as POSIX
    
    254
    -import GHC.Internal.IO.Handle.Text ( hGetBufSome, hPutStrLn )
    
    255
    -import GHC.Internal.IO.Exception ( userError )
    
    256
    -import GHC.Internal.IO.Encoding
    
    257
    -import GHC.Internal.Text.Read
    
    258
    -import GHC.Internal.IO.StdHandles
    
    259
    -import GHC.Internal.Show
    
    260
    ------------------------------------------------------------------------------
    
    261
    --- Standard IO
    
    262
    -
    
    263
    --- | Write a character to the standard output device
    
    264
    ---
    
    265
    --- 'putChar' is implemented as @'hPutChar' 'stdout'@.
    
    266
    ---
    
    267
    --- This operation may fail with the same errors as 'hPutChar'.
    
    268
    ---
    
    269
    --- ==== __Examples__
    
    270
    ---
    
    271
    --- Note that the following do not put a newline.
    
    272
    ---
    
    273
    --- >>> putChar 'x'
    
    274
    --- x
    
    275
    ---
    
    276
    --- >>> putChar '\0042'
    
    277
    --- *
    
    278
    -putChar         :: Char -> IO ()
    
    279
    -putChar c       =  hPutChar stdout c
    
    280
    -
    
    281
    --- | Write a string to the standard output device
    
    282
    ---
    
    283
    --- 'putStr' is implemented as @'hPutStr' 'stdout'@.
    
    284
    ---
    
    285
    --- This operation may fail with the same errors, and has the same issues with concurrency, as 'hPutStr'!
    
    286
    ---
    
    287
    --- ==== __Examples__
    
    288
    ---
    
    289
    --- Note that the following do not put a newline.
    
    290
    ---
    
    291
    --- >>> putStr "Hello, World!"
    
    292
    --- Hello, World!
    
    293
    ---
    
    294
    --- >>> putStr "\0052\0042\0050"
    
    295
    --- 4*2
    
    296
    ---
    
    297
    -putStr          :: String -> IO ()
    
    298
    -putStr s        =  hPutStr stdout s
    
    19
    +import GHC.Internal.Base (String)
    
    20
    +import GHC.Internal.IO (IO)
    
    21
    +import GHC.Internal.IO.Handle.Text (hPutStrLn)
    
    22
    +import GHC.Internal.IO.StdHandles (stdout)
    
    23
    +import GHC.Internal.Show (Show, show)
    
    299 24
     
    
    300 25
     -- | The same as 'putStr', but adds a newline character.
    
    301 26
     --
    
    ... ... @@ -332,485 +57,3 @@ putStrLn s = hPutStrLn stdout s
    332 57
     -- [(0,1),(1,2),(2,4),(3,8),(4,16),(5,32),(6,64),(7,128),(8,256)]
    
    333 58
     print           :: Show a => a -> IO ()
    
    334 59
     print x         =  putStrLn (show x)
    335
    -
    
    336
    --- | Read a single character from the standard input device.
    
    337
    ---
    
    338
    --- 'getChar' is implemented as @'hGetChar' 'stdin'@.
    
    339
    ---
    
    340
    --- This operation may fail with the same errors as 'hGetChar'.
    
    341
    ---
    
    342
    --- ==== __Examples__
    
    343
    ---
    
    344
    --- >>> getChar
    
    345
    --- a'a'
    
    346
    ---
    
    347
    --- >>> getChar
    
    348
    --- >
    
    349
    --- '\n'
    
    350
    -getChar         :: IO Char
    
    351
    -getChar         =  hGetChar stdin
    
    352
    -
    
    353
    --- | Read a line from the standard input device.
    
    354
    ---
    
    355
    --- 'getLine' is implemented as @'hGetLine' 'stdin'@.
    
    356
    ---
    
    357
    --- This operation may fail with the same errors as 'hGetLine'.
    
    358
    ---
    
    359
    --- ==== __Examples__
    
    360
    ---
    
    361
    --- >>> getLine
    
    362
    --- > Hello World!
    
    363
    --- "Hello World!"
    
    364
    ---
    
    365
    --- >>> getLine
    
    366
    --- >
    
    367
    --- ""
    
    368
    -getLine         :: IO String
    
    369
    -getLine         =  hGetLine stdin
    
    370
    -
    
    371
    --- | The 'getContents' operation returns all user input as a single string,
    
    372
    --- which is read lazily as it is needed.
    
    373
    ---
    
    374
    --- 'getContents' is implemented as @'hGetContents' 'stdin'@.
    
    375
    ---
    
    376
    --- This operation may fail with the same errors as 'hGetContents'.
    
    377
    ---
    
    378
    --- ==== __Examples__
    
    379
    ---
    
    380
    --- >>> getContents >>= putStr
    
    381
    --- > aaabbbccc :D
    
    382
    --- aaabbbccc :D
    
    383
    --- > I hope you have a great day
    
    384
    --- I hope you have a great day
    
    385
    --- > ^D
    
    386
    ---
    
    387
    --- >>> getContents >>= print . length
    
    388
    --- > abc
    
    389
    --- > <3
    
    390
    --- > def ^D
    
    391
    --- 11
    
    392
    -getContents     :: IO String
    
    393
    -getContents     =  hGetContents stdin
    
    394
    -
    
    395
    --- | The 'getContents'' operation returns all user input as a single string,
    
    396
    --- which is fully read before being returned
    
    397
    ---
    
    398
    --- 'getContents'' is implemented as @'hGetContents'' 'stdin'@.
    
    399
    ---
    
    400
    --- This operation may fail with the same errors as 'hGetContents''.
    
    401
    ---
    
    402
    --- ==== __Examples__
    
    403
    ---
    
    404
    --- >>> getContents' >>= putStr
    
    405
    --- > aaabbbccc :D
    
    406
    --- > I hope you have a great day
    
    407
    --- aaabbbccc :D
    
    408
    --- I hope you have a great day
    
    409
    ---
    
    410
    --- >>> getContents' >>= print . length
    
    411
    --- > abc
    
    412
    --- > <3
    
    413
    --- > def ^D
    
    414
    --- 11
    
    415
    ---
    
    416
    --- @since base-4.15.0.0
    
    417
    -getContents'    :: IO String
    
    418
    -getContents'    =  hGetContents' stdin
    
    419
    -
    
    420
    --- | @'interact' f@ takes the entire input from 'stdin' and applies @f@ to it.
    
    421
    --- The resulting string is written to the 'stdout' device.
    
    422
    ---
    
    423
    --- Note that this operation is lazy, which allows to produce output
    
    424
    --- even before all input has been consumed.
    
    425
    ---
    
    426
    --- This operation may fail with the same errors as 'getContents' and 'putStr'.
    
    427
    ---
    
    428
    --- If it doesn't produce output the buffering settings may not be
    
    429
    --- correct, use ^D (ctrl+D) to close stdin which forces
    
    430
    --- the buffer to be consumed.
    
    431
    ---
    
    432
    --- You may wish to set the buffering style appropriate to your program's
    
    433
    --- needs before using this function, for example:
    
    434
    ---
    
    435
    --- @
    
    436
    --- main :: IO ()
    
    437
    --- main = do
    
    438
    ---   hSetBuffering stdin LineBuffering
    
    439
    ---   hSetBuffering stdout NoBuffering
    
    440
    ---   interact (concatMap (\str -> str ++ str) . L.lines)
    
    441
    --- @
    
    442
    ---
    
    443
    --- ==== __Examples__
    
    444
    ---
    
    445
    --- >>> interact (\str -> str ++ str)
    
    446
    --- > hi :)
    
    447
    --- hi :)
    
    448
    --- > ^D
    
    449
    --- hi :)
    
    450
    ---
    
    451
    --- >>> interact (const ":D")
    
    452
    --- :D
    
    453
    ---
    
    454
    --- >>> interact (show . words)
    
    455
    --- > hello world!
    
    456
    --- > I hope you have a great day
    
    457
    --- > ^D
    
    458
    --- ["hello","world!","I","hope","you","have","a","great","day"]
    
    459
    -interact        ::  (String -> String) -> IO ()
    
    460
    -interact f      =   do s <- getContents
    
    461
    -                       putStr (f s)
    
    462
    -
    
    463
    --- | The 'readFile' function reads a file and
    
    464
    --- returns the contents of the file as a string.
    
    465
    ---
    
    466
    --- The file is read lazily, on demand, as with 'getContents'.
    
    467
    ---
    
    468
    --- This operation may fail with the same errors as 'hGetContents' and 'openFile'.
    
    469
    ---
    
    470
    --- ==== __Examples__
    
    471
    ---
    
    472
    --- >>> readFile "~/hello_world"
    
    473
    --- "Greetings!"
    
    474
    ---
    
    475
    --- >>> take 5 <$> readFile "/dev/zero"
    
    476
    --- "\NUL\NUL\NUL\NUL\NUL"
    
    477
    -readFile        :: FilePath -> IO String
    
    478
    -readFile name   =  openFile name ReadMode >>= hGetContents
    
    479
    -
    
    480
    --- | The 'readFile'' function reads a file and
    
    481
    --- returns the contents of the file as a string.
    
    482
    ---
    
    483
    --- This is identical to 'readFile', but the file is fully read before being returned,
    
    484
    --- as with 'getContents''.
    
    485
    ---
    
    486
    --- @since base-4.15.0.0
    
    487
    -readFile'       :: FilePath -> IO String
    
    488
    --- There's a bit of overkill here—both withFile and
    
    489
    --- hGetContents' will close the file in the end.
    
    490
    -readFile' name  =  withFile name ReadMode hGetContents'
    
    491
    -
    
    492
    --- | The computation @'writeFile' file str@ function writes the string @str@,
    
    493
    --- to the file @file@.
    
    494
    ---
    
    495
    --- This operation may fail with the same errors as 'hPutStr' and 'withFile'.
    
    496
    ---
    
    497
    --- ==== __Examples__
    
    498
    ---
    
    499
    --- >>> writeFile "hello" "world" >> readFile "hello"
    
    500
    --- "world"
    
    501
    ---
    
    502
    --- >>> writeFile "~/" "D:"
    
    503
    --- *** Exception: ~/: withFile: inappropriate type (Is a directory)
    
    504
    -writeFile :: FilePath -> String -> IO ()
    
    505
    -writeFile f txt = withFile f WriteMode (\ hdl -> hPutStr hdl txt)
    
    506
    -
    
    507
    --- | The computation @'appendFile' file str@ function appends the string @str@,
    
    508
    --- to the file @file@.
    
    509
    ---
    
    510
    --- Note that 'writeFile' and 'appendFile' write a literal string
    
    511
    --- to a file.  To write a value of any printable type, as with 'print',
    
    512
    --- use the 'show' function to convert the value to a string first.
    
    513
    ---
    
    514
    --- This operation may fail with the same errors as 'hPutStr' and 'withFile'.
    
    515
    ---
    
    516
    --- ==== __Examples__
    
    517
    ---
    
    518
    --- The following example could be more efficently written by acquiring a handle
    
    519
    --- instead with 'openFile' and using the computations capable of writing to handles
    
    520
    --- such as 'hPutStr'.
    
    521
    ---
    
    522
    --- >>> let fn = "hello_world"
    
    523
    --- >>> in writeFile fn "hello" >> appendFile fn " world!" >> (readFile fn >>= putStrLn)
    
    524
    --- "hello world!"
    
    525
    ---
    
    526
    --- >>> let fn = "foo"; output = readFile' fn >>= putStrLn
    
    527
    --- >>> in output >> appendFile fn (show [1,2,3]) >> output
    
    528
    --- this is what's in the file
    
    529
    --- this is what's in the file[1,2,3]
    
    530
    -appendFile      :: FilePath -> String -> IO ()
    
    531
    -appendFile f txt = withFile f AppendMode (\ hdl -> hPutStr hdl txt)
    
    532
    -
    
    533
    --- | The 'readLn' function combines 'getLine' and 'readIO'.
    
    534
    ---
    
    535
    --- This operation may fail with the same errors as 'getLine' and 'readIO'.
    
    536
    ---
    
    537
    --- ==== __Examples__
    
    538
    ---
    
    539
    --- >>> fmap (+ 5) readLn
    
    540
    --- > 25
    
    541
    --- 30
    
    542
    ---
    
    543
    --- >>> readLn :: IO String
    
    544
    --- > this is not a string literal
    
    545
    --- *** Exception: user error (Prelude.readIO: no parse)
    
    546
    -readLn :: Read a => IO a
    
    547
    -readLn = getLine >>= readIO
    
    548
    -
    
    549
    --- | The 'readIO' function is similar to 'read' except that it signals
    
    550
    --- parse failure to the 'IO' monad instead of terminating the program.
    
    551
    ---
    
    552
    --- This operation may fail with:
    
    553
    ---
    
    554
    ---  * 'GHC.Internal.System.IO.Error.isUserError' if there is no unambiguous parse.
    
    555
    ---
    
    556
    --- ==== __Examples__
    
    557
    ---
    
    558
    --- >>> fmap (+ 1) (readIO "1")
    
    559
    --- 2
    
    560
    ---
    
    561
    --- >>> readIO "not quite ()" :: IO ()
    
    562
    --- *** Exception: user error (Prelude.readIO: no parse)
    
    563
    -readIO          :: Read a => String -> IO a
    
    564
    -readIO s        =  case (do { (x,t) <- reads s ;
    
    565
    -                              ("","") <- lex t ;
    
    566
    -                              return x }) of
    
    567
    -                        [x]    -> return x
    
    568
    -                        []     -> ioError (userError "Prelude.readIO: no parse")
    
    569
    -                        _      -> ioError (userError "Prelude.readIO: ambiguous parse")
    
    570
    -
    
    571
    --- | The encoding of the current locale.
    
    572
    ---
    
    573
    --- This is the initial locale encoding: if it has been subsequently changed by
    
    574
    --- 'GHC.Internal.IO.Encoding.setLocaleEncoding' this value will not reflect that change.
    
    575
    -localeEncoding :: TextEncoding
    
    576
    -localeEncoding = initLocaleEncoding
    
    577
    -
    
    578
    --- | Computation 'hReady' @hdl@ indicates whether at least one item is
    
    579
    --- available for input from handle @hdl@.
    
    580
    ---
    
    581
    --- This operation may fail with:
    
    582
    ---
    
    583
    ---  * 'GHC.Internal.System.IO.Error.isEOFError' if the end of file has been reached.
    
    584
    -hReady          :: Handle -> IO Bool
    
    585
    -hReady h        =  hWaitForInput h 0
    
    586
    -
    
    587
    --- | Computation 'hPrint' @hdl t@ writes the string representation of @t@
    
    588
    --- given by the 'show' function to the file or channel managed by @hdl@
    
    589
    --- and appends a newline.
    
    590
    ---
    
    591
    --- This operation may fail with the same errors as 'hPutStrLn'
    
    592
    ---
    
    593
    --- ==== __Examples__
    
    594
    ---
    
    595
    --- >>> hPrint stdout [1,2,3]
    
    596
    --- [1,2,3]
    
    597
    ---
    
    598
    --- >>> hPrint stdin [4,5,6]
    
    599
    --- *** Exception: <stdin>: hPutStr: illegal operation (handle is not open for writing)
    
    600
    -hPrint          :: Show a => Handle -> a -> IO ()
    
    601
    -hPrint hdl      =  hPutStrLn hdl . show
    
    602
    -
    
    603
    --- | The function creates a temporary file in ReadWrite mode.
    
    604
    --- The created file isn\'t deleted automatically, so you need to delete it manually.
    
    605
    ---
    
    606
    --- The file is created with permissions such that only the current
    
    607
    --- user can read\/write it.
    
    608
    ---
    
    609
    --- With some exceptions (see below), the file will be created securely
    
    610
    --- in the sense that an attacker should not be able to cause
    
    611
    --- openTempFile to overwrite another file on the filesystem using your
    
    612
    --- credentials, by putting symbolic links (on Unix) in the place where
    
    613
    --- the temporary file is to be created.  On Unix the @O_CREAT@ and
    
    614
    --- @O_EXCL@ flags are used to prevent this attack, but note that
    
    615
    --- @O_EXCL@ is sometimes not supported on NFS filesystems, so if you
    
    616
    --- rely on this behaviour it is best to use local filesystems only.
    
    617
    -openTempFile :: FilePath   -- ^ Directory in which to create the file
    
    618
    -             -> String     -- ^ File name template. If the template is \"foo.ext\" then
    
    619
    -                           -- the created file will be \"fooXXX.ext\" where XXX is some
    
    620
    -                           -- random number. Note that this should not contain any path
    
    621
    -                           -- separator characters. On Windows, the template prefix may
    
    622
    -                           -- be truncated to 3 chars, e.g. \"foobar.ext\" will be
    
    623
    -                           -- \"fooXXX.ext\".
    
    624
    -             -> IO (FilePath, Handle)
    
    625
    -openTempFile tmp_dir template
    
    626
    -    = openTempFile' "openTempFile" tmp_dir template False 0o600
    
    627
    -
    
    628
    --- | Like 'openTempFile', but opens the file in binary mode. See 'openBinaryFile' for more comments.
    
    629
    -openBinaryTempFile :: FilePath -> String -> IO (FilePath, Handle)
    
    630
    -openBinaryTempFile tmp_dir template
    
    631
    -    = openTempFile' "openBinaryTempFile" tmp_dir template True 0o600
    
    632
    -
    
    633
    --- | Like 'openTempFile', but uses the default file permissions
    
    634
    -openTempFileWithDefaultPermissions :: FilePath -> String
    
    635
    -                                   -> IO (FilePath, Handle)
    
    636
    -openTempFileWithDefaultPermissions tmp_dir template
    
    637
    -    = openTempFile' "openTempFileWithDefaultPermissions" tmp_dir template False 0o666
    
    638
    -
    
    639
    --- | Like 'openBinaryTempFile', but uses the default file permissions
    
    640
    -openBinaryTempFileWithDefaultPermissions :: FilePath -> String
    
    641
    -                                         -> IO (FilePath, Handle)
    
    642
    -openBinaryTempFileWithDefaultPermissions tmp_dir template
    
    643
    -    = openTempFile' "openBinaryTempFileWithDefaultPermissions" tmp_dir template True 0o666
    
    644
    -
    
    645
    -openTempFile' :: String -> FilePath -> String -> Bool -> CMode
    
    646
    -              -> IO (FilePath, Handle)
    
    647
    -openTempFile' loc tmp_dir template binary mode
    
    648
    -    | pathSeparator template
    
    649
    -    = failIO $ "openTempFile': Template string must not contain path separator characters: "++template
    
    650
    -    | otherwise = findTempName
    
    651
    -  where
    
    652
    -    -- We split off the last extension, so we can use .foo.ext files
    
    653
    -    -- for temporary files (hidden on Unix OSes). Unfortunately we're
    
    654
    -    -- below filepath in the hierarchy here.
    
    655
    -    (prefix, suffix) =
    
    656
    -       case break (== '.') $ reverse template of
    
    657
    -         -- First case: template contains no '.'s. Just re-reverse it.
    
    658
    -         (rev_suffix, "")       -> (reverse rev_suffix, "")
    
    659
    -         -- Second case: template contains at least one '.'. Strip the
    
    660
    -         -- dot from the prefix and prepend it to the suffix (if we don't
    
    661
    -         -- do this, the unique number will get added after the '.' and
    
    662
    -         -- thus be part of the extension, which is wrong.)
    
    663
    -         (rev_suffix, '.':rest) -> (reverse rest, '.':reverse rev_suffix)
    
    664
    -         -- Otherwise, something is wrong, because (break (== '.')) should
    
    665
    -         -- always return a pair with either the empty string or a string
    
    666
    -         -- beginning with '.' as the second component.
    
    667
    -         _                      -> errorWithoutStackTrace "bug in GHC.Internal.System.IO.openTempFile"
    
    668
    -#if defined(mingw32_HOST_OS)
    
    669
    -    findTempName = findTempNamePosix <!> findTempNameWinIO
    
    670
    -
    
    671
    -    findTempNameWinIO = do
    
    672
    -      let label = if null prefix then "ghc" else prefix
    
    673
    -      withCWString tmp_dir $ \c_tmp_dir ->
    
    674
    -        withCWString label $ \c_template ->
    
    675
    -          withCWString suffix $ \c_suffix ->
    
    676
    -            with nullPtr $ \c_ptr -> do
    
    677
    -              res <- c_createUUIDTempFileErrNo c_tmp_dir c_template c_suffix c_ptr
    
    678
    -              if not res
    
    679
    -                 then do errno <- getErrno
    
    680
    -                         ioError (errnoToIOError loc errno Nothing (Just tmp_dir))
    
    681
    -                 else do c_p <- peek c_ptr
    
    682
    -                         filename <- peekCWString c_p
    
    683
    -                         free c_p
    
    684
    -                         let flags = fromIntegral mode .&. o_EXCL
    
    685
    -                         handleResultsWinIO filename (flags == o_EXCL)
    
    686
    -
    
    687
    -    findTempNamePosix = do
    
    688
    -      let label = if null prefix then "ghc" else prefix
    
    689
    -      withCWString tmp_dir $ \c_tmp_dir ->
    
    690
    -        withCWString label $ \c_template ->
    
    691
    -          withCWString suffix $ \c_suffix ->
    
    692
    -            allocaBytes (sizeOf (undefined :: CWchar) * 260) $ \c_str -> do
    
    693
    -            res <- c_getTempFileNameErrorNo c_tmp_dir c_template c_suffix 0
    
    694
    -                                            c_str
    
    695
    -            if not res
    
    696
    -               then do errno <- getErrno
    
    697
    -                       ioError (errnoToIOError loc errno Nothing (Just tmp_dir))
    
    698
    -               else do filename <- peekCWString c_str
    
    699
    -                       handleResultsPosix filename
    
    700
    -
    
    701
    -    handleResultsPosix filename = do
    
    702
    -      let oflags1 = rw_flags .|. o_EXCL
    
    703
    -          binary_flags
    
    704
    -              | binary    = o_BINARY
    
    705
    -              | otherwise = 0
    
    706
    -          oflags = oflags1 .|. binary_flags
    
    707
    -      fd <- withFilePath filename $ \ f -> c_open f oflags mode
    
    708
    -      case fd < 0 of
    
    709
    -        True -> do errno <- getErrno
    
    710
    -                   ioError (errnoToIOError loc errno Nothing (Just tmp_dir))
    
    711
    -        False ->
    
    712
    -          do (fD,fd_type) <- FD.mkFD fd ReadWriteMode Nothing{-no stat-}
    
    713
    -                                     False{-is_socket-}
    
    714
    -                                     True{-is_nonblock-}
    
    715
    -
    
    716
    -             enc <- getLocaleEncoding
    
    717
    -             h <- POSIX.mkHandleFromFD fD fd_type filename ReadWriteMode
    
    718
    -                                 False{-set non-block-} (Just enc)
    
    719
    -
    
    720
    -             return (filename, h)
    
    721
    -
    
    722
    -    handleResultsWinIO filename excl = do
    
    723
    -      (hwnd, hwnd_type) <- openFileAsTemp filename True excl
    
    724
    -      mb_codec <- if binary then return Nothing else fmap Just getLocaleEncoding
    
    725
    -
    
    726
    -      -- then use it to make a Handle
    
    727
    -      h <- mkHandleFromHANDLE hwnd hwnd_type filename ReadWriteMode mb_codec
    
    728
    -                `onException` IODevice.close hwnd
    
    729
    -      return (filename, h)
    
    730
    -
    
    731
    -foreign import ccall "getTempFileNameErrorNo" c_getTempFileNameErrorNo
    
    732
    -  :: CWString -> CWString -> CWString -> CUInt -> Ptr CWchar -> IO Bool
    
    733
    -
    
    734
    -foreign import ccall "__createUUIDTempFileErrNo" c_createUUIDTempFileErrNo
    
    735
    -  :: CWString -> CWString -> CWString -> Ptr CWString -> IO Bool
    
    736
    -
    
    737
    -pathSeparator :: String -> Bool
    
    738
    -pathSeparator template = any (\x-> x == '/' || x == '\\') template
    
    739
    -
    
    740
    -output_flags = std_flags
    
    741
    -#else /* else mingw32_HOST_OS */
    
    742
    -    findTempName = do
    
    743
    -      rs <- rand_string
    
    744
    -      let filename = prefix ++ rs ++ suffix
    
    745
    -          filepath = tmp_dir `combine` filename
    
    746
    -      r <- openNewFile filepath binary mode
    
    747
    -      case r of
    
    748
    -        FileExists -> findTempName
    
    749
    -        OpenNewError errno -> ioError (errnoToIOError loc errno Nothing (Just tmp_dir))
    
    750
    -        NewFileCreated fd -> do
    
    751
    -          (fD,fd_type) <- FD.mkFD fd ReadWriteMode Nothing{-no stat-}
    
    752
    -                               False{-is_socket-}
    
    753
    -                               True{-is_nonblock-}
    
    754
    -
    
    755
    -          enc <- getLocaleEncoding
    
    756
    -          h <- POSIX.mkHandleFromFD fD fd_type filepath ReadWriteMode False{-set non-block-} (Just enc)
    
    757
    -
    
    758
    -          return (filepath, h)
    
    759
    -
    
    760
    -      where
    
    761
    -        -- XXX bits copied from System.FilePath, since that's not available here
    
    762
    -        combine a b
    
    763
    -                  | null b = a
    
    764
    -                  | null a = b
    
    765
    -                  | pathSeparator [last a] = a ++ b
    
    766
    -                  | otherwise = a ++ [pathSeparatorChar] ++ b
    
    767
    -
    
    768
    -tempCounter :: IORef Int
    
    769
    -tempCounter = unsafePerformIO $ newIORef 0
    
    770
    -{-# NOINLINE tempCounter #-}
    
    771
    -
    
    772
    --- build large digit-alike number
    
    773
    -rand_string :: IO String
    
    774
    -rand_string = do
    
    775
    -  r1 <- c_getpid
    
    776
    -  (r2, _) <- atomicModifyIORef'_ tempCounter (+1)
    
    777
    -  return $ show r1 ++ "-" ++ show r2
    
    778
    -
    
    779
    -data OpenNewFileResult
    
    780
    -  = NewFileCreated CInt
    
    781
    -  | FileExists
    
    782
    -  | OpenNewError Errno
    
    783
    -
    
    784
    -openNewFile :: FilePath -> Bool -> CMode -> IO OpenNewFileResult
    
    785
    -openNewFile filepath binary mode = do
    
    786
    -  let oflags1 = rw_flags .|. o_EXCL
    
    787
    -
    
    788
    -      binary_flags
    
    789
    -        | binary    = o_BINARY
    
    790
    -        | otherwise = 0
    
    791
    -
    
    792
    -      oflags = oflags1 .|. binary_flags
    
    793
    -  fd <- withFilePath filepath $ \ f ->
    
    794
    -          c_open f oflags mode
    
    795
    -  if fd < 0
    
    796
    -    then do
    
    797
    -      errno <- getErrno
    
    798
    -      case errno of
    
    799
    -        _ | errno == eEXIST -> return FileExists
    
    800
    -        _ -> return (OpenNewError errno)
    
    801
    -    else return (NewFileCreated fd)
    
    802
    -
    
    803
    --- XXX Should use filepath library
    
    804
    -pathSeparatorChar :: Char
    
    805
    -pathSeparatorChar = '/'
    
    806
    -
    
    807
    -pathSeparator :: String -> Bool
    
    808
    -pathSeparator template = pathSeparatorChar `elem` template
    
    809
    -
    
    810
    -output_flags = std_flags    .|. o_CREAT
    
    811
    -#endif /* mingw32_HOST_OS */
    
    812
    -
    
    813
    --- XXX Copied from GHC.Handle
    
    814
    -std_flags, output_flags, rw_flags :: CInt
    
    815
    -std_flags    = o_NONBLOCK   .|. o_NOCTTY
    
    816
    -rw_flags     = output_flags .|. o_RDWR

  • testsuite/tests/interface-stability/base-exports.stdout
    ... ... @@ -7848,6 +7848,7 @@ module GHC.IO.Handle where
    7848 7848
       hGetEcho :: Handle -> GHC.Internal.Types.IO GHC.Internal.Types.Bool
    
    7849 7849
       hGetEncoding :: Handle -> GHC.Internal.Types.IO (GHC.Internal.Maybe.Maybe GHC.Internal.IO.Encoding.Types.TextEncoding)
    
    7850 7850
       hGetLine :: Handle -> GHC.Internal.Types.IO GHC.Internal.Base.String
    
    7851
    +  hGetNewlineMode :: Handle -> GHC.Internal.Types.IO NewlineMode
    
    7851 7852
       hGetPosn :: Handle -> GHC.Internal.Types.IO HandlePosn
    
    7852 7853
       hIsClosed :: Handle -> GHC.Internal.Types.IO GHC.Internal.Types.Bool
    
    7853 7854
       hIsEOF :: Handle -> GHC.Internal.Types.IO GHC.Internal.Types.Bool
    
    ... ... @@ -9883,7 +9884,7 @@ module System.Exit where
    9883 9884
       exitWith :: forall a. ExitCode -> GHC.Internal.Types.IO a
    
    9884 9885
     
    
    9885 9886
     module System.IO where
    
    9886
    -  -- Safety: Safe
    
    9887
    +  -- Safety: Trustworthy
    
    9887 9888
       type BufferMode :: *
    
    9888 9889
       data BufferMode = NoBuffering | LineBuffering | BlockBuffering (GHC.Internal.Maybe.Maybe GHC.Internal.Types.Int)
    
    9889 9890
       type FilePath :: *
    

  • testsuite/tests/interface-stability/base-exports.stdout-javascript-unknown-ghcjs
    ... ... @@ -7820,6 +7820,7 @@ module GHC.IO.Handle where
    7820 7820
       hGetEcho :: Handle -> GHC.Internal.Types.IO GHC.Internal.Types.Bool
    
    7821 7821
       hGetEncoding :: Handle -> GHC.Internal.Types.IO (GHC.Internal.Maybe.Maybe GHC.Internal.IO.Encoding.Types.TextEncoding)
    
    7822 7822
       hGetLine :: Handle -> GHC.Internal.Types.IO GHC.Internal.Base.String
    
    7823
    +  hGetNewlineMode :: Handle -> GHC.Internal.Types.IO NewlineMode
    
    7823 7824
       hGetPosn :: Handle -> GHC.Internal.Types.IO HandlePosn
    
    7824 7825
       hIsClosed :: Handle -> GHC.Internal.Types.IO GHC.Internal.Types.Bool
    
    7825 7826
       hIsEOF :: Handle -> GHC.Internal.Types.IO GHC.Internal.Types.Bool
    
    ... ... @@ -9921,7 +9922,7 @@ module System.Exit where
    9921 9922
       exitWith :: forall a. ExitCode -> GHC.Internal.Types.IO a
    
    9922 9923
     
    
    9923 9924
     module System.IO where
    
    9924
    -  -- Safety: Safe
    
    9925
    +  -- Safety: Trustworthy
    
    9925 9926
       type BufferMode :: *
    
    9926 9927
       data BufferMode = NoBuffering | LineBuffering | BlockBuffering (GHC.Internal.Maybe.Maybe GHC.Internal.Types.Int)
    
    9927 9928
       type FilePath :: *
    

  • testsuite/tests/interface-stability/base-exports.stdout-mingw32
    ... ... @@ -8012,6 +8012,7 @@ module GHC.IO.Handle where
    8012 8012
       hGetEcho :: Handle -> GHC.Internal.Types.IO GHC.Internal.Types.Bool
    
    8013 8013
       hGetEncoding :: Handle -> GHC.Internal.Types.IO (GHC.Internal.Maybe.Maybe GHC.Internal.IO.Encoding.Types.TextEncoding)
    
    8014 8014
       hGetLine :: Handle -> GHC.Internal.Types.IO GHC.Internal.Base.String
    
    8015
    +  hGetNewlineMode :: Handle -> GHC.Internal.Types.IO NewlineMode
    
    8015 8016
       hGetPosn :: Handle -> GHC.Internal.Types.IO HandlePosn
    
    8016 8017
       hIsClosed :: Handle -> GHC.Internal.Types.IO GHC.Internal.Types.Bool
    
    8017 8018
       hIsEOF :: Handle -> GHC.Internal.Types.IO GHC.Internal.Types.Bool
    
    ... ... @@ -10163,7 +10164,7 @@ module System.Exit where
    10163 10164
       exitWith :: forall a. ExitCode -> GHC.Internal.Types.IO a
    
    10164 10165
     
    
    10165 10166
     module System.IO where
    
    10166
    -  -- Safety: Safe
    
    10167
    +  -- Safety: Trustworthy
    
    10167 10168
       type BufferMode :: *
    
    10168 10169
       data BufferMode = NoBuffering | LineBuffering | BlockBuffering (GHC.Internal.Maybe.Maybe GHC.Internal.Types.Int)
    
    10169 10170
       type FilePath :: *
    

  • testsuite/tests/interface-stability/base-exports.stdout-ws-32
    ... ... @@ -7848,6 +7848,7 @@ module GHC.IO.Handle where
    7848 7848
       hGetEcho :: Handle -> GHC.Internal.Types.IO GHC.Internal.Types.Bool
    
    7849 7849
       hGetEncoding :: Handle -> GHC.Internal.Types.IO (GHC.Internal.Maybe.Maybe GHC.Internal.IO.Encoding.Types.TextEncoding)
    
    7850 7850
       hGetLine :: Handle -> GHC.Internal.Types.IO GHC.Internal.Base.String
    
    7851
    +  hGetNewlineMode :: Handle -> GHC.Internal.Types.IO NewlineMode
    
    7851 7852
       hGetPosn :: Handle -> GHC.Internal.Types.IO HandlePosn
    
    7852 7853
       hIsClosed :: Handle -> GHC.Internal.Types.IO GHC.Internal.Types.Bool
    
    7853 7854
       hIsEOF :: Handle -> GHC.Internal.Types.IO GHC.Internal.Types.Bool
    
    ... ... @@ -9883,7 +9884,7 @@ module System.Exit where
    9883 9884
       exitWith :: forall a. ExitCode -> GHC.Internal.Types.IO a
    
    9884 9885
     
    
    9885 9886
     module System.IO where
    
    9886
    -  -- Safety: Safe
    
    9887
    +  -- Safety: Trustworthy
    
    9887 9888
       type BufferMode :: *
    
    9888 9889
       data BufferMode = NoBuffering | LineBuffering | BlockBuffering (GHC.Internal.Maybe.Maybe GHC.Internal.Types.Int)
    
    9889 9890
       type FilePath :: *