IO.hs 20.5 KB
Newer Older
1
{-# LANGUAGE Trustworthy #-}
rwbarton's avatar
rwbarton committed
2
{-# LANGUAGE CPP, NoImplicitPrelude, CApiFFI #-}
3

4
-----------------------------------------------------------------------------
5
-- |
6
7
-- Module      :  System.IO
-- Copyright   :  (c) The University of Glasgow 2001
8
-- License     :  BSD-style (see the file libraries/base/LICENSE)
9
--
10
-- Maintainer  :  libraries@haskell.org
11
-- Stability   :  stable
12
13
14
15
16
17
18
-- Portability :  portable
--
-- The standard IO library.
--
-----------------------------------------------------------------------------

module System.IO (
ross's avatar
ross committed
19
20
    -- * The IO monad

21
22
    IO,
    fixIO,
ross's avatar
ross committed
23
24
25

    -- * Files and handles

26
    FilePath,
ross's avatar
ross committed
27

Don Stewart's avatar
Don Stewart committed
28
    Handle,             -- abstract, instance of: Eq, Show.
29

Simon Marlow's avatar
Simon Marlow committed
30
31
32
    -- | GHC note: a 'Handle' will be automatically closed when the garbage
    -- collector detects that it has become unreferenced by the program.
    -- However, relying on this behaviour is not generally recommended:
sol's avatar
sol committed
33
    -- the garbage collector is unpredictable.  If possible, use
Simon Marlow's avatar
Simon Marlow committed
34
35
36
37
38
    -- an explicit 'hClose' to close 'Handle's when they are no longer
    -- required.  GHC does not currently attempt to free up file
    -- descriptors when they have run out, it is your responsibility to
    -- ensure that this doesn't happen.

ross's avatar
ross committed
39
40
41
42
    -- ** Standard handles

    -- | Three handles are allocated during program initialisation,
    -- and are initially open.
43

44
    stdin, stdout, stderr,
45

ross's avatar
ross committed
46
47
48
49
    -- * Opening and closing files

    -- ** Opening files

50
    withFile,
51
    openFile,
ross's avatar
ross committed
52
53
54
55
    IOMode(ReadMode,WriteMode,AppendMode,ReadWriteMode),

    -- ** Closing files

56
    hClose,
ross's avatar
ross committed
57
58
59
60
61

    -- ** Special cases

    -- | These functions are also exported by the "Prelude".

62
63
64
    readFile,
    writeFile,
    appendFile,
ross's avatar
ross committed
65
66
67
68
69
70
71

    -- ** File locking

    -- $locking

    -- * Operations on handles

72
    -- ** Determining and changing the size of a file
ross's avatar
ross committed
73

74
75
    hFileSize,
    hSetFileSize,
ross's avatar
ross committed
76
77
78

    -- ** Detecting the end of input

79
80
    hIsEOF,
    isEOF,
81

ross's avatar
ross committed
82
83
84
    -- ** Buffering operations

    BufferMode(NoBuffering,LineBuffering,BlockBuffering),
85
86
87
    hSetBuffering,
    hGetBuffering,
    hFlush,
ross's avatar
ross committed
88
89
90

    -- ** Repositioning handles

91
92
    hGetPosn,
    hSetPosn,
ross's avatar
ross committed
93
94
    HandlePosn,                -- abstract, instance of: Eq, Show.

95
    hSeek,
ross's avatar
ross committed
96
    SeekMode(AbsoluteSeek,RelativeSeek,SeekFromEnd),
97
    hTell,
ross's avatar
ross committed
98
99
100

    -- ** Handle properties

101
102
103
    hIsOpen, hIsClosed,
    hIsReadable, hIsWritable,
    hIsSeekable,
ross's avatar
ross committed
104

105
    -- ** Terminal operations (not portable: GHC only)
ross's avatar
ross committed
106

107
    hIsTerminalDevice,
ross's avatar
ross committed
108

109
110
    hSetEcho,
    hGetEcho,
ross's avatar
ross committed
111

Simon Marlow's avatar
Simon Marlow committed
112
    -- ** Showing handle state (not portable: GHC only)
ross's avatar
ross committed
113

114
    hShow,
ross's avatar
ross committed
115
116
117
118
119

    -- * Text input and output

    -- ** Text input

120
121
122
123
124
125
    hWaitForInput,
    hReady,
    hGetChar,
    hGetLine,
    hLookAhead,
    hGetContents,
ross's avatar
ross committed
126
127
128

    -- ** Text output

129
130
131
132
    hPutChar,
    hPutStr,
    hPutStrLn,
    hPrint,
133

ross's avatar
ross committed
134
    -- ** Special cases for standard input and output
135

ross's avatar
ross committed
136
    -- | These functions are also exported by the "Prelude".
137

138
139
140
141
142
143
144
145
146
147
    interact,
    putChar,
    putStr,
    putStrLn,
    print,
    getChar,
    getLine,
    getContents,
    readIO,
    readLn,
148

ross's avatar
ross committed
149
150
    -- * Binary input and output

151
    withBinaryFile,
152
153
154
155
156
157
158
    openBinaryFile,
    hSetBinaryMode,
    hPutBuf,
    hGetBuf,
    hGetBufSome,
    hPutBufNonBlocking,
    hGetBufNonBlocking,
159

160
    -- * Temporary files
161
162
163

    openTempFile,
    openBinaryTempFile,
Ian Lynagh's avatar
Ian Lynagh committed
164
165
    openTempFileWithDefaultPermissions,
    openBinaryTempFileWithDefaultPermissions,
166
167
168
169
170
171
172
173
174

    -- * Unicode encoding\/decoding

    -- | A text-mode 'Handle' has an associated 'TextEncoding', which
    -- is used to decode bytes into Unicode characters when reading,
    -- and encode Unicode characters into bytes when writing.
    --
    -- The default 'TextEncoding' is the same as the default encoding
    -- on your system, which is also available as 'localeEncoding'.
175
176
177
    -- (GHC note: on Windows, we currently do not support double-byte
    -- encodings; if the console\'s code page is unsupported, then
    -- 'localeEncoding' will be 'latin1'.)
178
179
180
181
182
183
    --
    -- Encoding and decoding errors are always detected and reported,
    -- except during lazy I/O ('hGetContents', 'getContents', and
    -- 'readFile'), where a decoding error merely results in
    -- termination of the character stream, as with other I/O errors.

184
    hSetEncoding,
185
    hGetEncoding,
186
187

    -- ** Unicode encodings
188
    TextEncoding,
189
    latin1,
Simon Marlow's avatar
Simon Marlow committed
190
    utf8, utf8_bom,
191
    utf16, utf16le, utf16be,
192
    utf32, utf32le, utf32be,
193
    localeEncoding,
194
    char8,
195
196
197
    mkTextEncoding,

    -- * Newline conversion
198

199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
    -- | In Haskell, a newline is always represented by the character
    -- '\n'.  However, in files and external character streams, a
    -- newline may be represented by another character sequence, such
    -- as '\r\n'.
    --
    -- A text-mode 'Handle' has an associated 'NewlineMode' that
    -- specifies how to transate newline characters.  The
    -- 'NewlineMode' specifies the input and output translation
    -- separately, so that for instance you can translate '\r\n'
    -- to '\n' on input, but leave newlines as '\n' on output.
    --
    -- The default 'NewlineMode' for a 'Handle' is
    -- 'nativeNewlineMode', which does no translation on Unix systems,
    -- but translates '\r\n' to '\n' and back on Windows.
    --
    -- Binary-mode 'Handle's do no newline translation at all.
    --
216
217
218
    hSetNewlineMode,
    Newline(..), nativeNewline,
    NewlineMode(..),
219
    noNewlineTranslation, universalNewlineMode, nativeNewlineMode,
220
221
  ) where

222
import Control.Exception.Base
223

224
225
226
import Data.Bits
import Data.Maybe
import Foreign.C.Error
Ben Gamari's avatar
Ben Gamari committed
227
#if defined(mingw32_HOST_OS)
228
import Foreign.C.String
pcapriotti's avatar
pcapriotti committed
229
#endif
Ian Lynagh's avatar
Ian Lynagh committed
230
import Foreign.C.Types
231
import System.Posix.Internals
Ian Lynagh's avatar
Ian Lynagh committed
232
import System.Posix.Types
233

234
import GHC.Base
235
import GHC.List
Ben Gamari's avatar
Ben Gamari committed
236
237
import GHC.IORef
import GHC.Num
238
import GHC.IO hiding ( bracket, onException )
239
240
import GHC.IO.IOMode
import GHC.IO.Handle.FD
241
import qualified GHC.IO.FD as FD
242
import GHC.IO.Handle
243
import GHC.IO.Handle.Text ( hGetBufSome, hPutStrLn )
244
import GHC.IO.Exception ( userError )
245
import GHC.IO.Encoding
Ian Lynagh's avatar
Ian Lynagh committed
246
import Text.Read
247
import GHC.Show
248
import GHC.MVar
249

250
-- -----------------------------------------------------------------------------
251
252
-- Standard IO

ross's avatar
ross committed
253
254
255
-- | Write a character to the standard output device
-- (same as 'hPutChar' 'stdout').

256
257
258
putChar         :: Char -> IO ()
putChar c       =  hPutChar stdout c

ross's avatar
ross committed
259
260
261
-- | Write a string to the standard output device
-- (same as 'hPutStr' 'stdout').

262
263
264
putStr          :: String -> IO ()
putStr s        =  hPutStr stdout s

265
-- | The same as 'putStr', but adds a newline character.
ross's avatar
ross committed
266

267
putStrLn        :: String -> IO ()
268
putStrLn s      =  hPutStrLn stdout s
269

ross's avatar
ross committed
270
271
272
273
274
275
276
277
278
279
280
-- | The 'print' function outputs a value of any printable type to the
-- standard output device.
-- Printable types are those that are instances of class 'Show'; 'print'
-- converts values to strings for output using the 'show' operation and
-- adds a newline.
--
-- For example, a program to print the first 20 integers and their
-- powers of 2 could be written as:
--
-- > main = print ([(n, 2^n) | n <- [0..19]])

281
282
283
print           :: Show a => a -> IO ()
print x         =  putStrLn (show x)

ross's avatar
ross committed
284
285
286
-- | Read a character from the standard input device
-- (same as 'hGetChar' 'stdin').

287
288
289
getChar         :: IO Char
getChar         =  hGetChar stdin

ross's avatar
ross committed
290
291
292
-- | Read a line from the standard input device
-- (same as 'hGetLine' 'stdin').

293
294
295
getLine         :: IO String
getLine         =  hGetLine stdin

ross's avatar
ross committed
296
297
298
299
-- | The 'getContents' operation returns all user input as a single string,
-- which is read lazily as it is needed
-- (same as 'hGetContents' 'stdin').

300
301
302
getContents     :: IO String
getContents     =  hGetContents stdin

ross's avatar
ross committed
303
304
305
306
307
-- | The 'interact' function takes a function of type @String->String@
-- as its argument.  The entire input from the standard input device is
-- passed to this function as its argument, and the resulting string is
-- output on the standard output device.

308
309
310
311
interact        ::  (String -> String) -> IO ()
interact f      =   do s <- getContents
                       putStr (f s)

ross's avatar
ross committed
312
313
314
315
-- | The 'readFile' function reads a file and
-- returns the contents of the file as a string.
-- The file is read lazily, on demand, as with 'getContents'.

316
readFile        :: FilePath -> IO String
Don Stewart's avatar
Don Stewart committed
317
readFile name   =  openFile name ReadMode >>= hGetContents
318

ross's avatar
ross committed
319
320
-- | The computation 'writeFile' @file str@ function writes the string @str@,
-- to the file @file@.
321
writeFile :: FilePath -> String -> IO ()
322
writeFile f txt = withFile f WriteMode (\ hdl -> hPutStr hdl txt)
323

ross's avatar
ross committed
324
325
326
327
328
329
330
331
332
-- | The computation 'appendFile' @file str@ function appends the string @str@,
-- to the file @file@.
--
-- Note that 'writeFile' and 'appendFile' write a literal string
-- to a file.  To write a value of any printable type, as with 'print',
-- use the 'show' function to convert the value to a string first.
--
-- > main = appendFile "squares" (show [(x,x*x) | x <- [0,0.1..2]])

333
appendFile      :: FilePath -> String -> IO ()
334
appendFile f txt = withFile f AppendMode (\ hdl -> hPutStr hdl txt)
335

ross's avatar
ross committed
336
337
-- | The 'readLn' function combines 'getLine' and 'readIO'.

338
339
340
341
342
readLn          :: Read a => IO a
readLn          =  do l <- getLine
                      r <- readIO l
                      return r

ross's avatar
ross committed
343
344
345
-- | The 'readIO' function is similar to 'read' except that it signals
-- parse failure to the 'IO' monad instead of terminating the program.

346
347
readIO          :: Read a => String -> IO a
readIO s        =  case (do { (x,t) <- reads s ;
Don Stewart's avatar
Don Stewart committed
348
                              ("","") <- lex t ;
349
                              return x }) of
Don Stewart's avatar
Don Stewart committed
350
351
352
                        [x]    -> return x
                        []     -> ioError (userError "Prelude.readIO: no parse")
                        _      -> ioError (userError "Prelude.readIO: ambiguous parse")
353
354
355
356
357
358
359

-- | The Unicode encoding of the current locale
--
-- This is the initial locale encoding: if it has been subsequently changed by
-- 'GHC.IO.Encoding.setLocaleEncoding' this value will not reflect that change.
localeEncoding :: TextEncoding
localeEncoding = initLocaleEncoding
360

ross's avatar
ross committed
361
-- | Computation 'hReady' @hdl@ indicates whether at least one item is
ross's avatar
ross committed
362
-- available for input from handle @hdl@.
363
--
ross's avatar
ross committed
364
365
-- This operation may fail with:
--
366
--  * 'System.IO.Error.isEOFError' if the end of file has been reached.
ross's avatar
ross committed
367

Don Stewart's avatar
Don Stewart committed
368
369
hReady          :: Handle -> IO Bool
hReady h        =  hWaitForInput h 0
370

ross's avatar
ross committed
371
372
373
374
375
376
-- | Computation 'hPrint' @hdl t@ writes the string representation of @t@
-- given by the 'shows' function to the file or channel managed by @hdl@
-- and appends a newline.
--
-- This operation may fail with:
--
377
--  * 'System.IO.Error.isFullError' if the device is full; or
ross's avatar
ross committed
378
--
379
--  * 'System.IO.Error.isPermissionError' if another system resource limit would be exceeded.
ross's avatar
ross committed
380

Don Stewart's avatar
Don Stewart committed
381
382
hPrint          :: Show a => Handle -> a -> IO ()
hPrint hdl      =  hPutStrLn hdl . show
383

384
385
386
-- | @'withFile' name mode act@ opens a file using 'openFile' and passes
-- the resulting handle to the computation @act@.  The handle will be
-- closed on exit from 'withFile', whether by normal termination or by
387
388
389
-- raising an exception.  If closing the handle raises an exception, then
-- this exception will be raised by 'withFile' rather than any exception
-- raised by 'act'.
390
391
392
393
394
395
396
397
398
399
withFile :: FilePath -> IOMode -> (Handle -> IO r) -> IO r
withFile name mode = bracket (openFile name mode) hClose

-- | @'withBinaryFile' name mode act@ opens a file using 'openBinaryFile'
-- and passes the resulting handle to the computation @act@.  The handle
-- will be closed on exit from 'withBinaryFile', whether by normal
-- termination or by raising an exception.
withBinaryFile :: FilePath -> IOMode -> (Handle -> IO r) -> IO r
withBinaryFile name mode = bracket (openBinaryFile name mode) hClose

400
401
402
-- ---------------------------------------------------------------------------
-- fixIO

David Feuer's avatar
David Feuer committed
403
404
405
-- | The implementation of 'mfix' for 'IO'. If the function passed
-- to 'fixIO' inspects its argument, the resulting action will throw
-- 'FixIOException'.
406
407
fixIO :: (a -> IO a) -> IO a
fixIO k = do
408
    m <- newEmptyMVar
David Feuer's avatar
David Feuer committed
409
410
411
    ans <- unsafeDupableInterleaveIO
             (readMVar m `catch` \BlockedIndefinitelyOnMVar ->
                                    throwIO FixIOException)
412
    result <- k ans
413
    putMVar m result
414
415
416
417
418
    return result

-- NOTE: we do our own explicit black holing here, because GHC's lazy
-- blackholing isn't enough.  In an infinite loop, GHC may run the IO
-- computation a few times before it notices the loop, which is wrong.
419
420
--
-- NOTE2: the explicit black-holing with an IORef ran into trouble
David Feuer's avatar
David Feuer committed
421
422
423
424
425
426
427
428
429
430
431
432
-- with multiple threads (see #5421), so now we use an MVar. We used
-- to use takeMVar with unsafeInterleaveIO. This, however, uses noDuplicate#,
-- which is not particularly cheap. Better to use readMVar, which can be
-- performed in multiple threads safely, and to use unsafeDupableInterleaveIO
-- to avoid the noDuplicate cost.
--
-- What we'd ideally want is probably an IVar, but we don't quite have those.
-- STM TVars look like an option at first, but I don't think they are:
-- we'd need to be able to write to the variable in an IO context, which can
-- only be done using 'atomically', and 'atomically' is not allowed within
-- unsafePerformIO. We can't know if someone will try to use the result
-- of fixIO with unsafePerformIO!
433
434
435
--
-- See also System.IO.Unsafe.unsafeFixIO.
--
ross's avatar
ross committed
436

437
438
-- | The function creates a temporary file in ReadWrite mode.
-- The created file isn\'t deleted automatically, so you need to delete it manually.
439
--
Ingo Blechschmidt's avatar
Ingo Blechschmidt committed
440
-- The file is created with permissions such that only the current
441
-- user can read\/write it.
442
443
444
445
446
447
448
449
450
451
--
-- With some exceptions (see below), the file will be created securely
-- in the sense that an attacker should not be able to cause
-- openTempFile to overwrite another file on the filesystem using your
-- credentials, by putting symbolic links (on Unix) in the place where
-- the temporary file is to be created.  On Unix the @O_CREAT@ and
-- @O_EXCL@ flags are used to prevent this attack, but note that
-- @O_EXCL@ is sometimes not supported on NFS filesystems, so if you
-- rely on this behaviour it is best to use local filesystems only.
--
452
453
openTempFile :: FilePath   -- ^ Directory in which to create the file
             -> String     -- ^ File name template. If the template is \"foo.ext\" then
454
                           -- the created file will be \"fooXXX.ext\" where XXX is some
455
456
                           -- random number. Note that this should not contain any path
                           -- separator characters.
457
             -> IO (FilePath, Handle)
Ian Lynagh's avatar
Ian Lynagh committed
458
459
openTempFile tmp_dir template
    = openTempFile' "openTempFile" tmp_dir template False 0o600
460
461
462

-- | Like 'openTempFile', but opens the file in binary mode. See 'openBinaryFile' for more comments.
openBinaryTempFile :: FilePath -> String -> IO (FilePath, Handle)
Ian Lynagh's avatar
Ian Lynagh committed
463
464
465
466
467
468
469
openBinaryTempFile tmp_dir template
    = openTempFile' "openBinaryTempFile" tmp_dir template True 0o600

-- | Like 'openTempFile', but uses the default file permissions
openTempFileWithDefaultPermissions :: FilePath -> String
                                   -> IO (FilePath, Handle)
openTempFileWithDefaultPermissions tmp_dir template
470
    = openTempFile' "openTempFileWithDefaultPermissions" tmp_dir template False 0o666
Ian Lynagh's avatar
Ian Lynagh committed
471
472
473
474
475

-- | Like 'openBinaryTempFile', but uses the default file permissions
openBinaryTempFileWithDefaultPermissions :: FilePath -> String
                                         -> IO (FilePath, Handle)
openBinaryTempFileWithDefaultPermissions tmp_dir template
476
    = openTempFile' "openBinaryTempFileWithDefaultPermissions" tmp_dir template True 0o666
Ian Lynagh's avatar
Ian Lynagh committed
477
478
479

openTempFile' :: String -> FilePath -> String -> Bool -> CMode
              -> IO (FilePath, Handle)
480
481
482
483
openTempFile' loc tmp_dir template binary mode
    | pathSeparator `elem` template
    = fail $ "openTempFile': Template string must not contain path separator characters: "++template
    | otherwise = findTempName
484
  where
485
486
487
    -- We split off the last extension, so we can use .foo.ext files
    -- for temporary files (hidden on Unix OSes). Unfortunately we're
    -- below filepath in the hierarchy here.
Don Stewart's avatar
Don Stewart committed
488
    (prefix,suffix) =
489
490
491
492
493
494
495
496
497
498
499
       case break (== '.') $ reverse template of
         -- First case: template contains no '.'s. Just re-reverse it.
         (rev_suffix, "")       -> (reverse rev_suffix, "")
         -- Second case: template contains at least one '.'. Strip the
         -- dot from the prefix and prepend it to the suffix (if we don't
         -- do this, the unique number will get added after the '.' and
         -- thus be part of the extension, which is wrong.)
         (rev_suffix, '.':rest) -> (reverse rest, '.':reverse rev_suffix)
         -- Otherwise, something is wrong, because (break (== '.')) should
         -- always return a pair with either the empty string or a string
         -- beginning with '.' as the second component.
Eric Seidel's avatar
Eric Seidel committed
500
         _                      -> errorWithoutStackTrace "bug in System.IO.openTempFile"
501

502
503
504
505
    findTempName = do
      rs <- rand_string
      let filename = prefix ++ rs ++ suffix
          filepath = tmp_dir `combine` filename
506
507
      r <- openNewFile filepath binary mode
      case r of
508
        FileExists -> findTempName
509
510
511
512
513
514
515
516
517
518
        OpenNewError errno -> ioError (errnoToIOError loc errno Nothing (Just tmp_dir))
        NewFileCreated fd -> do
          (fD,fd_type) <- FD.mkFD fd ReadWriteMode Nothing{-no stat-}
                               False{-is_socket-}
                               True{-is_nonblock-}

          enc <- getLocaleEncoding
          h <- mkHandleFromFD fD fd_type filepath ReadWriteMode False{-set non-block-} (Just enc)

          return (filepath, h)
519

520
      where
521
522
523
524
525
526
527
        -- XXX bits copied from System.FilePath, since that's not available here
        combine a b
                  | null b = a
                  | null a = b
                  | last a == pathSeparator = a ++ b
                  | otherwise = a ++ [pathSeparator] ++ b

Ben Gamari's avatar
Ben Gamari committed
528
529
530
tempCounter :: IORef Int
tempCounter = unsafePerformIO $ newIORef 0
{-# NOINLINE tempCounter #-}
531
532
533
534

-- build large digit-alike number
rand_string :: IO String
rand_string = do
Ben Gamari's avatar
Ben Gamari committed
535
536
537
  r1 <- c_getpid
  r2 <- atomicModifyIORef tempCounter (\n -> (n+1, n))
  return $ show r1 ++ "-" ++ show r2
538

539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
data OpenNewFileResult
  = NewFileCreated CInt
  | FileExists
  | OpenNewError Errno

openNewFile :: FilePath -> Bool -> CMode -> IO OpenNewFileResult
openNewFile filepath binary mode = do
  let oflags1 = rw_flags .|. o_EXCL

      binary_flags
        | binary    = o_BINARY
        | otherwise = 0

      oflags = oflags1 .|. binary_flags
  fd <- withFilePath filepath $ \ f ->
          c_open f oflags mode
  if fd < 0
    then do
      errno <- getErrno
558
559
      case errno of
        _ | errno == eEXIST -> return FileExists
Ben Gamari's avatar
Ben Gamari committed
560
#if defined(mingw32_HOST_OS)
561
562
563
564
565
566
        -- If c_open throws EACCES on windows, it could mean that filepath is a
        -- directory. In this case, we want to return FileExists so that the
        -- enclosing openTempFile can try again instead of failing outright.
        -- See bug #4968.
        _ | errno == eACCES -> do
          withCString filepath $ \path -> do
Austin Seipp's avatar
Austin Seipp committed
567
568
569
570
571
572
573
574
            -- There is a race here: the directory might have been moved or
            -- deleted between the c_open call and the next line, but there
            -- doesn't seem to be any direct way to detect that the c_open call
            -- failed because of an existing directory.
            exists <- c_fileExists path
            return $ if exists
              then FileExists
              else OpenNewError errno
575
#endif
576
        _ -> return (OpenNewError errno)
577
    else return (NewFileCreated fd)
578

Ben Gamari's avatar
Ben Gamari committed
579
#if defined(mingw32_HOST_OS)
580
foreign import ccall "file_exists" c_fileExists :: CString -> IO Bool
581
582
#endif

583
584
-- XXX Should use filepath library
pathSeparator :: Char
Ben Gamari's avatar
Ben Gamari committed
585
#if defined(mingw32_HOST_OS)
586
587
588
589
590
591
pathSeparator = '\\'
#else
pathSeparator = '/'
#endif

-- XXX Copied from GHC.Handle
Ian Lynagh's avatar
Ian Lynagh committed
592
std_flags, output_flags, rw_flags :: CInt
593
594
595
std_flags    = o_NONBLOCK   .|. o_NOCTTY
output_flags = std_flags    .|. o_CREAT
rw_flags     = output_flags .|. o_RDWR
596

ross's avatar
ross committed
597
598
599
-- $locking
-- Implementations should enforce as far as possible, at least locally to the
-- Haskell process, multiple-reader single-writer locking on files.
Simon Marlow's avatar
Simon Marlow committed
600
-- That is, /there may either be many handles on the same file which manage input, or just one handle on the file which manages output/.  If any
ross's avatar
ross committed
601
602
603
604
605
606
607
608
609
610
611
612
-- open or semi-closed handle is managing a file for output, no new
-- handle can be allocated for that file.  If any open or semi-closed
-- handle is managing a file for input, new handles can only be allocated
-- if they do not manage output.  Whether two files are the same is
-- implementation-dependent, but they should normally be the same if they
-- have the same absolute path name and neither has been renamed, for
-- example.
--
-- /Warning/: the 'readFile' operation holds a semi-closed handle on
-- the file until the entire contents of the file have been consumed.
-- It follows that an attempt to write to a file (using 'writeFile', for
-- example) that was earlier opened by 'readFile' will usually result in
613
-- failure with 'System.IO.Error.isAlreadyInUseError'.
dterei's avatar
dterei committed
614