    {-# INCLUDE "HsUnix.h" #-}
    {-# LINE 1 "System/Posix/Terminal.hsc" #-}
    {-# LANGUAGE ForeignFunctionInterface #-}
    {-# LINE 2 "System/Posix/Terminal.hsc" #-}
    {-# OPTIONS_GHC -fno-warn-unused-imports #-}
    -----------------------------------------------------------------------------
    -- |
    -- Module      :  System.Posix.Terminal
    -- Copyright   :  (c) The University of Glasgow 2002
    -- License     :  BSD-style (see the file libraries/base/LICENSE)
    --
    -- Maintainer  :  libraries@haskell.org
    -- Stability   :  provisional
    -- Portability :  non-portable (requires POSIX)
    --
    -- POSIX Terminal support
    --
    -----------------------------------------------------------------------------

    module System.Posix.Terminal (
      -- * Terminal support

      -- ** Terminal attributes
      TerminalAttributes,
      getTerminalAttributes,
      TerminalState(..),
      setTerminalAttributes,

      TerminalMode(..),
      withoutMode,
      withMode,
      terminalMode,
      bitsPerByte,
      withBits,

      ControlCharacter(..),
      controlChar,
      withCC,
      withoutCC,

      inputTime,
      withTime,
      minInput,
      withMinInput,

      BaudRate(..),
      inputSpeed,
      withInputSpeed,
      outputSpeed,
      withOutputSpeed,

      -- ** Terminal operations
      sendBreak,
      drainOutput,
      QueueSelector(..),
      discardData,
      FlowAction(..),
      controlFlow,

      -- ** Process groups
      getTerminalProcessGroupID,
      setTerminalProcessGroupID,

      -- ** Testing a file descriptor
      queryTerminal,
      getTerminalName,
      getControllingTerminalName,

      -- ** Pseudoterminal operations
      openPseudoTerminal,
      getSlaveTerminalName
      ) where

    {-# LINE 72 "System/Posix/Terminal.hsc" #-}

    import Data.Bits
    import Data.Char
    import Foreign.C.Error ( errnoToIOError, throwErrnoIfMinus1,
                             throwErrnoIfMinus1_, throwErrnoIfNull )

    {-# LINE 80 "System/Posix/Terminal.hsc" #-}
    import Foreign.C.String ( CString, peekCString, withCString )
    import Foreign.C.Types ( CInt )
    import Foreign.ForeignPtr ( ForeignPtr, withForeignPtr, mallocForeignPtrBytes )
    import Foreign.Marshal.Alloc ( alloca )
    import Foreign.Marshal.Utils ( copyBytes )
    import Foreign.Ptr ( Ptr, nullPtr, plusPtr )
    import Foreign.Storable ( Storable(..) )
    import System.IO.Error ( ioError )
    import System.IO.Unsafe ( unsafePerformIO )
    import System.Posix.IO ( OpenFileFlags(..), OpenMode(..), defaultFileFlags,
                             openFd )
    import System.Posix.Types

    -- -----------------------------------------------------------------------------
    -- Terminal attributes

    type CTermios = ()
    newtype TerminalAttributes = TerminalAttributes (ForeignPtr CTermios)

    makeTerminalAttributes :: ForeignPtr CTermios -> TerminalAttributes
    makeTerminalAttributes = TerminalAttributes

    withTerminalAttributes :: TerminalAttributes -> (Ptr CTermios -> IO a) -> IO a
    withTerminalAttributes (TerminalAttributes termios) = withForeignPtr termios

    data TerminalMode
    	-- input flags
       = InterruptOnBreak		-- BRKINT
       | MapCRtoLF			-- ICRNL
       | IgnoreBreak		-- IGNBRK
       | IgnoreCR			-- IGNCR
       | IgnoreParityErrors		-- IGNPAR
       | MapLFtoCR			-- INLCR
       | CheckParity		-- INPCK
       | StripHighBit		-- ISTRIP
       | StartStopInput		-- IXOFF
       | StartStopOutput		-- IXON
       | MarkParityErrors		-- PARMRK

    	-- output flags
       | ProcessOutput		-- OPOST
    	-- ToDo: ONLCR, OCRNL, ONOCR, ONLRET, OFILL,
    	--       NLDLY(NL0,NL1), CRDLY(CR0,CR1,CR2,CR2)
    	--	 TABDLY(TAB0,TAB1,TAB2,TAB3)
    	--	 BSDLY(BS0,BS1), VTDLY(VT0,VT1), FFDLY(FF0,FF1)

    	-- control flags
       | LocalMode			-- CLOCAL
       | ReadEnable			-- CREAD
       | TwoStopBits		-- CSTOPB
       | HangupOnClose		-- HUPCL
       | EnableParity		-- PARENB
       | OddParity			-- PARODD

    	-- local modes
       | EnableEcho			-- ECHO
       | EchoErase			-- ECHOE
       | EchoKill			-- ECHOK
       | EchoLF			-- ECHONL
       | ProcessInput		-- ICANON
       | ExtendedFunctions		-- IEXTEN
       | KeyboardInterrupts		-- ISIG
       | NoFlushOnInterrupt		-- NOFLSH
       | BackgroundWriteInterrupt	-- TOSTOP

    withoutMode :: TerminalAttributes -> TerminalMode -> TerminalAttributes
    withoutMode termios InterruptOnBreak = clearInputFlag (2) termios
    {-# LINE 148 "System/Posix/Terminal.hsc" #-}
    withoutMode termios MapCRtoLF = clearInputFlag (256) termios
    {-# LINE 149 "System/Posix/Terminal.hsc" #-}
    withoutMode termios IgnoreBreak = clearInputFlag (1) termios
    {-# LINE 150 "System/Posix/Terminal.hsc" #-}
    withoutMode termios IgnoreCR = clearInputFlag (128) termios
    {-# LINE 151 "System/Posix/Terminal.hsc" #-}
    withoutMode termios IgnoreParityErrors = clearInputFlag (4) termios
    {-# LINE 152 "System/Posix/Terminal.hsc" #-}
    withoutMode termios MapLFtoCR = clearInputFlag (64) termios
    {-# LINE 153 "System/Posix/Terminal.hsc" #-}
    withoutMode termios CheckParity = clearInputFlag (16) termios
    {-# LINE 154 "System/Posix/Terminal.hsc" #-}
    withoutMode termios StripHighBit = clearInputFlag (32) termios
    {-# LINE 155 "System/Posix/Terminal.hsc" #-}
    withoutMode termios StartStopInput = clearInputFlag (1024) termios
    {-# LINE 156 "System/Posix/Terminal.hsc" #-}
    withoutMode termios StartStopOutput = clearInputFlag (512) termios
    {-# LINE 157 "System/Posix/Terminal.hsc" #-}
    withoutMode termios MarkParityErrors = clearInputFlag (8) termios
    {-# LINE 158 "System/Posix/Terminal.hsc" #-}
    withoutMode termios ProcessOutput = clearOutputFlag (1) termios
    {-# LINE 159 "System/Posix/Terminal.hsc" #-}
    withoutMode termios LocalMode = clearControlFlag (32768) termios
    {-# LINE 160 "System/Posix/Terminal.hsc" #-}
    withoutMode termios ReadEnable = clearControlFlag (2048) termios
    {-# LINE 161 "System/Posix/Terminal.hsc" #-}
    withoutMode termios TwoStopBits = clearControlFlag (1024) termios
    {-# LINE 162 "System/Posix/Terminal.hsc" #-}
    withoutMode termios HangupOnClose = clearControlFlag (16384) termios
    {-# LINE 163 "System/Posix/Terminal.hsc" #-}
    withoutMode termios EnableParity = clearControlFlag (4096) termios
    {-# LINE 164 "System/Posix/Terminal.hsc" #-}
    withoutMode termios OddParity = clearControlFlag (8192) termios
    {-# LINE 165 "System/Posix/Terminal.hsc" #-}
    withoutMode termios EnableEcho = clearLocalFlag (8) termios
    {-# LINE 166 "System/Posix/Terminal.hsc" #-}
    withoutMode termios EchoErase = clearLocalFlag (2) termios
    {-# LINE 167 "System/Posix/Terminal.hsc" #-}
    withoutMode termios EchoKill = clearLocalFlag (4) termios
    {-# LINE 168 "System/Posix/Terminal.hsc" #-}
    withoutMode termios EchoLF = clearLocalFlag (16) termios
    {-# LINE 169 "System/Posix/Terminal.hsc" #-}
    withoutMode termios ProcessInput = clearLocalFlag (256) termios
    {-# LINE 170 "System/Posix/Terminal.hsc" #-}
    withoutMode termios ExtendedFunctions = clearLocalFlag (1024) termios
    {-# LINE 171 "System/Posix/Terminal.hsc" #-}
    withoutMode termios KeyboardInterrupts = clearLocalFlag (128) termios
    {-# LINE 172 "System/Posix/Terminal.hsc" #-}
    withoutMode termios NoFlushOnInterrupt = setLocalFlag (2147483648) termios
    {-# LINE 173 "System/Posix/Terminal.hsc" #-}
    withoutMode termios BackgroundWriteInterrupt = clearLocalFlag (4194304) termios
    {-# LINE 174 "System/Posix/Terminal.hsc" #-}

    withMode :: TerminalAttributes -> TerminalMode -> TerminalAttributes
    withMode termios InterruptOnBreak = setInputFlag (2) termios
    {-# LINE 177 "System/Posix/Terminal.hsc" #-}
    withMode termios MapCRtoLF = setInputFlag (256) termios
    {-# LINE 178 "System/Posix/Terminal.hsc" #-}
    withMode termios IgnoreBreak = setInputFlag (1) termios
    {-# LINE 179 "System/Posix/Terminal.hsc" #-}
    withMode termios IgnoreCR = setInputFlag (128) termios
    {-# LINE 180 "System/Posix/Terminal.hsc" #-}
    withMode termios IgnoreParityErrors = setInputFlag (4) termios
    {-# LINE 181 "System/Posix/Terminal.hsc" #-}
    withMode termios MapLFtoCR = setInputFlag (64) termios
    {-# LINE 182 "System/Posix/Terminal.hsc" #-}
    withMode termios CheckParity = setInputFlag (16) termios
    {-# LINE 183 "System/Posix/Terminal.hsc" #-}
    withMode termios StripHighBit = setInputFlag (32) termios
    {-# LINE 184 "System/Posix/Terminal.hsc" #-}
    withMode termios StartStopInput = setInputFlag (1024) termios
    {-# LINE 185 "System/Posix/Terminal.hsc" #-}
    withMode termios StartStopOutput = setInputFlag (512) termios
    {-# LINE 186 "System/Posix/Terminal.hsc" #-}
    withMode termios MarkParityErrors = setInputFlag (8) termios
    {-# LINE 187 "System/Posix/Terminal.hsc" #-}
    withMode termios ProcessOutput = setOutputFlag (1) termios
    {-# LINE 188 "System/Posix/Terminal.hsc" #-}
    withMode termios LocalMode = setControlFlag (32768) termios
    {-# LINE 189 "System/Posix/Terminal.hsc" #-}
    withMode termios ReadEnable = setControlFlag (2048) termios
    {-# LINE 190 "System/Posix/Terminal.hsc" #-}
    withMode termios TwoStopBits = setControlFlag (1024) termios
    {-# LINE 191 "System/Posix/Terminal.hsc" #-}
    withMode termios HangupOnClose = setControlFlag (16384) termios
    {-# LINE 192 "System/Posix/Terminal.hsc" #-}
    withMode termios EnableParity = setControlFlag (4096) termios
    {-# LINE 193 "System/Posix/Terminal.hsc" #-}
    withMode termios OddParity = setControlFlag (8192) termios
    {-# LINE 194 "System/Posix/Terminal.hsc" #-}
    withMode termios EnableEcho = setLocalFlag (8) termios
    {-# LINE 195 "System/Posix/Terminal.hsc" #-}
    withMode termios EchoErase = setLocalFlag (2) termios
    {-# LINE 196 "System/Posix/Terminal.hsc" #-}
    withMode termios EchoKill = setLocalFlag (4) termios
    {-# LINE 197 "System/Posix/Terminal.hsc" #-}
    withMode termios EchoLF = setLocalFlag (16) termios
    {-# LINE 198 "System/Posix/Terminal.hsc" #-}
    withMode termios ProcessInput = setLocalFlag (256) termios
    {-# LINE 199 "System/Posix/Terminal.hsc" #-}
    withMode termios ExtendedFunctions = setLocalFlag (1024) termios
    {-# LINE 200 "System/Posix/Terminal.hsc" #-}
    withMode termios KeyboardInterrupts = setLocalFlag (128) termios
    {-# LINE 201 "System/Posix/Terminal.hsc" #-}
    withMode termios NoFlushOnInterrupt = clearLocalFlag (2147483648) termios
    {-# LINE 202 "System/Posix/Terminal.hsc" #-}
    withMode termios BackgroundWriteInterrupt = setLocalFlag (4194304) termios
    {-# LINE 203 "System/Posix/Terminal.hsc" #-}

    terminalMode :: TerminalMode -> TerminalAttributes -> Bool
    terminalMode InterruptOnBreak = testInputFlag (2)
    {-# LINE 206 "System/Posix/Terminal.hsc" #-}
    terminalMode MapCRtoLF = testInputFlag (256)
    {-# LINE 207 "System/Posix/Terminal.hsc" #-}
    terminalMode IgnoreBreak = testInputFlag (1)
    {-# LINE 208 "System/Posix/Terminal.hsc" #-}
    terminalMode IgnoreCR = testInputFlag (128)
    {-# LINE 209 "System/Posix/Terminal.hsc" #-}
    terminalMode IgnoreParityErrors = testInputFlag (4)
    {-# LINE 210 "System/Posix/Terminal.hsc" #-}
    terminalMode MapLFtoCR = testInputFlag (64)
    {-# LINE 211 "System/Posix/Terminal.hsc" #-}
    terminalMode CheckParity = testInputFlag (16)
    {-# LINE 212 "System/Posix/Terminal.hsc" #-}
    terminalMode StripHighBit = testInputFlag (32)
    {-# LINE 213 "System/Posix/Terminal.hsc" #-}
    terminalMode StartStopInput = testInputFlag (1024)
    {-# LINE 214 "System/Posix/Terminal.hsc" #-}
    terminalMode StartStopOutput = testInputFlag (512)
    {-# LINE 215 "System/Posix/Terminal.hsc" #-}
    terminalMode MarkParityErrors = testInputFlag (8)
    {-# LINE 216 "System/Posix/Terminal.hsc" #-}
    terminalMode ProcessOutput = testOutputFlag (1)
    {-# LINE 217 "System/Posix/Terminal.hsc" #-}
    terminalMode LocalMode = testControlFlag (32768)
    {-# LINE 218 "System/Posix/Terminal.hsc" #-}
    terminalMode ReadEnable = testControlFlag (2048)
    {-# LINE 219 "System/Posix/Terminal.hsc" #-}
    terminalMode TwoStopBits = testControlFlag (1024)
    {-# LINE 220 "System/Posix/Terminal.hsc" #-}
    terminalMode HangupOnClose = testControlFlag (16384)
    {-# LINE 221 "System/Posix/Terminal.hsc" #-}
    terminalMode EnableParity = testControlFlag (4096)
    {-# LINE 222 "System/Posix/Terminal.hsc" #-}
    terminalMode OddParity = testControlFlag (8192)
    {-# LINE 223 "System/Posix/Terminal.hsc" #-}
    terminalMode EnableEcho = testLocalFlag (8)
    {-# LINE 224 "System/Posix/Terminal.hsc" #-}
    terminalMode EchoErase = testLocalFlag (2)
    {-# LINE 225 "System/Posix/Terminal.hsc" #-}
    terminalMode EchoKill = testLocalFlag (4)
    {-# LINE 226 "System/Posix/Terminal.hsc" #-}
    terminalMode EchoLF = testLocalFlag (16)
    {-# LINE 227 "System/Posix/Terminal.hsc" #-}
    terminalMode ProcessInput = testLocalFlag (256)
    {-# LINE 228 "System/Posix/Terminal.hsc" #-}
    terminalMode ExtendedFunctions = testLocalFlag (1024)
    {-# LINE 229 "System/Posix/Terminal.hsc" #-}
    terminalMode KeyboardInterrupts = testLocalFlag (128)
    {-# LINE 230 "System/Posix/Terminal.hsc" #-}
    terminalMode NoFlushOnInterrupt = not . testLocalFlag (2147483648)
    {-# LINE 231 "System/Posix/Terminal.hsc" #-}
    terminalMode BackgroundWriteInterrupt = testLocalFlag (4194304)
    {-# LINE 232 "System/Posix/Terminal.hsc" #-}

    bitsPerByte :: TerminalAttributes -> Int
    bitsPerByte termios = unsafePerformIO $ do
      withTerminalAttributes termios $ \p -> do
        cflag <- ((\hsc_ptr -> peekByteOff hsc_ptr 8)) p
    {-# LINE 237 "System/Posix/Terminal.hsc" #-}
        return $! (word2Bits (cflag .&. (768)))
    {-# LINE 238 "System/Posix/Terminal.hsc" #-}
      where
        word2Bits :: CTcflag -> Int
        word2Bits x =
    	if x == (0) then 5
    {-# LINE 242 "System/Posix/Terminal.hsc" #-}
    	else if x == (256) then 6
    {-# LINE 243 "System/Posix/Terminal.hsc" #-}
    	else if x == (512) then 7
    {-# LINE 244 "System/Posix/Terminal.hsc" #-}
    	else if x == (768) then 8
    {-# LINE 245 "System/Posix/Terminal.hsc" #-}
    	else 0

    withBits :: TerminalAttributes -> Int -> TerminalAttributes
    withBits termios bits = unsafePerformIO $ do
      withNewTermios termios $ \p -> do
        cflag <- ((\hsc_ptr -> peekByteOff hsc_ptr 8)) p
    {-# LINE 251 "System/Posix/Terminal.hsc" #-}
        ((\hsc_ptr -> pokeByteOff hsc_ptr 8)) p
    {-# LINE 252 "System/Posix/Terminal.hsc" #-}
           ((cflag .&. complement (768)) .|. mask bits)
    {-# LINE 253 "System/Posix/Terminal.hsc" #-}
      where
        mask :: Int -> CTcflag
        mask 5 = (0)
    {-# LINE 256 "System/Posix/Terminal.hsc" #-}
        mask 6 = (256)
    {-# LINE 257 "System/Posix/Terminal.hsc" #-}
        mask 7 = (512)
    {-# LINE 258 "System/Posix/Terminal.hsc" #-}
        mask 8 = (768)
    {-# LINE 259 "System/Posix/Terminal.hsc" #-}
        mask _ = error "withBits bit value out of range [5..8]"

    data ControlCharacter
      = EndOfFile		-- VEOF
      | EndOfLine		-- VEOL
      | Erase		-- VERASE
      | Interrupt		-- VINTR
      | Kill		-- VKILL
      | Quit		-- VQUIT
      | Start		-- VSTART
      | Stop		-- VSTOP
      | Suspend		-- VSUSP

    controlChar :: TerminalAttributes -> ControlCharacter -> Maybe Char
    controlChar termios cc = unsafePerformIO $ do
      withTerminalAttributes termios $ \p -> do
        let c_cc = ((\hsc_ptr -> hsc_ptr `plusPtr` 16)) p
    {-# LINE 276 "System/Posix/Terminal.hsc" #-}
        val <- peekElemOff c_cc (cc2Word cc)
        if val == ((255)::CCc)
    {-# LINE 278 "System/Posix/Terminal.hsc" #-}
           then return Nothing
           else return (Just (chr (fromEnum val)))

    withCC :: TerminalAttributes
           -> (ControlCharacter, Char)
           -> TerminalAttributes
    withCC termios (cc, c) = unsafePerformIO $ do
      withNewTermios termios $ \p -> do
        let c_cc = ((\hsc_ptr -> hsc_ptr `plusPtr` 16)) p
    {-# LINE 287 "System/Posix/Terminal.hsc" #-}
        pokeElemOff c_cc (cc2Word cc) (fromIntegral (ord c) :: CCc)

    withoutCC :: TerminalAttributes
              -> ControlCharacter
              -> TerminalAttributes
    withoutCC termios cc = unsafePerformIO $ do
      withNewTermios termios $ \p -> do
        let c_cc = ((\hsc_ptr -> hsc_ptr `plusPtr` 16)) p
    {-# LINE 295 "System/Posix/Terminal.hsc" #-}
        pokeElemOff c_cc (cc2Word cc) ((255) :: CCc)
    {-# LINE 296 "System/Posix/Terminal.hsc" #-}

    inputTime :: TerminalAttributes -> Int
    inputTime termios = unsafePerformIO $ do
      withTerminalAttributes termios $ \p -> do
        c <- peekElemOff (((\hsc_ptr -> hsc_ptr `plusPtr` 16)) p) (17)
    {-# LINE 301 "System/Posix/Terminal.hsc" #-}
        return (fromEnum (c :: CCc))

    withTime :: TerminalAttributes -> Int -> TerminalAttributes
    withTime termios time = unsafePerformIO $ do
      withNewTermios termios $ \p -> do
        let c_cc = ((\hsc_ptr -> hsc_ptr `plusPtr` 16)) p
    {-# LINE 307 "System/Posix/Terminal.hsc" #-}
        pokeElemOff c_cc (17) (fromIntegral time :: CCc)
    {-# LINE 308 "System/Posix/Terminal.hsc" #-}

    minInput :: TerminalAttributes -> Int
    minInput termios = unsafePerformIO $ do
      withTerminalAttributes termios $ \p -> do
        c <- peekElemOff (((\hsc_ptr -> hsc_ptr `plusPtr` 16)) p) (16)
    {-# LINE 313 "System/Posix/Terminal.hsc" #-}
        return (fromEnum (c :: CCc))

    withMinInput :: TerminalAttributes -> Int -> TerminalAttributes
    withMinInput termios count = unsafePerformIO $ do
      withNewTermios termios $ \p -> do
        let c_cc = ((\hsc_ptr -> hsc_ptr `plusPtr` 16)) p
    {-# LINE 319 "System/Posix/Terminal.hsc" #-}
        pokeElemOff c_cc (16) (fromIntegral count :: CCc)
    {-# LINE 320 "System/Posix/Terminal.hsc" #-}

    data BaudRate
      = B0
      | B50
      | B75
      | B110
      | B134
      | B150
      | B200
      | B300
      | B600
      | B1200
      | B1800
      | B2400
      | B4800
      | B9600
      | B19200
      | B38400
      | B57600
      | B115200

    inputSpeed :: TerminalAttributes -> BaudRate
    inputSpeed termios = unsafePerformIO $ do
      withTerminalAttributes termios $ \p -> do
        w <- c_cfgetispeed p
        return (word2Baud w)

    foreign import ccall unsafe "cfgetispeed"
      c_cfgetispeed :: Ptr CTermios -> IO CSpeed

    withInputSpeed :: TerminalAttributes -> BaudRate -> TerminalAttributes
    withInputSpeed termios br = unsafePerformIO $ do
      withNewTermios termios $ \p -> c_cfsetispeed p (baud2Word br)

    foreign import ccall unsafe "cfsetispeed"
      c_cfsetispeed :: Ptr CTermios -> CSpeed -> IO CInt

    outputSpeed :: TerminalAttributes -> BaudRate
    outputSpeed termios = unsafePerformIO $ do
      withTerminalAttributes termios $ \p ->  do
        w <- c_cfgetospeed p
        return (word2Baud w)

    foreign import ccall unsafe "cfgetospeed"
      c_cfgetospeed :: Ptr CTermios -> IO CSpeed

    withOutputSpeed :: TerminalAttributes -> BaudRate -> TerminalAttributes
    withOutputSpeed termios br = unsafePerformIO $ do
      withNewTermios termios $ \p -> c_cfsetospeed p (baud2Word br)

    foreign import ccall unsafe "cfsetospeed"
      c_cfsetospeed :: Ptr CTermios -> CSpeed -> IO CInt

    -- | @getTerminalAttributes fd@ calls @tcgetattr@ to obtain
    --   the @TerminalAttributes@ associated with @Fd@ @fd@.
    getTerminalAttributes :: Fd -> IO TerminalAttributes
    getTerminalAttributes (Fd fd) = do
      fp <- mallocForeignPtrBytes (44)
    {-# LINE 379 "System/Posix/Terminal.hsc" #-}
      withForeignPtr fp $ \p ->
          throwErrnoIfMinus1_ "getTerminalAttributes" (c_tcgetattr fd p)
      return $ makeTerminalAttributes fp

    foreign import ccall unsafe "tcgetattr"
      c_tcgetattr :: CInt -> Ptr CTermios -> IO CInt

    data TerminalState
      = Immediately
      | WhenDrained
      | WhenFlushed

    -- | @setTerminalAttributes fd attr ts@ calls @tcsetattr@ to change
    --   the @TerminalAttributes@ associated with @Fd@ @fd@ to
    --   @attr@, when the terminal is in the state indicated by @ts@.
    setTerminalAttributes :: Fd
                          -> TerminalAttributes
                          -> TerminalState
                          -> IO ()
    setTerminalAttributes (Fd fd) termios state = do
      withTerminalAttributes termios $ \p ->
        throwErrnoIfMinus1_ "setTerminalAttributes"
          (c_tcsetattr fd (state2Int state) p)
      where
        state2Int :: TerminalState -> CInt
        state2Int Immediately = (0)
    {-# LINE 405 "System/Posix/Terminal.hsc" #-}
        state2Int WhenDrained = (1)
    {-# LINE 406 "System/Posix/Terminal.hsc" #-}
        state2Int WhenFlushed = (2)
    {-# LINE 407 "System/Posix/Terminal.hsc" #-}

    foreign import ccall unsafe "tcsetattr"
       c_tcsetattr :: CInt -> CInt -> Ptr CTermios -> IO CInt

    -- | @sendBreak fd duration@ calls @tcsendbreak@ to transmit a
    --   continuous stream of zero-valued bits on @Fd@ @fd@ for the
    --   specified implementation-dependent @duration@.
    sendBreak :: Fd -> Int -> IO ()
    sendBreak (Fd fd) duration
      = throwErrnoIfMinus1_ "sendBreak" (c_tcsendbreak fd (fromIntegral duration))

    foreign import ccall unsafe "tcsendbreak"
      c_tcsendbreak :: CInt -> CInt -> IO CInt

    -- | @drainOutput fd@ calls @tcdrain@ to block until all output
    --   written to @Fd@ @fd@ has been transmitted.
    drainOutput :: Fd -> IO ()
    drainOutput (Fd fd) = throwErrnoIfMinus1_ "drainOutput" (c_tcdrain fd)

    foreign import ccall unsafe "tcdrain"
      c_tcdrain :: CInt -> IO CInt

    data QueueSelector
      = InputQueue		-- TCIFLUSH
      | OutputQueue		-- TCOFLUSH
      | BothQueues		-- TCIOFLUSH

    -- | @discardData fd queues@ calls @tcflush@ to discard
    --   pending input and\/or output for @Fd@ @fd@,
    --   as indicated by the @QueueSelector@ @queues@.
    discardData :: Fd -> QueueSelector -> IO ()
    discardData (Fd fd) queue =
      throwErrnoIfMinus1_ "discardData" (c_tcflush fd (queue2Int queue))
      where
        queue2Int :: QueueSelector -> CInt
        queue2Int InputQueue  = (1)
    {-# LINE 444 "System/Posix/Terminal.hsc" #-}
        queue2Int OutputQueue = (2)
    {-# LINE 445 "System/Posix/Terminal.hsc" #-}
        queue2Int BothQueues  = (3)
    {-# LINE 446 "System/Posix/Terminal.hsc" #-}

    foreign import ccall unsafe "tcflush"
      c_tcflush :: CInt -> CInt -> IO CInt

    data FlowAction
      = SuspendOutput	-- ^ TCOOFF
      | RestartOutput	-- ^ TCOON
      | TransmitStop	-- ^ TCIOFF
      | TransmitStart	-- ^ TCION

    -- | @controlFlow fd action@ calls @tcflow@ to control the
    --   flow of data on @Fd@ @fd@, as indicated by
    --   @action@.
    controlFlow :: Fd -> FlowAction -> IO ()
    controlFlow (Fd fd) action =
      throwErrnoIfMinus1_ "controlFlow" (c_tcflow fd (action2Int action))
      where
        action2Int :: FlowAction -> CInt
        action2Int SuspendOutput = (1)
    {-# LINE 465 "System/Posix/Terminal.hsc" #-}
        action2Int RestartOutput = (2)
    {-# LINE 466 "System/Posix/Terminal.hsc" #-}
        action2Int TransmitStop  = (3)
    {-# LINE 467 "System/Posix/Terminal.hsc" #-}
        action2Int TransmitStart = (4)
    {-# LINE 468 "System/Posix/Terminal.hsc" #-}

    foreign import ccall unsafe "tcflow"
      c_tcflow :: CInt -> CInt -> IO CInt

    -- | @getTerminalProcessGroupID fd@ calls @tcgetpgrp@ to
    --   obtain the @ProcessGroupID@ of the foreground process group
    --   associated with the terminal attached to @Fd@ @fd@.
    getTerminalProcessGroupID :: Fd -> IO ProcessGroupID
    getTerminalProcessGroupID (Fd fd) = do
      throwErrnoIfMinus1 "getTerminalProcessGroupID" (c_tcgetpgrp fd)

    foreign import ccall unsafe "tcgetpgrp"
      c_tcgetpgrp :: CInt -> IO CPid

    -- | @setTerminalProcessGroupID fd pgid@ calls @tcsetpgrp@ to
    --   set the @ProcessGroupID@ of the foreground process group
    --   associated with the terminal attached to @Fd@
    --   @fd@ to @pgid@.
    setTerminalProcessGroupID :: Fd -> ProcessGroupID -> IO ()
    setTerminalProcessGroupID (Fd fd) pgid =
      throwErrnoIfMinus1_ "setTerminalProcessGroupID" (c_tcsetpgrp fd pgid)

    foreign import ccall unsafe "tcsetpgrp"
      c_tcsetpgrp :: CInt -> CPid -> IO CInt

    -- -----------------------------------------------------------------------------
    -- file descriptor queries

    -- | @queryTerminal fd@ calls @isatty@ to determine whether or
    --   not @Fd@ @fd@ is associated with a terminal.
    queryTerminal :: Fd -> IO Bool
    queryTerminal (Fd fd) = do
      r <- c_isatty fd
      return (r == 1)
      -- ToDo: the spec says that it can set errno to EBADF if the result is zero

    foreign import ccall unsafe "isatty"
      c_isatty :: CInt -> IO CInt

    -- | @getTerminalName fd@ calls @ttyname@ to obtain a name associated
    --   with the terminal for @Fd@ @fd@. If @fd@ is associated
    --   with a terminal, @getTerminalName@ returns the name of the
    --   terminal.
    getTerminalName :: Fd -> IO FilePath
    getTerminalName (Fd fd) = do
      s <- throwErrnoIfNull "getTerminalName" (c_ttyname fd)
      peekCString s

    foreign import ccall unsafe "ttyname"
      c_ttyname :: CInt -> IO CString

    -- | @getControllingTerminalName@ calls @ctermid@ to obtain
    --   a name associated with the controlling terminal for the process.  If a
    --   controlling terminal exists,
    --   @getControllingTerminalName@ returns the name of the
    --   controlling terminal.
    getControllingTerminalName :: IO FilePath
    getControllingTerminalName = do
      s <- throwErrnoIfNull "getControllingTerminalName" (c_ctermid nullPtr)
      peekCString s

    foreign import ccall unsafe "ctermid"
      c_ctermid :: CString -> IO CString

    -- | @getSlaveTerminalName@ calls @ptsname@ to obtain the name of the
    -- slave terminal associated with a pseudoterminal pair.  The file
    -- descriptor to pass in must be that of the master.
    getSlaveTerminalName :: Fd -> IO FilePath

    {-# LINE 538 "System/Posix/Terminal.hsc" #-}
    getSlaveTerminalName (Fd fd) = do
      s <- throwErrnoIfNull "getSlaveTerminalName" (c_ptsname fd)
      peekCString s

    foreign import ccall unsafe "__hsunix_ptsname"
      c_ptsname :: CInt -> IO CString

    {-# LINE 548 "System/Posix/Terminal.hsc" #-}

    -- | @openPseudoTerminal@ creates a pseudoterminal (pty) pair, and
    -- returns the newly created pair as a (@master@, @slave@) tuple.
    openPseudoTerminal :: IO (Fd, Fd)

    {-# LINE 554 "System/Posix/Terminal.hsc" #-}
    openPseudoTerminal =
      alloca $ \p_master ->
        alloca $ \p_slave -> do
          throwErrnoIfMinus1_ "openPty"
              (c_openpty p_master p_slave nullPtr nullPtr nullPtr)
          master <- peek p_master
          slave <- peek p_slave
          return (Fd master, Fd slave)

    foreign import ccall unsafe "openpty"
      c_openpty :: Ptr CInt -> Ptr CInt -> CString -> Ptr CTermios -> Ptr a
                -> IO CInt

    {-# LINE 605 "System/Posix/Terminal.hsc" #-}

    -- -----------------------------------------------------------------------------
    -- Local utility functions

    -- Convert Haskell ControlCharacter to Int

    cc2Word :: ControlCharacter -> Int
    cc2Word EndOfFile = (0)
    {-# LINE 613 "System/Posix/Terminal.hsc" #-}
    cc2Word EndOfLine = (1)
    {-# LINE 614 "System/Posix/Terminal.hsc" #-}
    cc2Word Erase     = (3)
    {-# LINE 615 "System/Posix/Terminal.hsc" #-}
    cc2Word Interrupt = (8)
    {-# LINE 616 "System/Posix/Terminal.hsc" #-}
    cc2Word Kill      = (5)
    {-# LINE 617 "System/Posix/Terminal.hsc" #-}
    cc2Word Quit      = (9)
    {-# LINE 618 "System/Posix/Terminal.hsc" #-}
    cc2Word Suspend   = (10)
    {-# LINE 619 "System/Posix/Terminal.hsc" #-}
    cc2Word Start     = (12)
    {-# LINE 620 "System/Posix/Terminal.hsc" #-}
    cc2Word Stop      = (13)
    {-# LINE 621 "System/Posix/Terminal.hsc" #-}

    -- Convert Haskell BaudRate to unsigned integral type (Word)

    baud2Word :: BaudRate -> CSpeed
    baud2Word B0 = (0)
    {-# LINE 626 "System/Posix/Terminal.hsc" #-}
    baud2Word B50 = (50)
    {-# LINE 627 "System/Posix/Terminal.hsc" #-}
    baud2Word B75 = (75)
    {-# LINE 628 "System/Posix/Terminal.hsc" #-}
    baud2Word B110 = (110)
    {-# LINE 629 "System/Posix/Terminal.hsc" #-}
    baud2Word B134 = (134)
    {-# LINE 630 "System/Posix/Terminal.hsc" #-}
    baud2Word B150 = (150)
    {-# LINE 631 "System/Posix/Terminal.hsc" #-}
    baud2Word B200 = (200)
    {-# LINE 632 "System/Posix/Terminal.hsc" #-}
    baud2Word B300 = (300)
    {-# LINE 633 "System/Posix/Terminal.hsc" #-}
    baud2Word B600 = (600)
    {-# LINE 634 "System/Posix/Terminal.hsc" #-}
    baud2Word B1200 = (1200)
    {-# LINE 635 "System/Posix/Terminal.hsc" #-}
    baud2Word B1800 = (1800)
    {-# LINE 636 "System/Posix/Terminal.hsc" #-}
    baud2Word B2400 = (2400)
    {-# LINE 637 "System/Posix/Terminal.hsc" #-}
    baud2Word B4800 = (4800)
    {-# LINE 638 "System/Posix/Terminal.hsc" #-}
    baud2Word B9600 = (9600)
    {-# LINE 639 "System/Posix/Terminal.hsc" #-}
    baud2Word B19200 = (19200)
    {-# LINE 640 "System/Posix/Terminal.hsc" #-}
    baud2Word B38400 = (38400)
    {-# LINE 641 "System/Posix/Terminal.hsc" #-}
    baud2Word B57600 = (57600)
    {-# LINE 642 "System/Posix/Terminal.hsc" #-}
    baud2Word B115200 = (115200)
    {-# LINE 643 "System/Posix/Terminal.hsc" #-}

    -- And convert a word back to a baud rate
    -- We really need some cpp macros here.

    word2Baud :: CSpeed -> BaudRate
    word2Baud x =
        if x == (0) then B0
    {-# LINE 650 "System/Posix/Terminal.hsc" #-}
        else if x == (50) then B50
    {-# LINE 651 "System/Posix/Terminal.hsc" #-}
        else if x == (75) then B75
    {-# LINE 652 "System/Posix/Terminal.hsc" #-}
        else if x == (110) then B110
    {-# LINE 653 "System/Posix/Terminal.hsc" #-}
        else if x == (134) then B134
    {-# LINE 654 "System/Posix/Terminal.hsc" #-}
        else if x == (150) then B150
    {-# LINE 655 "System/Posix/Terminal.hsc" #-}
        else if x == (200) then B200
    {-# LINE 656 "System/Posix/Terminal.hsc" #-}
        else if x == (300) then B300
    {-# LINE 657 "System/Posix/Terminal.hsc" #-}
        else if x == (600) then B600
    {-# LINE 658 "System/Posix/Terminal.hsc" #-}
        else if x == (1200) then B1200
    {-# LINE 659 "System/Posix/Terminal.hsc" #-}
        else if x == (1800) then B1800
    {-# LINE 660 "System/Posix/Terminal.hsc" #-}
        else if x == (2400) then B2400
    {-# LINE 661 "System/Posix/Terminal.hsc" #-}
        else if x == (4800) then B4800
    {-# LINE 662 "System/Posix/Terminal.hsc" #-}
        else if x == (9600) then B9600
    {-# LINE 663 "System/Posix/Terminal.hsc" #-}
        else if x == (19200) then B19200
    {-# LINE 664 "System/Posix/Terminal.hsc" #-}
        else if x == (38400) then B38400
    {-# LINE 665 "System/Posix/Terminal.hsc" #-}
        else if x == (57600) then B57600
    {-# LINE 666 "System/Posix/Terminal.hsc" #-}
        else if x == (115200) then B115200
    {-# LINE 667 "System/Posix/Terminal.hsc" #-}
        else error "unknown baud rate"

    -- Clear termios i_flag

    clearInputFlag :: CTcflag -> TerminalAttributes -> TerminalAttributes
    clearInputFlag flag termios = unsafePerformIO $ do
      fp <- mallocForeignPtrBytes (44)
    {-# LINE 674 "System/Posix/Terminal.hsc" #-}
      withForeignPtr fp $ \p1 -> do
        withTerminalAttributes termios $ \p2 -> do
          copyBytes p1 p2 (44)
    {-# LINE 677 "System/Posix/Terminal.hsc" #-}
          iflag <- ((\hsc_ptr -> peekByteOff hsc_ptr 0)) p2
    {-# LINE 678 "System/Posix/Terminal.hsc" #-}
          ((\hsc_ptr -> pokeByteOff hsc_ptr 0)) p1 (iflag .&. complement flag)
    {-# LINE 679 "System/Posix/Terminal.hsc" #-}
      return $ makeTerminalAttributes fp

    -- Set termios i_flag

    setInputFlag :: CTcflag -> TerminalAttributes -> TerminalAttributes
    setInputFlag flag termios = unsafePerformIO $ do
      fp <- mallocForeignPtrBytes (44)
    {-# LINE 686 "System/Posix/Terminal.hsc" #-}
      withForeignPtr fp $ \p1 -> do
        withTerminalAttributes termios $ \p2 -> do
          copyBytes p1 p2 (44)
    {-# LINE 689 "System/Posix/Terminal.hsc" #-}
          iflag <- ((\hsc_ptr -> peekByteOff hsc_ptr 0)) p2
    {-# LINE 690 "System/Posix/Terminal.hsc" #-}
          ((\hsc_ptr -> pokeByteOff hsc_ptr 0)) p1 (iflag .|. flag)
    {-# LINE 691 "System/Posix/Terminal.hsc" #-}
      return $ makeTerminalAttributes fp

    -- Examine termios i_flag

    testInputFlag :: CTcflag -> TerminalAttributes -> Bool
    testInputFlag flag termios = unsafePerformIO $
      withTerminalAttributes termios $ \p ->  do
        iflag <- ((\hsc_ptr -> peekByteOff hsc_ptr 0)) p
    {-# LINE 699 "System/Posix/Terminal.hsc" #-}
        return $! ((iflag .&. flag) /= 0)

    -- Clear termios c_flag

    clearControlFlag :: CTcflag -> TerminalAttributes -> TerminalAttributes
    clearControlFlag flag termios = unsafePerformIO $ do
      fp <- mallocForeignPtrBytes (44)
    {-# LINE 706 "System/Posix/Terminal.hsc" #-}
      withForeignPtr fp $ \p1 -> do
        withTerminalAttributes termios $ \p2 -> do
          copyBytes p1 p2 (44)
    {-# LINE 709 "System/Posix/Terminal.hsc" #-}
          cflag <- ((\hsc_ptr -> peekByteOff hsc_ptr 8)) p2
    {-# LINE 710 "System/Posix/Terminal.hsc" #-}
          ((\hsc_ptr -> pokeByteOff hsc_ptr 8)) p1 (cflag .&. complement flag)
    {-# LINE 711 "System/Posix/Terminal.hsc" #-}
      return $ makeTerminalAttributes fp

    -- Set termios c_flag

    setControlFlag :: CTcflag -> TerminalAttributes -> TerminalAttributes
    setControlFlag flag termios = unsafePerformIO $ do
      fp <- mallocForeignPtrBytes (44)
    {-# LINE 718 "System/Posix/Terminal.hsc" #-}
      withForeignPtr fp $ \p1 -> do
        withTerminalAttributes termios $ \p2 -> do
          copyBytes p1 p2 (44)
    {-# LINE 721 "System/Posix/Terminal.hsc" #-}
          cflag <- ((\hsc_ptr -> peekByteOff hsc_ptr 8)) p2
    {-# LINE 722 "System/Posix/Terminal.hsc" #-}
          ((\hsc_ptr -> pokeByteOff hsc_ptr 8)) p1 (cflag .|. flag)
    {-# LINE 723 "System/Posix/Terminal.hsc" #-}
      return $ makeTerminalAttributes fp

    -- Examine termios c_flag

    testControlFlag :: CTcflag -> TerminalAttributes -> Bool
    testControlFlag flag termios = unsafePerformIO $
      withTerminalAttributes termios $ \p -> do
        cflag <- ((\hsc_ptr -> peekByteOff hsc_ptr 8)) p
    {-# LINE 731 "System/Posix/Terminal.hsc" #-}
        return $! ((cflag .&. flag) /= 0)

    -- Clear termios l_flag

    clearLocalFlag :: CTcflag -> TerminalAttributes -> TerminalAttributes
    clearLocalFlag flag termios = unsafePerformIO $ do
      fp <- mallocForeignPtrBytes (44)
    {-# LINE 738 "System/Posix/Terminal.hsc" #-}
      withForeignPtr fp $ \p1 -> do
        withTerminalAttributes termios $ \p2 -> do
          copyBytes p1 p2 (44)
    {-# LINE 741 "System/Posix/Terminal.hsc" #-}
          lflag <- ((\hsc_ptr -> peekByteOff hsc_ptr 12)) p2
    {-# LINE 742 "System/Posix/Terminal.hsc" #-}
          ((\hsc_ptr -> pokeByteOff hsc_ptr 12)) p1 (lflag .&. complement flag)
    {-# LINE 743 "System/Posix/Terminal.hsc" #-}
      return $ makeTerminalAttributes fp

    -- Set termios l_flag

    setLocalFlag :: CTcflag -> TerminalAttributes -> TerminalAttributes
    setLocalFlag flag termios = unsafePerformIO $ do
      fp <- mallocForeignPtrBytes (44)
    {-# LINE 750 "System/Posix/Terminal.hsc" #-}
      withForeignPtr fp $ \p1 -> do
        withTerminalAttributes termios $ \p2 -> do
          copyBytes p1 p2 (44)
    {-# LINE 753 "System/Posix/Terminal.hsc" #-}
          lflag <- ((\hsc_ptr -> peekByteOff hsc_ptr 12)) p2
    {-# LINE 754 "System/Posix/Terminal.hsc" #-}
          ((\hsc_ptr -> pokeByteOff hsc_ptr 12)) p1 (lflag .|. flag)
    {-# LINE 755 "System/Posix/Terminal.hsc" #-}
      return $ makeTerminalAttributes fp

    -- Examine termios l_flag

    testLocalFlag :: CTcflag -> TerminalAttributes -> Bool
    testLocalFlag flag termios = unsafePerformIO $
      withTerminalAttributes termios $ \p ->  do
        lflag <- ((\hsc_ptr -> peekByteOff hsc_ptr 12)) p
    {-# LINE 763 "System/Posix/Terminal.hsc" #-}
        return $! ((lflag .&. flag) /= 0)

    -- Clear termios o_flag

    clearOutputFlag :: CTcflag -> TerminalAttributes -> TerminalAttributes
    clearOutputFlag flag termios = unsafePerformIO $ do
      fp <- mallocForeignPtrBytes (44)
    {-# LINE 770 "System/Posix/Terminal.hsc" #-}
      withForeignPtr fp $ \p1 -> do
        withTerminalAttributes termios $ \p2 -> do
          copyBytes p1 p2 (44)
    {-# LINE 773 "System/Posix/Terminal.hsc" #-}
          oflag <- ((\hsc_ptr -> peekByteOff hsc_ptr 4)) p2
    {-# LINE 774 "System/Posix/Terminal.hsc" #-}
          ((\hsc_ptr -> pokeByteOff hsc_ptr 4)) p1 (oflag .&. complement flag)
    {-# LINE 775 "System/Posix/Terminal.hsc" #-}
      return $ makeTerminalAttributes fp

    -- Set termios o_flag

    setOutputFlag :: CTcflag -> TerminalAttributes -> TerminalAttributes
    setOutputFlag flag termios = unsafePerformIO $ do
      fp <- mallocForeignPtrBytes (44)
    {-# LINE 782 "System/Posix/Terminal.hsc" #-}
      withForeignPtr fp $ \p1 -> do
        withTerminalAttributes termios $ \p2 -> do
          copyBytes p1 p2 (44)
    {-# LINE 785 "System/Posix/Terminal.hsc" #-}
          oflag <- ((\hsc_ptr -> peekByteOff hsc_ptr 4)) p2
    {-# LINE 786 "System/Posix/Terminal.hsc" #-}
          ((\hsc_ptr -> pokeByteOff hsc_ptr 4)) p1 (oflag .|. flag)
    {-# LINE 787 "System/Posix/Terminal.hsc" #-}
      return $ makeTerminalAttributes fp

    -- Examine termios o_flag

    testOutputFlag :: CTcflag -> TerminalAttributes -> Bool
    testOutputFlag flag termios = unsafePerformIO $
      withTerminalAttributes termios $ \p -> do
        oflag <- ((\hsc_ptr -> peekByteOff hsc_ptr 4)) p
    {-# LINE 795 "System/Posix/Terminal.hsc" #-}
        return $! ((oflag .&. flag) /= 0)

    withNewTermios :: TerminalAttributes -> (Ptr CTermios -> IO a)
      -> IO TerminalAttributes
    withNewTermios termios action = do
      fp1 <- mallocForeignPtrBytes (44)
    {-# LINE 801 "System/Posix/Terminal.hsc" #-}
      withForeignPtr fp1 $ \p1 -> do
       withTerminalAttributes termios $ \p2 -> do
        copyBytes p1 p2 (44)
    {-# LINE 804 "System/Posix/Terminal.hsc" #-}
        action p1
      return $ makeTerminalAttributes fp1