module System.Posix.IO where

import Foreign.C.String ( withCString )
import Foreign.C.Error ( throwErrnoIfMinus1, throwErrnoIfMinus1_ )

import GHC.Handle ( fdToHandle )

import System.Posix.Internals ( c_open, c_close, c_dup2 )
import System.Posix.Types ( Fd(..), FileMode )
import System.IO ( Handle )

import Data.Bits ( (.|.) )


stdOutput :: Fd
stdOutput = Fd 1

stdError :: Fd
stdError = Fd 2

data OpenFileFlags = 
 OpenFileFlags {
  append :: Bool,
  exclusive :: Bool,
  noctty :: Bool,
  nonBlock :: Bool,
  trunc :: Bool
 }


-- Adapted from System.Posix.IO in ghc
#include <fcntl.h>

openFd :: FilePath -> OpenMode -> Maybe FileMode -> OpenFileFlags -> IO Fd
openFd name how maybe_mode off = do
  withCString name $ \s -> do
   fd <- throwErrnoIfMinus1 "openFd" (c_open s all_flags mode_w)
   return (Fd fd)
 where
   all_flags = binary .|. creat .|. flags .|. open_mode
   flags =
    (if append off    then (#const O_APPEND)   else 0) .|.
    (if exclusive off then (#const O_EXCL)     else 0) .|.
    (if trunc off     then (#const O_TRUNC)    else 0)
   binary = (#const O_BINARY)
   (creat, mode_w) = maybe (0,0) (\x->((#const O_CREAT),x)) maybe_mode
   open_mode = case how of
                ReadOnly  -> (#const O_RDONLY)
                WriteOnly -> (#const O_WRONLY)
                ReadWrite -> (#const O_RDWR)

closeFd :: Fd -> IO ()
closeFd (Fd fd) = throwErrnoIfMinus1_ "closeFd" (c_close fd)


fdToHandle :: Fd -> IO Handle
fdToHandle fd = GHC.Handle.fdToHandle (fromIntegral fd)

dupTo :: Fd -> Fd -> IO Fd
dupTo (Fd fd1) (Fd fd2) = do
  r <- throwErrnoIfMinus1 "dupTo" (c_dup2 fd1 fd2)
  return (Fd r)

data OpenMode = ReadOnly | WriteOnly | ReadWrite

defaultFileFlags :: OpenFileFlags
defaultFileFlags = OpenFileFlags False False False False False


