unix 2.5.0.0 → 2.5.1.0
raw patch · 40 files changed
+3886/−1804 lines, 40 filesdep +bytestringdep ~basePVP: major bump suggested
API removals or changes: PVP suggests a major version bump
Dependencies added: bytestring
Dependency ranges changed: base
API changes (from Hackage documentation)
+ System.Posix.ByteString: type RawFilePath = ByteString
+ System.Posix.ByteString.FilePath: peekFilePath :: CString -> IO RawFilePath
+ System.Posix.ByteString.FilePath: peekFilePathLen :: CStringLen -> IO RawFilePath
+ System.Posix.ByteString.FilePath: throwErrnoPath :: String -> RawFilePath -> IO a
+ System.Posix.ByteString.FilePath: throwErrnoPathIf :: (a -> Bool) -> String -> RawFilePath -> IO a -> IO a
+ System.Posix.ByteString.FilePath: throwErrnoPathIfMinus1 :: (Eq a, Num a) => String -> RawFilePath -> IO a -> IO a
+ System.Posix.ByteString.FilePath: throwErrnoPathIfMinus1Retry :: (Eq a, Num a) => String -> RawFilePath -> IO a -> IO a
+ System.Posix.ByteString.FilePath: throwErrnoPathIfMinus1Retry_ :: (Eq a, Num a) => String -> RawFilePath -> IO a -> IO ()
+ System.Posix.ByteString.FilePath: throwErrnoPathIfMinus1_ :: (Eq a, Num a) => String -> RawFilePath -> IO a -> IO ()
+ System.Posix.ByteString.FilePath: throwErrnoPathIfNull :: String -> RawFilePath -> IO (Ptr a) -> IO (Ptr a)
+ System.Posix.ByteString.FilePath: throwErrnoPathIfNullRetry :: String -> RawFilePath -> IO (Ptr a) -> IO (Ptr a)
+ System.Posix.ByteString.FilePath: throwErrnoPathIfRetry :: (a -> Bool) -> String -> RawFilePath -> IO a -> IO a
+ System.Posix.ByteString.FilePath: throwErrnoPathIf_ :: (a -> Bool) -> String -> RawFilePath -> IO a -> IO ()
+ System.Posix.ByteString.FilePath: type RawFilePath = ByteString
+ System.Posix.ByteString.FilePath: withFilePath :: RawFilePath -> (CString -> IO a) -> IO a
+ System.Posix.Directory.ByteString: changeWorkingDirectory :: RawFilePath -> IO ()
+ System.Posix.Directory.ByteString: changeWorkingDirectoryFd :: Fd -> IO ()
+ System.Posix.Directory.ByteString: closeDirStream :: DirStream -> IO ()
+ System.Posix.Directory.ByteString: createDirectory :: RawFilePath -> FileMode -> IO ()
+ System.Posix.Directory.ByteString: data DirStream
+ System.Posix.Directory.ByteString: data DirStreamOffset
+ System.Posix.Directory.ByteString: getWorkingDirectory :: IO RawFilePath
+ System.Posix.Directory.ByteString: openDirStream :: RawFilePath -> IO DirStream
+ System.Posix.Directory.ByteString: readDirStream :: DirStream -> IO RawFilePath
+ System.Posix.Directory.ByteString: removeDirectory :: RawFilePath -> IO ()
+ System.Posix.Directory.ByteString: rewindDirStream :: DirStream -> IO ()
+ System.Posix.Directory.ByteString: seekDirStream :: DirStream -> DirStreamOffset -> IO ()
+ System.Posix.Directory.ByteString: tellDirStream :: DirStream -> IO DirStreamOffset
+ System.Posix.DynamicLinker.ByteString: dlclose :: DL -> IO ()
+ System.Posix.DynamicLinker.ByteString: dlerror :: IO String
+ System.Posix.DynamicLinker.ByteString: dlopen :: RawFilePath -> [RTLDFlags] -> IO DL
+ System.Posix.DynamicLinker.ByteString: dlsym :: DL -> String -> IO (FunPtr a)
+ System.Posix.DynamicLinker.ByteString: undl :: DL -> Ptr ()
+ System.Posix.DynamicLinker.ByteString: withDL :: RawFilePath -> [RTLDFlags] -> (DL -> IO a) -> IO a
+ System.Posix.DynamicLinker.ByteString: withDL_ :: RawFilePath -> [RTLDFlags] -> (DL -> IO a) -> IO ()
+ System.Posix.DynamicLinker.Module.ByteString: data Module
+ System.Posix.DynamicLinker.Module.ByteString: moduleClose :: Module -> IO ()
+ System.Posix.DynamicLinker.Module.ByteString: moduleError :: IO String
+ System.Posix.DynamicLinker.Module.ByteString: moduleOpen :: RawFilePath -> [RTLDFlags] -> IO Module
+ System.Posix.DynamicLinker.Module.ByteString: moduleSymbol :: Module -> String -> IO (FunPtr a)
+ System.Posix.DynamicLinker.Module.ByteString: withModule :: Maybe String -> String -> [RTLDFlags] -> (Module -> IO a) -> IO a
+ System.Posix.DynamicLinker.Module.ByteString: withModule_ :: Maybe String -> String -> [RTLDFlags] -> (Module -> IO a) -> IO ()
+ System.Posix.Env.ByteString: getArgs :: IO [ByteString]
+ System.Posix.Env.ByteString: getEnv :: ByteString -> IO (Maybe ByteString)
+ System.Posix.Env.ByteString: getEnvDefault :: ByteString -> ByteString -> IO ByteString
+ System.Posix.Env.ByteString: getEnvironment :: IO [(ByteString, ByteString)]
+ System.Posix.Env.ByteString: getEnvironmentPrim :: IO [ByteString]
+ System.Posix.Env.ByteString: putEnv :: ByteString -> IO ()
+ System.Posix.Env.ByteString: setEnv :: ByteString -> ByteString -> Bool -> IO ()
+ System.Posix.Env.ByteString: unsetEnv :: ByteString -> IO ()
+ System.Posix.Files.ByteString: AsyncIOAvailable :: PathVar
+ System.Posix.Files.ByteString: FileNameLimit :: PathVar
+ System.Posix.Files.ByteString: FileNamesAreNotTruncated :: PathVar
+ System.Posix.Files.ByteString: FileSizeBits :: PathVar
+ System.Posix.Files.ByteString: InputLineLimit :: PathVar
+ System.Posix.Files.ByteString: InputQueueLimit :: PathVar
+ System.Posix.Files.ByteString: LinkLimit :: PathVar
+ System.Posix.Files.ByteString: PathNameLimit :: PathVar
+ System.Posix.Files.ByteString: PipeBufferLimit :: PathVar
+ System.Posix.Files.ByteString: PrioIOAvailable :: PathVar
+ System.Posix.Files.ByteString: SetOwnerAndGroupIsRestricted :: PathVar
+ System.Posix.Files.ByteString: SymbolicLinkLimit :: PathVar
+ System.Posix.Files.ByteString: SyncIOAvailable :: PathVar
+ System.Posix.Files.ByteString: VDisableChar :: PathVar
+ System.Posix.Files.ByteString: accessModes :: FileMode
+ System.Posix.Files.ByteString: accessTime :: FileStatus -> EpochTime
+ System.Posix.Files.ByteString: blockSpecialMode :: FileMode
+ System.Posix.Files.ByteString: characterSpecialMode :: FileMode
+ System.Posix.Files.ByteString: createDevice :: RawFilePath -> FileMode -> DeviceID -> IO ()
+ System.Posix.Files.ByteString: createLink :: RawFilePath -> RawFilePath -> IO ()
+ System.Posix.Files.ByteString: createNamedPipe :: RawFilePath -> FileMode -> IO ()
+ System.Posix.Files.ByteString: createSymbolicLink :: RawFilePath -> RawFilePath -> IO ()
+ System.Posix.Files.ByteString: data FileStatus
+ System.Posix.Files.ByteString: data PathVar
+ System.Posix.Files.ByteString: deviceID :: FileStatus -> DeviceID
+ System.Posix.Files.ByteString: directoryMode :: FileMode
+ System.Posix.Files.ByteString: fileAccess :: RawFilePath -> Bool -> Bool -> Bool -> IO Bool
+ System.Posix.Files.ByteString: fileExist :: RawFilePath -> IO Bool
+ System.Posix.Files.ByteString: fileGroup :: FileStatus -> GroupID
+ System.Posix.Files.ByteString: fileID :: FileStatus -> FileID
+ System.Posix.Files.ByteString: fileMode :: FileStatus -> FileMode
+ System.Posix.Files.ByteString: fileOwner :: FileStatus -> UserID
+ System.Posix.Files.ByteString: fileSize :: FileStatus -> FileOffset
+ System.Posix.Files.ByteString: fileTypeModes :: FileMode
+ System.Posix.Files.ByteString: getFdPathVar :: Fd -> PathVar -> IO Limit
+ System.Posix.Files.ByteString: getFdStatus :: Fd -> IO FileStatus
+ System.Posix.Files.ByteString: getFileStatus :: RawFilePath -> IO FileStatus
+ System.Posix.Files.ByteString: getPathVar :: RawFilePath -> PathVar -> IO Limit
+ System.Posix.Files.ByteString: getSymbolicLinkStatus :: RawFilePath -> IO FileStatus
+ System.Posix.Files.ByteString: groupExecuteMode :: FileMode
+ System.Posix.Files.ByteString: groupModes :: FileMode
+ System.Posix.Files.ByteString: groupReadMode :: FileMode
+ System.Posix.Files.ByteString: groupWriteMode :: FileMode
+ System.Posix.Files.ByteString: intersectFileModes :: FileMode -> FileMode -> FileMode
+ System.Posix.Files.ByteString: isBlockDevice :: FileStatus -> Bool
+ System.Posix.Files.ByteString: isCharacterDevice :: FileStatus -> Bool
+ System.Posix.Files.ByteString: isDirectory :: FileStatus -> Bool
+ System.Posix.Files.ByteString: isNamedPipe :: FileStatus -> Bool
+ System.Posix.Files.ByteString: isRegularFile :: FileStatus -> Bool
+ System.Posix.Files.ByteString: isSocket :: FileStatus -> Bool
+ System.Posix.Files.ByteString: isSymbolicLink :: FileStatus -> Bool
+ System.Posix.Files.ByteString: linkCount :: FileStatus -> LinkCount
+ System.Posix.Files.ByteString: modificationTime :: FileStatus -> EpochTime
+ System.Posix.Files.ByteString: namedPipeMode :: FileMode
+ System.Posix.Files.ByteString: nullFileMode :: FileMode
+ System.Posix.Files.ByteString: otherExecuteMode :: FileMode
+ System.Posix.Files.ByteString: otherModes :: FileMode
+ System.Posix.Files.ByteString: otherReadMode :: FileMode
+ System.Posix.Files.ByteString: otherWriteMode :: FileMode
+ System.Posix.Files.ByteString: ownerExecuteMode :: FileMode
+ System.Posix.Files.ByteString: ownerModes :: FileMode
+ System.Posix.Files.ByteString: ownerReadMode :: FileMode
+ System.Posix.Files.ByteString: ownerWriteMode :: FileMode
+ System.Posix.Files.ByteString: readSymbolicLink :: RawFilePath -> IO RawFilePath
+ System.Posix.Files.ByteString: regularFileMode :: FileMode
+ System.Posix.Files.ByteString: removeLink :: RawFilePath -> IO ()
+ System.Posix.Files.ByteString: rename :: RawFilePath -> RawFilePath -> IO ()
+ System.Posix.Files.ByteString: setFdMode :: Fd -> FileMode -> IO ()
+ System.Posix.Files.ByteString: setFdOwnerAndGroup :: Fd -> UserID -> GroupID -> IO ()
+ System.Posix.Files.ByteString: setFdSize :: Fd -> FileOffset -> IO ()
+ System.Posix.Files.ByteString: setFileCreationMask :: FileMode -> IO FileMode
+ System.Posix.Files.ByteString: setFileMode :: RawFilePath -> FileMode -> IO ()
+ System.Posix.Files.ByteString: setFileSize :: RawFilePath -> FileOffset -> IO ()
+ System.Posix.Files.ByteString: setFileTimes :: RawFilePath -> EpochTime -> EpochTime -> IO ()
+ System.Posix.Files.ByteString: setGroupIDMode :: FileMode
+ System.Posix.Files.ByteString: setOwnerAndGroup :: RawFilePath -> UserID -> GroupID -> IO ()
+ System.Posix.Files.ByteString: setSymbolicLinkOwnerAndGroup :: RawFilePath -> UserID -> GroupID -> IO ()
+ System.Posix.Files.ByteString: setUserIDMode :: FileMode
+ System.Posix.Files.ByteString: socketMode :: FileMode
+ System.Posix.Files.ByteString: specialDeviceID :: FileStatus -> DeviceID
+ System.Posix.Files.ByteString: statusChangeTime :: FileStatus -> EpochTime
+ System.Posix.Files.ByteString: stdFileMode :: FileMode
+ System.Posix.Files.ByteString: symbolicLinkMode :: FileMode
+ System.Posix.Files.ByteString: touchFile :: RawFilePath -> IO ()
+ System.Posix.Files.ByteString: unionFileModes :: FileMode -> FileMode -> FileMode
+ System.Posix.IO.ByteString: AppendOnWrite :: FdOption
+ System.Posix.IO.ByteString: CloseOnExec :: FdOption
+ System.Posix.IO.ByteString: NonBlockingRead :: FdOption
+ System.Posix.IO.ByteString: OpenFileFlags :: Bool -> Bool -> Bool -> Bool -> Bool -> OpenFileFlags
+ System.Posix.IO.ByteString: ReadLock :: LockRequest
+ System.Posix.IO.ByteString: ReadOnly :: OpenMode
+ System.Posix.IO.ByteString: ReadWrite :: OpenMode
+ System.Posix.IO.ByteString: SynchronousWrites :: FdOption
+ System.Posix.IO.ByteString: Unlock :: LockRequest
+ System.Posix.IO.ByteString: WriteLock :: LockRequest
+ System.Posix.IO.ByteString: WriteOnly :: OpenMode
+ System.Posix.IO.ByteString: append :: OpenFileFlags -> Bool
+ System.Posix.IO.ByteString: closeFd :: Fd -> IO ()
+ System.Posix.IO.ByteString: createFile :: RawFilePath -> FileMode -> IO Fd
+ System.Posix.IO.ByteString: createPipe :: IO (Fd, Fd)
+ System.Posix.IO.ByteString: data FdOption
+ System.Posix.IO.ByteString: data LockRequest
+ System.Posix.IO.ByteString: data OpenFileFlags
+ System.Posix.IO.ByteString: data OpenMode
+ System.Posix.IO.ByteString: defaultFileFlags :: OpenFileFlags
+ System.Posix.IO.ByteString: dup :: Fd -> IO Fd
+ System.Posix.IO.ByteString: dupTo :: Fd -> Fd -> IO Fd
+ System.Posix.IO.ByteString: exclusive :: OpenFileFlags -> Bool
+ System.Posix.IO.ByteString: fdRead :: Fd -> ByteCount -> IO (String, ByteCount)
+ System.Posix.IO.ByteString: fdReadBuf :: Fd -> Ptr Word8 -> ByteCount -> IO ByteCount
+ System.Posix.IO.ByteString: fdSeek :: Fd -> SeekMode -> FileOffset -> IO FileOffset
+ System.Posix.IO.ByteString: fdToHandle :: Fd -> IO Handle
+ System.Posix.IO.ByteString: fdWrite :: Fd -> String -> IO ByteCount
+ System.Posix.IO.ByteString: fdWriteBuf :: Fd -> Ptr Word8 -> ByteCount -> IO ByteCount
+ System.Posix.IO.ByteString: getLock :: Fd -> FileLock -> IO (Maybe (ProcessID, FileLock))
+ System.Posix.IO.ByteString: handleToFd :: Handle -> IO Fd
+ System.Posix.IO.ByteString: noctty :: OpenFileFlags -> Bool
+ System.Posix.IO.ByteString: nonBlock :: OpenFileFlags -> Bool
+ System.Posix.IO.ByteString: openFd :: RawFilePath -> OpenMode -> Maybe FileMode -> OpenFileFlags -> IO Fd
+ System.Posix.IO.ByteString: queryFdOption :: Fd -> FdOption -> IO Bool
+ System.Posix.IO.ByteString: setFdOption :: Fd -> FdOption -> Bool -> IO ()
+ System.Posix.IO.ByteString: setLock :: Fd -> FileLock -> IO ()
+ System.Posix.IO.ByteString: stdInput, stdError, stdOutput :: Fd
+ System.Posix.IO.ByteString: trunc :: OpenFileFlags -> Bool
+ System.Posix.IO.ByteString: type FileLock = (LockRequest, SeekMode, FileOffset, FileOffset)
+ System.Posix.IO.ByteString: waitToSetLock :: Fd -> FileLock -> IO ()
+ System.Posix.Process.ByteString: Exited :: ExitCode -> ProcessStatus
+ System.Posix.Process.ByteString: ProcessTimes :: ClockTick -> ClockTick -> ClockTick -> ClockTick -> ClockTick -> ProcessTimes
+ System.Posix.Process.ByteString: Stopped :: Signal -> ProcessStatus
+ System.Posix.Process.ByteString: Terminated :: Signal -> ProcessStatus
+ System.Posix.Process.ByteString: childSystemTime :: ProcessTimes -> ClockTick
+ System.Posix.Process.ByteString: childUserTime :: ProcessTimes -> ClockTick
+ System.Posix.Process.ByteString: createProcessGroup :: ProcessID -> IO ProcessGroupID
+ System.Posix.Process.ByteString: createProcessGroupFor :: ProcessID -> IO ProcessGroupID
+ System.Posix.Process.ByteString: createSession :: IO ProcessGroupID
+ System.Posix.Process.ByteString: data ProcessStatus
+ System.Posix.Process.ByteString: data ProcessTimes
+ System.Posix.Process.ByteString: elapsedTime :: ProcessTimes -> ClockTick
+ System.Posix.Process.ByteString: executeFile :: RawFilePath -> Bool -> [ByteString] -> Maybe [(ByteString, ByteString)] -> IO a
+ System.Posix.Process.ByteString: exitImmediately :: ExitCode -> IO ()
+ System.Posix.Process.ByteString: forkProcess :: IO () -> IO ProcessID
+ System.Posix.Process.ByteString: getAnyProcessStatus :: Bool -> Bool -> IO (Maybe (ProcessID, ProcessStatus))
+ System.Posix.Process.ByteString: getGroupProcessStatus :: Bool -> Bool -> ProcessGroupID -> IO (Maybe (ProcessID, ProcessStatus))
+ System.Posix.Process.ByteString: getParentProcessID :: IO ProcessID
+ System.Posix.Process.ByteString: getProcessGroupID :: IO ProcessGroupID
+ System.Posix.Process.ByteString: getProcessGroupIDOf :: ProcessID -> IO ProcessGroupID
+ System.Posix.Process.ByteString: getProcessGroupPriority :: ProcessGroupID -> IO Int
+ System.Posix.Process.ByteString: getProcessID :: IO ProcessID
+ System.Posix.Process.ByteString: getProcessPriority :: ProcessID -> IO Int
+ System.Posix.Process.ByteString: getProcessStatus :: Bool -> Bool -> ProcessID -> IO (Maybe ProcessStatus)
+ System.Posix.Process.ByteString: getProcessTimes :: IO ProcessTimes
+ System.Posix.Process.ByteString: getUserPriority :: UserID -> IO Int
+ System.Posix.Process.ByteString: joinProcessGroup :: ProcessGroupID -> IO ()
+ System.Posix.Process.ByteString: nice :: Int -> IO ()
+ System.Posix.Process.ByteString: setProcessGroupID :: ProcessID -> ProcessGroupID -> IO ()
+ System.Posix.Process.ByteString: setProcessGroupIDOf :: ProcessID -> ProcessGroupID -> IO ()
+ System.Posix.Process.ByteString: setProcessGroupPriority :: ProcessGroupID -> Int -> IO ()
+ System.Posix.Process.ByteString: setProcessPriority :: ProcessID -> Int -> IO ()
+ System.Posix.Process.ByteString: setUserPriority :: UserID -> Int -> IO ()
+ System.Posix.Process.ByteString: systemTime :: ProcessTimes -> ClockTick
+ System.Posix.Process.ByteString: userTime :: ProcessTimes -> ClockTick
+ System.Posix.Temp.ByteString: mkstemp :: ByteString -> IO (RawFilePath, Handle)
+ System.Posix.Terminal.ByteString: B0 :: BaudRate
+ System.Posix.Terminal.ByteString: B110 :: BaudRate
+ System.Posix.Terminal.ByteString: B115200 :: BaudRate
+ System.Posix.Terminal.ByteString: B1200 :: BaudRate
+ System.Posix.Terminal.ByteString: B134 :: BaudRate
+ System.Posix.Terminal.ByteString: B150 :: BaudRate
+ System.Posix.Terminal.ByteString: B1800 :: BaudRate
+ System.Posix.Terminal.ByteString: B19200 :: BaudRate
+ System.Posix.Terminal.ByteString: B200 :: BaudRate
+ System.Posix.Terminal.ByteString: B2400 :: BaudRate
+ System.Posix.Terminal.ByteString: B300 :: BaudRate
+ System.Posix.Terminal.ByteString: B38400 :: BaudRate
+ System.Posix.Terminal.ByteString: B4800 :: BaudRate
+ System.Posix.Terminal.ByteString: B50 :: BaudRate
+ System.Posix.Terminal.ByteString: B57600 :: BaudRate
+ System.Posix.Terminal.ByteString: B600 :: BaudRate
+ System.Posix.Terminal.ByteString: B75 :: BaudRate
+ System.Posix.Terminal.ByteString: B9600 :: BaudRate
+ System.Posix.Terminal.ByteString: BackgroundWriteInterrupt :: TerminalMode
+ System.Posix.Terminal.ByteString: BothQueues :: QueueSelector
+ System.Posix.Terminal.ByteString: CheckParity :: TerminalMode
+ System.Posix.Terminal.ByteString: EchoErase :: TerminalMode
+ System.Posix.Terminal.ByteString: EchoKill :: TerminalMode
+ System.Posix.Terminal.ByteString: EchoLF :: TerminalMode
+ System.Posix.Terminal.ByteString: EnableEcho :: TerminalMode
+ System.Posix.Terminal.ByteString: EnableParity :: TerminalMode
+ System.Posix.Terminal.ByteString: EndOfFile :: ControlCharacter
+ System.Posix.Terminal.ByteString: EndOfLine :: ControlCharacter
+ System.Posix.Terminal.ByteString: Erase :: ControlCharacter
+ System.Posix.Terminal.ByteString: ExtendedFunctions :: TerminalMode
+ System.Posix.Terminal.ByteString: HangupOnClose :: TerminalMode
+ System.Posix.Terminal.ByteString: IgnoreBreak :: TerminalMode
+ System.Posix.Terminal.ByteString: IgnoreCR :: TerminalMode
+ System.Posix.Terminal.ByteString: IgnoreParityErrors :: TerminalMode
+ System.Posix.Terminal.ByteString: Immediately :: TerminalState
+ System.Posix.Terminal.ByteString: InputQueue :: QueueSelector
+ System.Posix.Terminal.ByteString: Interrupt :: ControlCharacter
+ System.Posix.Terminal.ByteString: InterruptOnBreak :: TerminalMode
+ System.Posix.Terminal.ByteString: KeyboardInterrupts :: TerminalMode
+ System.Posix.Terminal.ByteString: Kill :: ControlCharacter
+ System.Posix.Terminal.ByteString: LocalMode :: TerminalMode
+ System.Posix.Terminal.ByteString: MapCRtoLF :: TerminalMode
+ System.Posix.Terminal.ByteString: MapLFtoCR :: TerminalMode
+ System.Posix.Terminal.ByteString: MarkParityErrors :: TerminalMode
+ System.Posix.Terminal.ByteString: NoFlushOnInterrupt :: TerminalMode
+ System.Posix.Terminal.ByteString: OddParity :: TerminalMode
+ System.Posix.Terminal.ByteString: OutputQueue :: QueueSelector
+ System.Posix.Terminal.ByteString: ProcessInput :: TerminalMode
+ System.Posix.Terminal.ByteString: ProcessOutput :: TerminalMode
+ System.Posix.Terminal.ByteString: Quit :: ControlCharacter
+ System.Posix.Terminal.ByteString: ReadEnable :: TerminalMode
+ System.Posix.Terminal.ByteString: RestartOutput :: FlowAction
+ System.Posix.Terminal.ByteString: Start :: ControlCharacter
+ System.Posix.Terminal.ByteString: StartStopInput :: TerminalMode
+ System.Posix.Terminal.ByteString: StartStopOutput :: TerminalMode
+ System.Posix.Terminal.ByteString: Stop :: ControlCharacter
+ System.Posix.Terminal.ByteString: StripHighBit :: TerminalMode
+ System.Posix.Terminal.ByteString: Suspend :: ControlCharacter
+ System.Posix.Terminal.ByteString: SuspendOutput :: FlowAction
+ System.Posix.Terminal.ByteString: TransmitStart :: FlowAction
+ System.Posix.Terminal.ByteString: TransmitStop :: FlowAction
+ System.Posix.Terminal.ByteString: TwoStopBits :: TerminalMode
+ System.Posix.Terminal.ByteString: WhenDrained :: TerminalState
+ System.Posix.Terminal.ByteString: WhenFlushed :: TerminalState
+ System.Posix.Terminal.ByteString: bitsPerByte :: TerminalAttributes -> Int
+ System.Posix.Terminal.ByteString: controlChar :: TerminalAttributes -> ControlCharacter -> Maybe Char
+ System.Posix.Terminal.ByteString: controlFlow :: Fd -> FlowAction -> IO ()
+ System.Posix.Terminal.ByteString: data BaudRate
+ System.Posix.Terminal.ByteString: data ControlCharacter
+ System.Posix.Terminal.ByteString: data FlowAction
+ System.Posix.Terminal.ByteString: data QueueSelector
+ System.Posix.Terminal.ByteString: data TerminalAttributes
+ System.Posix.Terminal.ByteString: data TerminalMode
+ System.Posix.Terminal.ByteString: data TerminalState
+ System.Posix.Terminal.ByteString: discardData :: Fd -> QueueSelector -> IO ()
+ System.Posix.Terminal.ByteString: drainOutput :: Fd -> IO ()
+ System.Posix.Terminal.ByteString: getControllingTerminalName :: IO RawFilePath
+ System.Posix.Terminal.ByteString: getSlaveTerminalName :: Fd -> IO RawFilePath
+ System.Posix.Terminal.ByteString: getTerminalAttributes :: Fd -> IO TerminalAttributes
+ System.Posix.Terminal.ByteString: getTerminalName :: Fd -> IO RawFilePath
+ System.Posix.Terminal.ByteString: getTerminalProcessGroupID :: Fd -> IO ProcessGroupID
+ System.Posix.Terminal.ByteString: inputSpeed :: TerminalAttributes -> BaudRate
+ System.Posix.Terminal.ByteString: inputTime :: TerminalAttributes -> Int
+ System.Posix.Terminal.ByteString: minInput :: TerminalAttributes -> Int
+ System.Posix.Terminal.ByteString: openPseudoTerminal :: IO (Fd, Fd)
+ System.Posix.Terminal.ByteString: outputSpeed :: TerminalAttributes -> BaudRate
+ System.Posix.Terminal.ByteString: queryTerminal :: Fd -> IO Bool
+ System.Posix.Terminal.ByteString: sendBreak :: Fd -> Int -> IO ()
+ System.Posix.Terminal.ByteString: setTerminalAttributes :: Fd -> TerminalAttributes -> TerminalState -> IO ()
+ System.Posix.Terminal.ByteString: setTerminalProcessGroupID :: Fd -> ProcessGroupID -> IO ()
+ System.Posix.Terminal.ByteString: terminalMode :: TerminalMode -> TerminalAttributes -> Bool
+ System.Posix.Terminal.ByteString: withBits :: TerminalAttributes -> Int -> TerminalAttributes
+ System.Posix.Terminal.ByteString: withCC :: TerminalAttributes -> (ControlCharacter, Char) -> TerminalAttributes
+ System.Posix.Terminal.ByteString: withInputSpeed :: TerminalAttributes -> BaudRate -> TerminalAttributes
+ System.Posix.Terminal.ByteString: withMinInput :: TerminalAttributes -> Int -> TerminalAttributes
+ System.Posix.Terminal.ByteString: withMode :: TerminalAttributes -> TerminalMode -> TerminalAttributes
+ System.Posix.Terminal.ByteString: withOutputSpeed :: TerminalAttributes -> BaudRate -> TerminalAttributes
+ System.Posix.Terminal.ByteString: withTime :: TerminalAttributes -> Int -> TerminalAttributes
+ System.Posix.Terminal.ByteString: withoutCC :: TerminalAttributes -> ControlCharacter -> TerminalAttributes
+ System.Posix.Terminal.ByteString: withoutMode :: TerminalAttributes -> TerminalMode -> TerminalAttributes
- System.Posix.Error: throwErrnoPathIfMinus1 :: Num a => String -> FilePath -> IO a -> IO a
+ System.Posix.Error: throwErrnoPathIfMinus1 :: (Eq a, Num a) => String -> FilePath -> IO a -> IO a
- System.Posix.Error: throwErrnoPathIfMinus1Retry :: Num a => String -> FilePath -> IO a -> IO a
+ System.Posix.Error: throwErrnoPathIfMinus1Retry :: (Eq a, Num a) => String -> FilePath -> IO a -> IO a
- System.Posix.Error: throwErrnoPathIfMinus1Retry_ :: Num a => String -> FilePath -> IO a -> IO ()
+ System.Posix.Error: throwErrnoPathIfMinus1Retry_ :: (Eq a, Num a) => String -> FilePath -> IO a -> IO ()
- System.Posix.Error: throwErrnoPathIfMinus1_ :: Num a => String -> FilePath -> IO a -> IO ()
+ System.Posix.Error: throwErrnoPathIfMinus1_ :: (Eq a, Num a) => String -> FilePath -> IO a -> IO ()
Files
- System/Posix.hs +10/−1
- System/Posix/ByteString.hs +69/−0
- System/Posix/ByteString/FilePath.hsc +123/−0
- System/Posix/Directory.hsc +9/−53
- System/Posix/Directory/ByteString.hsc +155/−0
- System/Posix/Directory/Common.hsc +80/−0
- System/Posix/DynamicLinker.hsc +8/−35
- System/Posix/DynamicLinker/ByteString.hsc +70/−0
- System/Posix/DynamicLinker/Common.hsc +90/−0
- System/Posix/DynamicLinker/Module.hsc +5/−5
- System/Posix/DynamicLinker/Module/ByteString.hsc +77/−0
- System/Posix/DynamicLinker/Prim.hsc +5/−2
- System/Posix/Env.hsc +4/−1
- System/Posix/Env/ByteString.hsc +165/−0
- System/Posix/Error.hs +7/−2
- System/Posix/Files.hsc +12/−328
- System/Posix/Files/ByteString.hsc +382/−0
- System/Posix/Files/Common.hsc +408/−0
- System/Posix/IO.hsc +10/−393
- System/Posix/IO/ByteString.hsc +102/−0
- System/Posix/IO/Common.hsc +456/−0
- System/Posix/Process.hsc +6/−331
- System/Posix/Process/ByteString.hsc +140/−0
- System/Posix/Process/Common.hsc +401/−0
- System/Posix/Process/Internals.hs +3/−0
- System/Posix/Resource.hsc +3/−0
- System/Posix/Semaphore.hsc +3/−1
- System/Posix/SharedMem.hsc +3/−1
- System/Posix/Signals.hsc +6/−3
- System/Posix/Signals/Exts.hsc +4/−1
- System/Posix/Temp.hsc +3/−0
- System/Posix/Temp/ByteString.hsc +82/−0
- System/Posix/Terminal.hsc +30/−631
- System/Posix/Terminal/ByteString.hsc +194/−0
- System/Posix/Terminal/Common.hsc +705/−0
- System/Posix/Time.hsc +3/−0
- System/Posix/Unistd.hsc +3/−0
- System/Posix/User.hsc +3/−0
- cbits/HsUnix.c +3/−3
- unix.cabal +44/−13
System/Posix.hs view
@@ -1,3 +1,6 @@+#if __GLASGOW_HASKELL__ >= 701+{-# LANGUAGE Safe #-}+#endif ----------------------------------------------------------------------------- -- | -- Module : System.Posix@@ -27,7 +30,10 @@ module System.Posix.User, module System.Posix.Resource, module System.Posix.Semaphore,- module System.Posix.SharedMem+ module System.Posix.SharedMem,+ module System.Posix.DynamicLinker,+-- XXX 'Module' type clashes with GHC+-- module System.Posix.DynamicLinker.Module ) where import System.Posix.Types@@ -45,6 +51,9 @@ import System.Posix.Resource import System.Posix.Semaphore import System.Posix.SharedMem+-- XXX: bad planning, we have two constructors called "Default"+import System.Posix.DynamicLinker hiding (Default)+--import System.Posix.DynamicLinker.Module {- TODO
+ System/Posix/ByteString.hs view
@@ -0,0 +1,69 @@+#if __GLASGOW_HASKELL__ >= 701+{-# LANGUAGE Safe #-}+#endif+-----------------------------------------------------------------------------+-- |+-- Module : System.Posix.ByteString+-- 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 support with ByteString file paths and environment strings.+--+-- This module exports exactly the same API as "System.Posix", except+-- that all file paths and environment strings are represented by+-- 'ByteString' instead of 'String'. The "System.Posix" API+-- implicitly translates all file paths and environment strings using+-- the locale encoding, whereas this version of the API does no+-- encoding or decoding and works directly in terms of raw bytes.+--+-- Note that if you do need to interpret file paths or environment+-- strings as text, then some Unicode encoding or decoding should be+-- applied first.+--+-----------------------------------------------------------------------------++module System.Posix.ByteString (+ System.Posix.ByteString.FilePath.RawFilePath,+ module System.Posix.Types,+ module System.Posix.Signals,+ module System.Posix.Directory.ByteString,+ module System.Posix.Files.ByteString,+ module System.Posix.Unistd,+ module System.Posix.IO.ByteString,+ module System.Posix.Env.ByteString,+ module System.Posix.Process.ByteString,+ module System.Posix.Temp.ByteString,+ module System.Posix.Terminal.ByteString,+ module System.Posix.Time,+ module System.Posix.User,+ module System.Posix.Resource,+ module System.Posix.Semaphore,+ module System.Posix.SharedMem,+ module System.Posix.DynamicLinker.ByteString,+-- XXX 'Module' type clashes with GHC+-- module System.Posix.DynamicLinker.Module.ByteString+ ) where++import System.Posix.ByteString.FilePath+import System.Posix.Types+import System.Posix.Signals+import System.Posix.Directory.ByteString+import System.Posix.Files.ByteString+import System.Posix.Unistd+import System.Posix.Process.ByteString+import System.Posix.IO.ByteString+import System.Posix.Env.ByteString+import System.Posix.Temp.ByteString+import System.Posix.Terminal.ByteString+import System.Posix.Time+import System.Posix.User+import System.Posix.Resource+import System.Posix.Semaphore+import System.Posix.SharedMem+-- XXX: bad planning, we have two constructors called "Default"+import System.Posix.DynamicLinker.ByteString hiding (Default)+--import System.Posix.DynamicLinker.Module.ByteString
+ System/Posix/ByteString/FilePath.hsc view
@@ -0,0 +1,123 @@+#if __GLASGOW_HASKELL__ >= 701+{-# LANGUAGE Trustworthy #-}+#endif+-----------------------------------------------------------------------------+-- |+-- Module : System.Posix.ByteString.FilePath+-- 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)+--+-- Internal stuff: support for ByteString FilePaths+--+-----------------------------------------------------------------------------++module System.Posix.ByteString.FilePath (+ RawFilePath, withFilePath, peekFilePath, peekFilePathLen,+ throwErrnoPathIfMinus1Retry,+ throwErrnoPathIfMinus1Retry_,+ throwErrnoPathIfNullRetry,+ throwErrnoPathIfRetry,+ throwErrnoPath,+ throwErrnoPathIf,+ throwErrnoPathIf_,+ throwErrnoPathIfNull,+ throwErrnoPathIfMinus1,+ throwErrnoPathIfMinus1_+ ) where++import Foreign+import Foreign.C hiding (+ throwErrnoPath,+ throwErrnoPathIf,+ throwErrnoPathIf_,+ throwErrnoPathIfNull,+ throwErrnoPathIfMinus1,+ throwErrnoPathIfMinus1_ )++import Data.ByteString+import Data.ByteString.Char8 as BC+import Prelude hiding (FilePath)++-- | A literal POSIX file path+type RawFilePath = ByteString++withFilePath :: RawFilePath -> (CString -> IO a) -> IO a+withFilePath = useAsCString++peekFilePath :: CString -> IO RawFilePath+peekFilePath = packCString++peekFilePathLen :: CStringLen -> IO RawFilePath+peekFilePathLen = packCStringLen+++throwErrnoPathIfMinus1Retry :: (Eq a, Num a)+ => String -> RawFilePath -> IO a -> IO a+throwErrnoPathIfMinus1Retry loc path f = do+ throwErrnoPathIfRetry (== -1) loc path f++throwErrnoPathIfMinus1Retry_ :: (Eq a, Num a)+ => String -> RawFilePath -> IO a -> IO ()+throwErrnoPathIfMinus1Retry_ loc path f =+ void $ throwErrnoPathIfRetry (== -1) loc path f++throwErrnoPathIfNullRetry :: String -> RawFilePath -> IO (Ptr a) -> IO (Ptr a)+throwErrnoPathIfNullRetry loc path f =+ throwErrnoPathIfRetry (== nullPtr) loc path f++throwErrnoPathIfRetry :: (a -> Bool) -> String -> RawFilePath -> IO a -> IO a+throwErrnoPathIfRetry pr loc rpath f =+ do+ res <- f+ if pr res+ then do+ err <- getErrno+ if err == eINTR+ then throwErrnoPathIfRetry pr loc rpath f+ else throwErrnoPath loc rpath+ else return res++-- | as 'throwErrno', but exceptions include the given path when appropriate.+--+throwErrnoPath :: String -> RawFilePath -> IO a+throwErrnoPath loc path =+ do+ errno <- getErrno+ ioError (errnoToIOError loc errno Nothing (Just (BC.unpack path)))++-- | as 'throwErrnoIf', but exceptions include the given path when+-- appropriate.+--+throwErrnoPathIf :: (a -> Bool) -> String -> RawFilePath -> IO a -> IO a+throwErrnoPathIf cond loc path f =+ do+ res <- f+ if cond res then throwErrnoPath loc path else return res++-- | as 'throwErrnoIf_', but exceptions include the given path when+-- appropriate.+--+throwErrnoPathIf_ :: (a -> Bool) -> String -> RawFilePath -> IO a -> IO ()+throwErrnoPathIf_ cond loc path f = void $ throwErrnoPathIf cond loc path f++-- | as 'throwErrnoIfNull', but exceptions include the given path when+-- appropriate.+--+throwErrnoPathIfNull :: String -> RawFilePath -> IO (Ptr a) -> IO (Ptr a)+throwErrnoPathIfNull = throwErrnoPathIf (== nullPtr)++-- | as 'throwErrnoIfMinus1', but exceptions include the given path when+-- appropriate.+--+throwErrnoPathIfMinus1 :: (Eq a, Num a) => String -> RawFilePath -> IO a -> IO a+throwErrnoPathIfMinus1 = throwErrnoPathIf (== -1)++-- | as 'throwErrnoIfMinus1_', but exceptions include the given path when+-- appropriate.+--+throwErrnoPathIfMinus1_ :: (Eq a, Num a) => String -> RawFilePath -> IO a -> IO ()+throwErrnoPathIfMinus1_ = throwErrnoPathIf_ (== -1)
System/Posix/Directory.hsc view
@@ -1,8 +1,12 @@ {-# LANGUAGE ForeignFunctionInterface #-} {-# OPTIONS_GHC -fno-warn-unused-imports #-}+#if __GLASGOW_HASKELL__ >= 701+{-# LANGUAGE Trustworthy #-}+#endif+ ----------------------------------------------------------------------------- -- |--- Module : System.Posix.Files+-- Module : System.Posix.Directory -- Copyright : (c) The University of Glasgow 2002 -- License : BSD-style (see the file libraries/base/LICENSE) -- @@ -10,7 +14,7 @@ -- Stability : provisional -- Portability : non-portable (requires POSIX) ----- POSIX directory support+-- String-based POSIX directory support -- ----------------------------------------------------------------------------- @@ -39,6 +43,9 @@ import System.Posix.Types import Foreign import Foreign.C++import System.Posix.Directory.Common+ #if __GLASGOW_HASKELL__ > 700 import System.Posix.Internals (withFilePath, peekFilePath) #elif __GLASGOW_HASKELL__ > 611@@ -67,8 +74,6 @@ foreign import ccall unsafe "mkdir" c_mkdir :: CString -> CMode -> IO CInt -newtype DirStream = DirStream (Ptr CDir)- -- | @openDirStream dir@ calls @opendir@ to obtain a -- directory stream for @dir@. openDirStream :: FilePath -> IO DirStream@@ -106,9 +111,6 @@ then return [] else throwErrno "readDirStream" -type CDir = ()-type CDirent = ()- -- traversing directories foreign import ccall unsafe "__hscore_readdir" c_readdir :: Ptr CDir -> Ptr (Ptr CDirent) -> IO CInt@@ -119,46 +121,7 @@ foreign import ccall unsafe "__hscore_d_name" d_name :: Ptr CDirent -> IO CString --- | @rewindDirStream dp@ calls @rewinddir@ to reposition--- the directory stream @dp@ at the beginning of the directory.-rewindDirStream :: DirStream -> IO ()-rewindDirStream (DirStream dirp) = c_rewinddir dirp -foreign import ccall unsafe "rewinddir"- c_rewinddir :: Ptr CDir -> IO ()---- | @closeDirStream dp@ calls @closedir@ to close--- the directory stream @dp@.-closeDirStream :: DirStream -> IO ()-closeDirStream (DirStream dirp) = do- throwErrnoIfMinus1Retry_ "closeDirStream" (c_closedir dirp)--foreign import ccall unsafe "closedir"- c_closedir :: Ptr CDir -> IO CInt--newtype DirStreamOffset = DirStreamOffset COff--seekDirStream :: DirStream -> DirStreamOffset -> IO ()-seekDirStream (DirStream dirp) (DirStreamOffset off) =- c_seekdir dirp off--foreign import ccall unsafe "seekdir"- c_seekdir :: Ptr CDir -> COff -> IO ()--tellDirStream :: DirStream -> IO DirStreamOffset-tellDirStream (DirStream dirp) = do- off <- c_telldir dirp- return (DirStreamOffset off)--foreign import ccall unsafe "telldir"- c_telldir :: Ptr CDir -> IO COff--{-- Renamings of functionality provided via Directory interface,- kept around for b.wards compatibility and for having more POSIXy- names--}- -- | @getWorkingDirectory@ calls @getcwd@ to obtain the name -- of the current working directory. getWorkingDirectory :: IO FilePath@@ -203,10 +166,3 @@ foreign import ccall unsafe "rmdir" c_rmdir :: CString -> IO CInt--changeWorkingDirectoryFd :: Fd -> IO ()-changeWorkingDirectoryFd (Fd fd) = - throwErrnoIfMinus1Retry_ "changeWorkingDirectoryFd" (c_fchdir fd)--foreign import ccall unsafe "fchdir"- c_fchdir :: CInt -> IO CInt
+ System/Posix/Directory/ByteString.hsc view
@@ -0,0 +1,155 @@+{-# LANGUAGE ForeignFunctionInterface #-}+{-# OPTIONS_GHC -fno-warn-unused-imports #-}+#if __GLASGOW_HASKELL__ >= 701+{-# LANGUAGE Trustworthy #-}+#endif++-----------------------------------------------------------------------------+-- |+-- Module : System.Posix.Directory.ByteString+-- 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)+--+-- String-based POSIX directory support+--+-----------------------------------------------------------------------------++module System.Posix.Directory.ByteString (+ -- * Creating and removing directories+ createDirectory, removeDirectory,++ -- * Reading directories+ DirStream,+ openDirStream,+ readDirStream,+ rewindDirStream, + closeDirStream,+ DirStreamOffset,+ tellDirStream,+ seekDirStream,++ -- * The working dirctory+ getWorkingDirectory,+ changeWorkingDirectory,+ changeWorkingDirectoryFd,+ ) where++import System.IO.Error+import System.Posix.Types+import Foreign+import Foreign.C++import Data.ByteString.Char8 as BC++import System.Posix.Directory.Common+import System.Posix.ByteString.FilePath++-- | @createDirectory dir mode@ calls @mkdir@ to+-- create a new directory, @dir@, with permissions based on+-- @mode@.+createDirectory :: RawFilePath -> FileMode -> IO ()+createDirectory name mode =+ withFilePath name $ \s -> + throwErrnoPathIfMinus1Retry_ "createDirectory" name (c_mkdir s mode) + -- POSIX doesn't allow mkdir() to return EINTR, but it does on+ -- OS X (#5184), so we need the Retry variant here.++foreign import ccall unsafe "mkdir"+ c_mkdir :: CString -> CMode -> IO CInt++-- | @openDirStream dir@ calls @opendir@ to obtain a+-- directory stream for @dir@.+openDirStream :: RawFilePath -> IO DirStream+openDirStream name =+ withFilePath name $ \s -> do+ dirp <- throwErrnoPathIfNullRetry "openDirStream" name $ c_opendir s+ return (DirStream dirp)++foreign import ccall unsafe "__hsunix_opendir"+ c_opendir :: CString -> IO (Ptr CDir)++-- | @readDirStream dp@ calls @readdir@ to obtain the+-- next directory entry (@struct dirent@) for the open directory+-- stream @dp@, and returns the @d_name@ member of that+-- structure.+readDirStream :: DirStream -> IO RawFilePath+readDirStream (DirStream dirp) =+ alloca $ \ptr_dEnt -> loop ptr_dEnt+ where+ loop ptr_dEnt = do+ resetErrno+ r <- c_readdir dirp ptr_dEnt+ if (r == 0)+ then do dEnt <- peek ptr_dEnt+ if (dEnt == nullPtr)+ then return BC.empty+ else do+ entry <- (d_name dEnt >>= peekFilePath)+ c_freeDirEnt dEnt+ return entry+ else do errno <- getErrno+ if (errno == eINTR) then loop ptr_dEnt else do+ let (Errno eo) = errno+ if (eo == 0)+ then return BC.empty+ else throwErrno "readDirStream"++-- traversing directories+foreign import ccall unsafe "__hscore_readdir"+ c_readdir :: Ptr CDir -> Ptr (Ptr CDirent) -> IO CInt++foreign import ccall unsafe "__hscore_free_dirent"+ c_freeDirEnt :: Ptr CDirent -> IO ()++foreign import ccall unsafe "__hscore_d_name"+ d_name :: Ptr CDirent -> IO CString+++-- | @getWorkingDirectory@ calls @getcwd@ to obtain the name+-- of the current working directory.+getWorkingDirectory :: IO RawFilePath+getWorkingDirectory = do+ p <- mallocBytes long_path_size+ go p long_path_size+ where go p bytes = do+ p' <- c_getcwd p (fromIntegral bytes)+ if p' /= nullPtr + then do s <- peekFilePath p'+ free p'+ return s+ else do errno <- getErrno+ if errno == eRANGE+ then do let bytes' = bytes * 2+ p'' <- reallocBytes p bytes'+ go p'' bytes'+ else throwErrno "getCurrentDirectory"++foreign import ccall unsafe "getcwd"+ c_getcwd :: Ptr CChar -> CSize -> IO (Ptr CChar)++foreign import ccall unsafe "__hsunix_long_path_size"+ long_path_size :: Int++-- | @changeWorkingDirectory dir@ calls @chdir@ to change+-- the current working directory to @dir@.+changeWorkingDirectory :: RawFilePath -> IO ()+changeWorkingDirectory path =+ modifyIOError (`ioeSetFileName` (BC.unpack path)) $+ withFilePath path $ \s -> + throwErrnoIfMinus1Retry_ "changeWorkingDirectory" (c_chdir s)++foreign import ccall unsafe "chdir"+ c_chdir :: CString -> IO CInt++removeDirectory :: RawFilePath -> IO ()+removeDirectory path =+ modifyIOError (`ioeSetFileName` BC.unpack path) $+ withFilePath path $ \s ->+ throwErrnoIfMinus1Retry_ "removeDirectory" (c_rmdir s)++foreign import ccall unsafe "rmdir"+ c_rmdir :: CString -> IO CInt
+ System/Posix/Directory/Common.hsc view
@@ -0,0 +1,80 @@+{-# LANGUAGE ForeignFunctionInterface #-}+{-# OPTIONS_GHC -fno-warn-unused-imports #-}+#if __GLASGOW_HASKELL__ >= 701+{-# LANGUAGE Trustworthy #-}+#endif++-----------------------------------------------------------------------------+-- |+-- Module : System.Posix.Directory.Common+-- 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 directory support+--+-----------------------------------------------------------------------------++module System.Posix.Directory.Common (+ DirStream(..), CDir, CDirent, DirStreamOffset(..),+ rewindDirStream,+ closeDirStream,+ seekDirStream,+ tellDirStream,+ changeWorkingDirectoryFd,+ ) where++import System.IO.Error+import System.Posix.Error+import System.Posix.Types+import Foreign+import Foreign.C++newtype DirStream = DirStream (Ptr CDir)++type CDir = ()+type CDirent = ()++-- | @rewindDirStream dp@ calls @rewinddir@ to reposition+-- the directory stream @dp@ at the beginning of the directory.+rewindDirStream :: DirStream -> IO ()+rewindDirStream (DirStream dirp) = c_rewinddir dirp++foreign import ccall unsafe "rewinddir"+ c_rewinddir :: Ptr CDir -> IO ()++-- | @closeDirStream dp@ calls @closedir@ to close+-- the directory stream @dp@.+closeDirStream :: DirStream -> IO ()+closeDirStream (DirStream dirp) = do+ throwErrnoIfMinus1Retry_ "closeDirStream" (c_closedir dirp)++foreign import ccall unsafe "closedir"+ c_closedir :: Ptr CDir -> IO CInt++newtype DirStreamOffset = DirStreamOffset COff++seekDirStream :: DirStream -> DirStreamOffset -> IO ()+seekDirStream (DirStream dirp) (DirStreamOffset off) =+ c_seekdir dirp off++foreign import ccall unsafe "seekdir"+ c_seekdir :: Ptr CDir -> COff -> IO ()++tellDirStream :: DirStream -> IO DirStreamOffset+tellDirStream (DirStream dirp) = do+ off <- c_telldir dirp+ return (DirStreamOffset off)++foreign import ccall unsafe "telldir"+ c_telldir :: Ptr CDir -> IO COff++changeWorkingDirectoryFd :: Fd -> IO ()+changeWorkingDirectoryFd (Fd fd) = + throwErrnoIfMinus1Retry_ "changeWorkingDirectoryFd" (c_fchdir fd)++foreign import ccall unsafe "fchdir"+ c_fchdir :: CInt -> IO CInt
System/Posix/DynamicLinker.hsc view
@@ -1,3 +1,6 @@+#if __GLASGOW_HASKELL__ >= 701+{-# LANGUAGE Trustworthy #-}+#endif ----------------------------------------------------------------------------- -- | -- Module : System.Posix.DynamicLinker@@ -45,13 +48,14 @@ where +import System.Posix.DynamicLinker.Common+import System.Posix.DynamicLinker.Prim+ #include "HsUnix.h" -import System.Posix.DynamicLinker.Prim-import Control.Exception ( bracket )+import Control.Exception ( bracket ) import Control.Monad ( liftM )-import Foreign.Ptr ( Ptr, nullPtr, FunPtr, nullFunPtr )-import Foreign.C.String+import Foreign #if __GLASGOW_HASKELL__ > 611 import System.Posix.Internals ( withFilePath ) #else@@ -64,39 +68,8 @@ withFilePath path $ \ p -> do liftM DLHandle $ throwDLErrorIf "dlopen" (== nullPtr) $ c_dlopen p (packRTLDFlags flags) -dlclose :: DL -> IO ()-dlclose (DLHandle h) = throwDLErrorIf_ "dlclose" (/= 0) $ c_dlclose h-dlclose h = error $ "dlclose: invalid argument" ++ (show h)--dlerror :: IO String-dlerror = c_dlerror >>= peekCString ---- |'dlsym' returns the address binding of the symbol described in @symbol@,--- as it occurs in the shared object identified by @source@.--dlsym :: DL -> String -> IO (FunPtr a)-dlsym source symbol = do- withCAString symbol $ \ s -> do- throwDLErrorIf "dlsym" (== nullFunPtr) $ c_dlsym (packDL source) s- withDL :: String -> [RTLDFlags] -> (DL -> IO a) -> IO a withDL file flags f = bracket (dlopen file flags) (dlclose) f withDL_ :: String -> [RTLDFlags] -> (DL -> IO a) -> IO () withDL_ file flags f = withDL file flags f >> return ()---- |'undl' obtains the raw handle. You mustn't do something like--- @withDL mod flags $ liftM undl >>= \ p -> use p@--undl :: DL -> Ptr ()-undl = packDL--throwDLErrorIf :: String -> (a -> Bool) -> IO a -> IO a-throwDLErrorIf s p f = do- r <- f- if (p r)- then dlerror >>= \ err -> ioError (userError ( s ++ ": " ++ err))- else return r--throwDLErrorIf_ :: String -> (a -> Bool) -> IO a -> IO ()-throwDLErrorIf_ s p f = throwDLErrorIf s p f >> return ()
+ System/Posix/DynamicLinker/ByteString.hsc view
@@ -0,0 +1,70 @@+#if __GLASGOW_HASKELL__ >= 701+{-# LANGUAGE Trustworthy #-}+#endif+-----------------------------------------------------------------------------+-- |+-- Module : System.Posix.DynamicLinker.ByteString+-- Copyright : (c) Volker Stolz <vs@foldr.org> 2003+-- License : BSD-style (see the file libraries/base/LICENSE)+-- +-- Maintainer : vs@foldr.org+-- Stability : provisional+-- Portability : non-portable (requires POSIX)+--+-- Dynamic linker support through dlopen()+-----------------------------------------------------------------------------++module System.Posix.DynamicLinker.ByteString (++ module System.Posix.DynamicLinker.Prim,+ dlopen,+ dlsym,+ dlerror,+ dlclose,+ withDL, withDL_,+ undl,+ )++-- Usage:+-- ******+-- +-- Let's assume you want to open a local shared library \'foo\' (.\/libfoo.so)+-- offering a function+-- @char \* mogrify (char\*,int)@+-- and invoke @str = mogrify("test",1)@:+-- +-- +-- type Fun = CString -> Int -> IO CString+-- foreign import dynamic unsafe fun__ :: FunPtr Fun -> Fun+-- +-- withDL "libfoo.so" [RTLD_NOW] \$ \\ mod -> do+-- funptr <- dlsym mod "mogrify"+-- let fun = fun__ funptr+-- withCString "test" \$ \\ str -> do+-- strptr <- fun str 1+-- strstr <- peekCString strptr+-- ...+-- ++where++import System.Posix.DynamicLinker.Common+import System.Posix.DynamicLinker.Prim++#include "HsUnix.h"++import Control.Exception ( bracket )+import Control.Monad ( liftM )+import Foreign+import System.Posix.ByteString.FilePath++dlopen :: RawFilePath -> [RTLDFlags] -> IO DL+dlopen path flags = do+ withFilePath path $ \ p -> do+ liftM DLHandle $ throwDLErrorIf "dlopen" (== nullPtr) $ c_dlopen p (packRTLDFlags flags)++withDL :: RawFilePath -> [RTLDFlags] -> (DL -> IO a) -> IO a+withDL file flags f = bracket (dlopen file flags) (dlclose) f++withDL_ :: RawFilePath -> [RTLDFlags] -> (DL -> IO a) -> IO ()+withDL_ file flags f = withDL file flags f >> return ()
+ System/Posix/DynamicLinker/Common.hsc view
@@ -0,0 +1,90 @@+#if __GLASGOW_HASKELL__ >= 701+{-# LANGUAGE Trustworthy #-}+#endif+-----------------------------------------------------------------------------+-- |+-- Module : System.Posix.DynamicLinker.Common+-- Copyright : (c) Volker Stolz <vs@foldr.org> 2003+-- License : BSD-style (see the file libraries/base/LICENSE)+-- +-- Maintainer : vs@foldr.org+-- Stability : provisional+-- Portability : non-portable (requires POSIX)+--+-- Dynamic linker support through dlopen()+-----------------------------------------------------------------------------++module System.Posix.DynamicLinker.Common (++ module System.Posix.DynamicLinker.Prim,+ dlsym,+ dlerror,+ dlclose,+ undl,+ throwDLErrorIf,+ Module(..)+ )++-- Usage:+-- ******+-- +-- Let's assume you want to open a local shared library \'foo\' (.\/libfoo.so)+-- offering a function+-- @char \* mogrify (char\*,int)@+-- and invoke @str = mogrify("test",1)@:+-- +-- +-- type Fun = CString -> Int -> IO CString+-- foreign import dynamic unsafe fun__ :: FunPtr Fun -> Fun+-- +-- withDL "libfoo.so" [RTLD_NOW] \$ \\ mod -> do+-- funptr <- dlsym mod "mogrify"+-- let fun = fun__ funptr+-- withCString "test" \$ \\ str -> do+-- strptr <- fun str 1+-- strstr <- peekCString strptr+-- ...+-- ++where++#include "HsUnix.h"++import System.Posix.DynamicLinker.Prim+import Foreign+import Foreign.C++dlclose :: DL -> IO ()+dlclose (DLHandle h) = throwDLErrorIf_ "dlclose" (/= 0) $ c_dlclose h+dlclose h = error $ "dlclose: invalid argument" ++ (show h)++dlerror :: IO String+dlerror = c_dlerror >>= peekCString ++-- |'dlsym' returns the address binding of the symbol described in @symbol@,+-- as it occurs in the shared object identified by @source@.++dlsym :: DL -> String -> IO (FunPtr a)+dlsym source symbol = do+ withCAString symbol $ \ s -> do+ throwDLErrorIf "dlsym" (== nullFunPtr) $ c_dlsym (packDL source) s++-- |'undl' obtains the raw handle. You mustn't do something like+-- @withDL mod flags $ liftM undl >>= \ p -> use p@++undl :: DL -> Ptr ()+undl = packDL++throwDLErrorIf :: String -> (a -> Bool) -> IO a -> IO a+throwDLErrorIf s p f = do+ r <- f+ if (p r)+ then dlerror >>= \ err -> ioError (userError ( s ++ ": " ++ err))+ else return r++throwDLErrorIf_ :: String -> (a -> Bool) -> IO a -> IO ()+throwDLErrorIf_ s p f = throwDLErrorIf s p f >> return ()++-- abstract handle for dynamically loaded module (EXPORTED)+--+newtype Module = Module (Ptr ())
System/Posix/DynamicLinker/Module.hsc view
@@ -1,4 +1,7 @@ {-# LANGUAGE ForeignFunctionInterface #-}+#if __GLASGOW_HASKELL__ >= 701+{-# LANGUAGE Trustworthy #-}+#endif ----------------------------------------------------------------------------- -- | -- Module : System.Posix.DynamicLinker.Module@@ -57,7 +60,8 @@ #include "HsUnix.h" import System.Posix.DynamicLinker-import Foreign.Ptr ( Ptr, nullPtr, FunPtr )+import System.Posix.DynamicLinker.Common+import Foreign.Ptr ( Ptr, nullPtr, FunPtr ) #if __GLASGOW_HASKELL__ > 611 import System.Posix.Internals ( withFilePath ) #else@@ -66,10 +70,6 @@ withFilePath :: FilePath -> (CString -> IO a) -> IO a withFilePath = withCString #endif---- abstract handle for dynamically loaded module (EXPORTED)----newtype Module = Module (Ptr ()) unModule :: Module -> (Ptr ()) unModule (Module adr) = adr
+ System/Posix/DynamicLinker/Module/ByteString.hsc view
@@ -0,0 +1,77 @@+{-# LANGUAGE ForeignFunctionInterface #-}+#if __GLASGOW_HASKELL__ >= 701+{-# LANGUAGE Trustworthy #-}+#endif+-----------------------------------------------------------------------------+-- |+-- Module : System.Posix.DynamicLinker.Module.ByteString+-- Copyright : (c) Volker Stolz <vs@foldr.org> 2003+-- License : BSD-style (see the file libraries/base/LICENSE)+-- +-- Maintainer : vs@foldr.org+-- Stability : provisional+-- Portability : non-portable (requires POSIX)+--+-- DLOpen support, old API+-- Derived from GModule.chs by M.Weber & M.Chakravarty which is part of c2hs+-- I left the API more or less the same, mostly the flags are different.+--+-----------------------------------------------------------------------------++module System.Posix.DynamicLinker.Module.ByteString (++-- Usage:+-- ******+-- +-- Let's assume you want to open a local shared library 'foo' (./libfoo.so)+-- offering a function+-- char * mogrify (char*,int)+-- and invoke str = mogrify("test",1):+-- +-- type Fun = CString -> Int -> IO CString+-- foreign import dynamic unsafe fun__ :: FunPtr Fun -> Fun+-- +-- withModule (Just ".") ("libfoo.so") [RTLD_NOW] $ \ mod -> do+-- funptr <- moduleSymbol mod "mogrify"+-- let fun = fun__ funptr+-- withCString "test" $ \ str -> do+-- strptr <- fun str 1+-- strstr <- peekCString strptr+-- ...++ Module+ , moduleOpen -- :: String -> ModuleFlags -> IO Module+ , moduleSymbol -- :: Source -> String -> IO (FunPtr a)+ , moduleClose -- :: Module -> IO Bool+ , moduleError -- :: IO String+ , withModule -- :: Maybe String + -- -> String + -- -> [ModuleFlags ]+ -- -> (Module -> IO a) + -- -> IO a+ , withModule_ -- :: Maybe String + -- -> String + -- -> [ModuleFlags] + -- -> (Module -> IO a) + -- -> IO ()+ )+where++#include "HsUnix.h"++import System.Posix.DynamicLinker.Module hiding (moduleOpen)+import System.Posix.DynamicLinker.Prim+import System.Posix.DynamicLinker.Common++import Foreign+import System.Posix.ByteString.FilePath++-- Opens a module (EXPORTED)+--++moduleOpen :: RawFilePath -> [RTLDFlags] -> IO Module+moduleOpen file flags = do+ modPtr <- withFilePath file $ \ modAddr -> c_dlopen modAddr (packRTLDFlags flags)+ if (modPtr == nullPtr)+ then moduleError >>= \ err -> ioError (userError ("dlopen: " ++ err))+ else return $ Module modPtr
System/Posix/DynamicLinker/Prim.hsc view
@@ -1,4 +1,7 @@ {-# LANGUAGE ForeignFunctionInterface #-}+#if __GLASGOW_HASKELL__ >= 701+{-# LANGUAGE Trustworthy #-}+#endif ----------------------------------------------------------------------------- -- | -- Module : System.Posix.DynamicLinker.Prim@@ -27,7 +30,7 @@ packRTLDFlags, RTLDFlags(..), packDL,- DL(..)+ DL(..), ) where@@ -36,7 +39,7 @@ import Data.Bits ( (.|.) ) import Foreign.Ptr ( Ptr, FunPtr, nullPtr )-import Foreign.C.Types ( CInt )+import Foreign.C.Types import Foreign.C.String ( CString ) -- RTLD_NEXT madness
System/Posix/Env.hsc view
@@ -1,4 +1,7 @@ {-# LANGUAGE ForeignFunctionInterface #-}+#if __GLASGOW_HASKELL__ >= 701+{-# LANGUAGE Trustworthy #-}+#endif ----------------------------------------------------------------------------- -- | -- Module : System.Posix.Env@@ -26,7 +29,7 @@ #include "HsUnix.h" import Foreign.C.Error ( throwErrnoIfMinus1_ )-import Foreign.C.Types ( CInt )+import Foreign.C.Types import Foreign.C.String import Foreign.Marshal.Array import Foreign.Ptr
+ System/Posix/Env/ByteString.hsc view
@@ -0,0 +1,165 @@+{-# LANGUAGE ForeignFunctionInterface #-}+#if __GLASGOW_HASKELL__ >= 701+{-# LANGUAGE Trustworthy #-}+#endif+-----------------------------------------------------------------------------+-- |+-- Module : System.Posix.Env.ByteString+-- 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 environment support+--+-----------------------------------------------------------------------------++module System.Posix.Env.ByteString (+ -- * Environment Variables+ getEnv+ , getEnvDefault+ , getEnvironmentPrim+ , getEnvironment+ , putEnv+ , setEnv+ , unsetEnv++ -- * Program arguments+ , getArgs+) where++#include "HsUnix.h"++import Foreign+import Foreign.C+import Control.Monad ( liftM )+import Data.Maybe ( fromMaybe )++import qualified Data.ByteString as B+import qualified Data.ByteString.Char8 as BC+import Data.ByteString (ByteString)++-- |'getEnv' looks up a variable in the environment.++getEnv :: ByteString -> IO (Maybe ByteString)+getEnv name = do+ litstring <- B.useAsCString name c_getenv+ if litstring /= nullPtr+ then liftM Just $ B.packCString litstring+ else return Nothing++-- |'getEnvDefault' is a wrapper around 'getEnv' where the+-- programmer can specify a fallback if the variable is not found+-- in the environment.++getEnvDefault :: ByteString -> ByteString -> IO ByteString+getEnvDefault name fallback = liftM (fromMaybe fallback) (getEnv name)++foreign import ccall unsafe "getenv"+ c_getenv :: CString -> IO CString++getEnvironmentPrim :: IO [ByteString]+getEnvironmentPrim = do+ c_environ <- getCEnviron+ arr <- peekArray0 nullPtr c_environ+ mapM B.packCString arr++getCEnviron :: IO (Ptr CString)+#if darwin_HOST_OS+-- You should not access _environ directly on Darwin in a bundle/shared library.+-- See #2458 and http://developer.apple.com/library/mac/#documentation/Darwin/Reference/ManPages/man7/environ.7.html+getCEnviron = nsGetEnviron >>= peek++foreign import ccall unsafe "_NSGetEnviron"+ nsGetEnviron :: IO (Ptr (Ptr CString))+#else+getCEnviron = peek c_environ_p++foreign import ccall unsafe "&environ"+ c_environ_p :: Ptr (Ptr CString)+#endif++-- |'getEnvironment' retrieves the entire environment as a+-- list of @(key,value)@ pairs.++getEnvironment :: IO [(ByteString,ByteString)]+getEnvironment = do+ env <- getEnvironmentPrim+ return $ map (dropEq.(BC.break ((==) '='))) env+ where+ dropEq (x,y)+ | BC.head y == '=' = (x,B.tail y)+ | otherwise = error $ "getEnvironment: insane variable " ++ BC.unpack x++-- |The 'unsetEnv' function deletes all instances of the variable name+-- from the environment.++unsetEnv :: ByteString -> IO ()+#ifdef HAVE_UNSETENV++unsetEnv name = B.useAsCString name $ \ s ->+ throwErrnoIfMinus1_ "unsetenv" (c_unsetenv s)++foreign import ccall unsafe "__hsunix_unsetenv"+ c_unsetenv :: CString -> IO CInt+#else+unsetEnv name = putEnv (name ++ "=")+#endif++-- |'putEnv' function takes an argument of the form @name=value@+-- and is equivalent to @setEnv(key,value,True{-overwrite-})@.++putEnv :: ByteString -> IO ()+putEnv keyvalue = B.useAsCString keyvalue $ \s ->+ throwErrnoIfMinus1_ "putenv" (c_putenv s)++foreign import ccall unsafe "putenv"+ c_putenv :: CString -> IO CInt++{- |The 'setEnv' function inserts or resets the environment variable name in+ the current environment list. If the variable @name@ does not exist in the+ list, it is inserted with the given value. If the variable does exist,+ the argument @overwrite@ is tested; if @overwrite@ is @False@, the variable is+ not reset, otherwise it is reset to the given value.+-}++setEnv :: ByteString -> ByteString -> Bool {-overwrite-} -> IO ()+#ifdef HAVE_SETENV+setEnv key value ovrwrt = do+ B.useAsCString key $ \ keyP ->+ B.useAsCString value $ \ valueP ->+ throwErrnoIfMinus1_ "setenv" $+ c_setenv keyP valueP (fromIntegral (fromEnum ovrwrt))++foreign import ccall unsafe "setenv"+ c_setenv :: CString -> CString -> CInt -> IO CInt+#else+setEnv key value True = putEnv (key++"="++value)+setEnv key value False = do+ res <- getEnv key+ case res of+ Just _ -> return ()+ Nothing -> putEnv (key++"="++value)+#endif++-- | Computation 'getArgs' returns a list of the program's command+-- line arguments (not including the program name), as 'ByteString's.+--+-- Unlike 'System.Environment.getArgs', this function does no Unicode+-- decoding of the arguments; you get the exact bytes that were passed+-- to the program by the OS. To interpret the arguments as text, some+-- Unicode decoding should be applied.+--+getArgs :: IO [ByteString]+getArgs =+ alloca $ \ p_argc ->+ alloca $ \ p_argv -> do+ getProgArgv p_argc p_argv+ p <- fromIntegral `liftM` peek p_argc+ argv <- peek p_argv+ peekArray (p - 1) (advancePtr argv 1) >>= mapM B.packCString++foreign import ccall unsafe "getProgArgv"+ getProgArgv :: Ptr CInt -> Ptr (Ptr CString) -> IO ()
System/Posix/Error.hs view
@@ -1,3 +1,6 @@+#if __GLASGOW_HASKELL__ >= 701+{-# LANGUAGE Trustworthy #-}+#endif ----------------------------------------------------------------------------- -- | -- Module : System.Posix.Error@@ -28,11 +31,13 @@ import Foreign import Foreign.C -throwErrnoPathIfMinus1Retry :: Num a => String -> FilePath -> IO a -> IO a+throwErrnoPathIfMinus1Retry :: (Eq a, Num a)+ => String -> FilePath -> IO a -> IO a throwErrnoPathIfMinus1Retry loc path f = throwErrnoPathIfRetry (== -1) loc path f -throwErrnoPathIfMinus1Retry_ :: Num a => String -> FilePath -> IO a -> IO ()+throwErrnoPathIfMinus1Retry_ :: (Eq a, Num a)+ => String -> FilePath -> IO a -> IO () throwErrnoPathIfMinus1Retry_ loc path f = void $ throwErrnoPathIfRetry (== -1) loc path f
System/Posix/Files.hsc view
@@ -1,5 +1,8 @@ {-# LANGUAGE ForeignFunctionInterface #-} {-# OPTIONS_GHC -fno-warn-unused-imports #-}+#if __GLASGOW_HASKELL__ >= 701+{-# LANGUAGE Trustworthy #-}+#endif ----------------------------------------------------------------------------- -- | -- Module : System.Posix.Files@@ -86,13 +89,15 @@ PathVar(..), getPathVar, getFdPathVar, ) where ++import Foreign+import Foreign.C+ import System.Posix.Error import System.Posix.Types-import System.IO.Unsafe-import Data.Bits import System.Posix.Internals-import Foreign hiding (unsafePerformIO)-import Foreign.C+import System.Posix.Files.Common+ #if __GLASGOW_HASKELL__ > 700 import System.Posix.Internals (withFilePath, peekFilePath) #elif __GLASGOW_HASKELL__ > 611@@ -115,114 +120,7 @@ #endif -- -------------------------------------------------------------------------------- POSIX file modes---- The abstract type 'FileMode', constants and operators for--- manipulating the file modes defined by POSIX.---- | No permissions.-nullFileMode :: FileMode-nullFileMode = 0---- | Owner has read permission.-ownerReadMode :: FileMode-ownerReadMode = (#const S_IRUSR)---- | Owner has write permission.-ownerWriteMode :: FileMode-ownerWriteMode = (#const S_IWUSR)---- | Owner has execute permission.-ownerExecuteMode :: FileMode-ownerExecuteMode = (#const S_IXUSR)---- | Group has read permission.-groupReadMode :: FileMode-groupReadMode = (#const S_IRGRP)---- | Group has write permission.-groupWriteMode :: FileMode-groupWriteMode = (#const S_IWGRP)---- | Group has execute permission.-groupExecuteMode :: FileMode-groupExecuteMode = (#const S_IXGRP)---- | Others have read permission.-otherReadMode :: FileMode-otherReadMode = (#const S_IROTH)---- | Others have write permission.-otherWriteMode :: FileMode-otherWriteMode = (#const S_IWOTH)---- | Others have execute permission.-otherExecuteMode :: FileMode-otherExecuteMode = (#const S_IXOTH)---- | Set user ID on execution.-setUserIDMode :: FileMode-setUserIDMode = (#const S_ISUID)---- | Set group ID on execution.-setGroupIDMode :: FileMode-setGroupIDMode = (#const S_ISGID)---- | Owner, group and others have read and write permission.-stdFileMode :: FileMode-stdFileMode = ownerReadMode .|. ownerWriteMode .|. - groupReadMode .|. groupWriteMode .|. - otherReadMode .|. otherWriteMode---- | Owner has read, write and execute permission.-ownerModes :: FileMode-ownerModes = (#const S_IRWXU)---- | Group has read, write and execute permission.-groupModes :: FileMode-groupModes = (#const S_IRWXG)---- | Others have read, write and execute permission.-otherModes :: FileMode-otherModes = (#const S_IRWXO)---- | Owner, group and others have read, write and execute permission.-accessModes :: FileMode-accessModes = ownerModes .|. groupModes .|. otherModes---- | Combines the two file modes into one that contains modes that appear in--- either.-unionFileModes :: FileMode -> FileMode -> FileMode-unionFileModes m1 m2 = m1 .|. m2---- | Combines two file modes into one that only contains modes that appear in--- both.-intersectFileModes :: FileMode -> FileMode -> FileMode-intersectFileModes m1 m2 = m1 .&. m2--fileTypeModes :: FileMode-fileTypeModes = (#const S_IFMT)--blockSpecialMode :: FileMode-blockSpecialMode = (#const S_IFBLK)--characterSpecialMode :: FileMode-characterSpecialMode = (#const S_IFCHR)--namedPipeMode :: FileMode-namedPipeMode = (#const S_IFIFO)--regularFileMode :: FileMode-regularFileMode = (#const S_IFREG)--directoryMode :: FileMode-directoryMode = (#const S_IFDIR)--symbolicLinkMode :: FileMode-symbolicLinkMode = (#const S_IFLNK)--socketMode :: FileMode-socketMode = (#const S_IFSOCK)+-- chmod() -- | @setFileMode path mode@ changes permission of the file given by @path@ -- to @mode@. This operation may fail with 'throwErrnoPathIfMinus1_' if @path@@@ -235,25 +133,6 @@ withFilePath name $ \s -> do throwErrnoPathIfMinus1_ "setFileMode" name (c_chmod s m) --- | @setFdMode fd mode@ acts like 'setFileMode' but uses a file descriptor--- @fd@ instead of a 'FilePath'.------ Note: calls @fchmod@.-setFdMode :: Fd -> FileMode -> IO ()-setFdMode (Fd fd) m =- throwErrnoIfMinus1_ "setFdMode" (c_fchmod fd m)--foreign import ccall unsafe "fchmod" - c_fchmod :: CInt -> CMode -> IO CInt---- | @setFileCreationMask mode@ sets the file mode creation mask to @mode@.--- Modes set by this operation are subtracted from files and directories upon--- creation. The previous file creation mask is returned.------ Note: calls @umask@.-setFileCreationMask :: FileMode -> IO FileMode-setFileCreationMask mask = c_umask mask- -- ----------------------------------------------------------------------------- -- access() @@ -295,93 +174,7 @@ then return False else throwErrnoPath "fileAccess" name --- -------------------------------------------------------------------------------- stat() support --- | POSIX defines operations to get information, such as owner, permissions,--- size and access times, about a file. This information is represented by the--- 'FileStatus' type.------ Note: see @chmod@.-newtype FileStatus = FileStatus (ForeignPtr CStat)---- | ID of the device on which this file resides.-deviceID :: FileStatus -> DeviceID--- | inode number-fileID :: FileStatus -> FileID--- | File mode (such as permissions).-fileMode :: FileStatus -> FileMode--- | Number of hard links to this file.-linkCount :: FileStatus -> LinkCount--- | ID of owner.-fileOwner :: FileStatus -> UserID--- | ID of group.-fileGroup :: FileStatus -> GroupID--- | Describes the device that this file represents.-specialDeviceID :: FileStatus -> DeviceID--- | Size of the file in bytes. If this file is a symbolic link the size is--- the length of the pathname it contains.-fileSize :: FileStatus -> FileOffset--- | Time of last access.-accessTime :: FileStatus -> EpochTime--- | Time of last modification.-modificationTime :: FileStatus -> EpochTime--- | Time of last status change (i.e. owner, group, link count, mode, etc.).-statusChangeTime :: FileStatus -> EpochTime--deviceID (FileStatus stat) = - unsafePerformIO $ withForeignPtr stat $ (#peek struct stat, st_dev)-fileID (FileStatus stat) = - unsafePerformIO $ withForeignPtr stat $ (#peek struct stat, st_ino)-fileMode (FileStatus stat) =- unsafePerformIO $ withForeignPtr stat $ (#peek struct stat, st_mode)-linkCount (FileStatus stat) =- unsafePerformIO $ withForeignPtr stat $ (#peek struct stat, st_nlink)-fileOwner (FileStatus stat) =- unsafePerformIO $ withForeignPtr stat $ (#peek struct stat, st_uid)-fileGroup (FileStatus stat) =- unsafePerformIO $ withForeignPtr stat $ (#peek struct stat, st_gid)-specialDeviceID (FileStatus stat) =- unsafePerformIO $ withForeignPtr stat $ (#peek struct stat, st_rdev)-fileSize (FileStatus stat) =- unsafePerformIO $ withForeignPtr stat $ (#peek struct stat, st_size)-accessTime (FileStatus stat) =- unsafePerformIO $ withForeignPtr stat $ (#peek struct stat, st_atime)-modificationTime (FileStatus stat) =- unsafePerformIO $ withForeignPtr stat $ (#peek struct stat, st_mtime)-statusChangeTime (FileStatus stat) =- unsafePerformIO $ withForeignPtr stat $ (#peek struct stat, st_ctime)---- | Checks if this file is a block device.-isBlockDevice :: FileStatus -> Bool--- | Checks if this file is a character device.-isCharacterDevice :: FileStatus -> Bool--- | Checks if this file is a named pipe device.-isNamedPipe :: FileStatus -> Bool--- | Checks if this file is a regular file device.-isRegularFile :: FileStatus -> Bool--- | Checks if this file is a directory device.-isDirectory :: FileStatus -> Bool--- | Checks if this file is a symbolic link device.-isSymbolicLink :: FileStatus -> Bool--- | Checks if this file is a socket device.-isSocket :: FileStatus -> Bool--isBlockDevice stat = - (fileMode stat `intersectFileModes` fileTypeModes) == blockSpecialMode-isCharacterDevice stat = - (fileMode stat `intersectFileModes` fileTypeModes) == characterSpecialMode-isNamedPipe stat = - (fileMode stat `intersectFileModes` fileTypeModes) == namedPipeMode-isRegularFile stat = - (fileMode stat `intersectFileModes` fileTypeModes) == regularFileMode-isDirectory stat = - (fileMode stat `intersectFileModes` fileTypeModes) == directoryMode-isSymbolicLink stat = - (fileMode stat `intersectFileModes` fileTypeModes) == symbolicLinkMode-isSocket stat = - (fileMode stat `intersectFileModes` fileTypeModes) == socketMode- -- | @getFileStatus path@ calls gets the @FileStatus@ information (user ID, -- size, access times, etc.) for the file @path@. --@@ -394,16 +187,6 @@ throwErrnoPathIfMinus1_ "getFileStatus" path (c_stat s p) return (FileStatus fp) --- | @getFdStatus fd@ acts as 'getFileStatus' but uses a file descriptor @fd@.------ Note: calls @fstat@.-getFdStatus :: Fd -> IO FileStatus-getFdStatus (Fd fd) = do- fp <- mallocForeignPtrBytes (#const sizeof(struct stat)) - withForeignPtr fp $ \p ->- throwErrnoIfMinus1_ "getFdStatus" (c_fstat fd p)- return (FileStatus fp)- -- | Acts as 'getFileStatus' except when the 'FilePath' refers to a symbolic -- link. In that case the @FileStatus@ information of the symbolic link itself -- is returned instead of that of the file it points to.@@ -417,10 +200,10 @@ throwErrnoPathIfMinus1_ "getSymbolicLinkStatus" path (c_lstat s p) return (FileStatus fp) -foreign import ccall unsafe "__hsunix_lstat" +foreign import ccall unsafe "__hsunix_lstat" c_lstat :: CString -> Ptr CStat -> IO CInt --- | @createNamedPipe fifo mode@ +-- | @createNamedPipe fifo mode@ -- creates a new named pipe, @fifo@, with permissions based on -- @mode@. May fail with 'throwErrnoPathIfMinus1_' if a file named @name@ -- already exists or if the effective user ID of the current process doesn't@@ -543,17 +326,6 @@ foreign import ccall unsafe "chown" c_chown :: CString -> CUid -> CGid -> IO CInt --- | Acts as 'setOwnerAndGroup' but uses a file descriptor instead of a--- 'FilePath'.------ Note: calls @fchown@.-setFdOwnerAndGroup :: Fd -> UserID -> GroupID -> IO ()-setFdOwnerAndGroup (Fd fd) uid gid = - throwErrnoIfMinus1_ "setFdOwnerAndGroup" (c_fchown fd uid gid)--foreign import ccall unsafe "fchown"- c_fchown :: CInt -> CUid -> CGid -> IO CInt- #if HAVE_LCHOWN -- | Acts as 'setOwnerAndGroup' but does not follow symlinks (and thus -- changes permissions on the link itself).@@ -608,81 +380,9 @@ foreign import ccall unsafe "truncate" c_truncate :: CString -> COff -> IO CInt --- | Acts as 'setFileSize' but uses a file descriptor instead of a 'FilePath'.------ Note: calls @ftruncate@.-setFdSize :: Fd -> FileOffset -> IO ()-setFdSize (Fd fd) off =- throwErrnoIfMinus1_ "setFdSize" (c_ftruncate fd off)- -- ----------------------------------------------------------------------------- -- pathconf()/fpathconf() support -data PathVar- = FileSizeBits {- _PC_FILESIZEBITS -}- | LinkLimit {- _PC_LINK_MAX -}- | InputLineLimit {- _PC_MAX_CANON -}- | InputQueueLimit {- _PC_MAX_INPUT -}- | FileNameLimit {- _PC_NAME_MAX -}- | PathNameLimit {- _PC_PATH_MAX -}- | PipeBufferLimit {- _PC_PIPE_BUF -}- -- These are described as optional in POSIX:- {- _PC_ALLOC_SIZE_MIN -}- {- _PC_REC_INCR_XFER_SIZE -}- {- _PC_REC_MAX_XFER_SIZE -}- {- _PC_REC_MIN_XFER_SIZE -}- {- _PC_REC_XFER_ALIGN -}- | SymbolicLinkLimit {- _PC_SYMLINK_MAX -}- | SetOwnerAndGroupIsRestricted {- _PC_CHOWN_RESTRICTED -}- | FileNamesAreNotTruncated {- _PC_NO_TRUNC -}- | VDisableChar {- _PC_VDISABLE -}- | AsyncIOAvailable {- _PC_ASYNC_IO -}- | PrioIOAvailable {- _PC_PRIO_IO -}- | SyncIOAvailable {- _PC_SYNC_IO -}--pathVarConst :: PathVar -> CInt-pathVarConst v = case v of- LinkLimit -> (#const _PC_LINK_MAX)- InputLineLimit -> (#const _PC_MAX_CANON)- InputQueueLimit -> (#const _PC_MAX_INPUT)- FileNameLimit -> (#const _PC_NAME_MAX)- PathNameLimit -> (#const _PC_PATH_MAX)- PipeBufferLimit -> (#const _PC_PIPE_BUF)- SetOwnerAndGroupIsRestricted -> (#const _PC_CHOWN_RESTRICTED)- FileNamesAreNotTruncated -> (#const _PC_NO_TRUNC)- VDisableChar -> (#const _PC_VDISABLE)--#ifdef _PC_SYNC_IO- SyncIOAvailable -> (#const _PC_SYNC_IO)-#else- SyncIOAvailable -> error "_PC_SYNC_IO not available"-#endif--#ifdef _PC_ASYNC_IO- AsyncIOAvailable -> (#const _PC_ASYNC_IO)-#else- AsyncIOAvailable -> error "_PC_ASYNC_IO not available"-#endif--#ifdef _PC_PRIO_IO- PrioIOAvailable -> (#const _PC_PRIO_IO)-#else- PrioIOAvailable -> error "_PC_PRIO_IO not available"-#endif--#if _PC_FILESIZEBITS- FileSizeBits -> (#const _PC_FILESIZEBITS)-#else- FileSizeBits -> error "_PC_FILESIZEBITS not available"-#endif--#if _PC_SYMLINK_MAX- SymbolicLinkLimit -> (#const _PC_SYMLINK_MAX)-#else- SymbolicLinkLimit -> error "_PC_SYMLINK_MAX not available"-#endif-- -- | @getPathVar var path@ obtains the dynamic value of the requested -- configurable file limit or option associated with file or directory @path@. -- For defined file limits, @getPathVar@ returns the associated@@ -698,19 +398,3 @@ foreign import ccall unsafe "pathconf" c_pathconf :: CString -> CInt -> IO CLong----- | @getFdPathVar var fd@ obtains the dynamic value of the requested--- configurable file limit or option associated with the file or directory--- attached to the open channel @fd@. For defined file limits, @getFdPathVar@--- returns the associated value. For defined file options, the result of--- @getFdPathVar@ is undefined, but not failure.------ Note: calls @fpathconf@.-getFdPathVar :: Fd -> PathVar -> IO Limit-getFdPathVar (Fd fd) v =- throwErrnoIfMinus1 "getFdPathVar" $ - c_fpathconf fd (pathVarConst v)--foreign import ccall unsafe "fpathconf" - c_fpathconf :: CInt -> CInt -> IO CLong
+ System/Posix/Files/ByteString.hsc view
@@ -0,0 +1,382 @@+#if __GLASGOW_HASKELL__ >= 701+{-# LANGUAGE Trustworthy #-}+#endif+-----------------------------------------------------------------------------+-- |+-- Module : System.Posix.Files.ByteString+-- 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)+--+-- Functions defined by the POSIX standards for manipulating and querying the+-- file system. Names of underlying POSIX functions are indicated whenever+-- possible. A more complete documentation of the POSIX functions together+-- with a more detailed description of different error conditions are usually+-- available in the system's manual pages or from+-- <http://www.unix.org/version3/online.html> (free registration required).+--+-- When a function that calls an underlying POSIX function fails, the errno+-- code is converted to an 'IOError' using 'Foreign.C.Error.errnoToIOError'.+-- For a list of which errno codes may be generated, consult the POSIX+-- documentation for the underlying function.+--+-----------------------------------------------------------------------------++#include "HsUnix.h"++module System.Posix.Files.ByteString (+ -- * File modes+ -- FileMode exported by System.Posix.Types+ unionFileModes, intersectFileModes,+ nullFileMode,+ ownerReadMode, ownerWriteMode, ownerExecuteMode, ownerModes,+ groupReadMode, groupWriteMode, groupExecuteMode, groupModes,+ otherReadMode, otherWriteMode, otherExecuteMode, otherModes,+ setUserIDMode, setGroupIDMode,+ stdFileMode, accessModes,+ fileTypeModes,+ blockSpecialMode, characterSpecialMode, namedPipeMode, regularFileMode,+ directoryMode, symbolicLinkMode, socketMode,++ -- ** Setting file modes+ setFileMode, setFdMode, setFileCreationMask,++ -- ** Checking file existence and permissions+ fileAccess, fileExist,++ -- * File status+ FileStatus,+ -- ** Obtaining file status+ getFileStatus, getFdStatus, getSymbolicLinkStatus,+ -- ** Querying file status+ deviceID, fileID, fileMode, linkCount, fileOwner, fileGroup,+ specialDeviceID, fileSize, accessTime, modificationTime,+ statusChangeTime,+ isBlockDevice, isCharacterDevice, isNamedPipe, isRegularFile,+ isDirectory, isSymbolicLink, isSocket,++ -- * Creation+ createNamedPipe, + createDevice,++ -- * Hard links+ createLink, removeLink,++ -- * Symbolic links+ createSymbolicLink, readSymbolicLink,++ -- * Renaming files+ rename,++ -- * Changing file ownership+ setOwnerAndGroup, setFdOwnerAndGroup,+#if HAVE_LCHOWN+ setSymbolicLinkOwnerAndGroup,+#endif++ -- * Changing file timestamps+ setFileTimes, touchFile,++ -- * Setting file sizes+ setFileSize, setFdSize,++ -- * Find system-specific limits for a file+ PathVar(..), getPathVar, getFdPathVar,+ ) where++import System.Posix.Types+import System.Posix.Internals hiding (withFilePath, peekFilePathLen)+import Foreign+import Foreign.C hiding (+ throwErrnoPath,+ throwErrnoPathIf,+ throwErrnoPathIf_,+ throwErrnoPathIfNull,+ throwErrnoPathIfMinus1,+ throwErrnoPathIfMinus1_ )++import System.Posix.Files.Common+import System.Posix.ByteString.FilePath++-- -----------------------------------------------------------------------------+-- chmod()++-- | @setFileMode path mode@ changes permission of the file given by @path@+-- to @mode@. This operation may fail with 'throwErrnoPathIfMinus1_' if @path@+-- doesn't exist or if the effective user ID of the current process is not that+-- of the file's owner.+--+-- Note: calls @chmod@.+setFileMode :: RawFilePath -> FileMode -> IO ()+setFileMode name m =+ withFilePath name $ \s -> do+ throwErrnoPathIfMinus1_ "setFileMode" name (c_chmod s m)++-- -----------------------------------------------------------------------------+-- access()++-- | @fileAccess name read write exec@ checks if the file (or other file system+-- object) @name@ can be accessed for reading, writing and\/or executing. To+-- check a permission set the corresponding argument to 'True'.+--+-- Note: calls @access@.+fileAccess :: RawFilePath -> Bool -> Bool -> Bool -> IO Bool+fileAccess name readOK writeOK execOK = access name flags+ where+ flags = read_f .|. write_f .|. exec_f+ read_f = if readOK then (#const R_OK) else 0+ write_f = if writeOK then (#const W_OK) else 0+ exec_f = if execOK then (#const X_OK) else 0++-- | Checks for the existence of the file.+--+-- Note: calls @access@.+fileExist :: RawFilePath -> IO Bool+fileExist name = + withFilePath name $ \s -> do+ r <- c_access s (#const F_OK)+ if (r == 0)+ then return True+ else do err <- getErrno+ if (err == eNOENT)+ then return False+ else throwErrnoPath "fileExist" name++access :: RawFilePath -> CMode -> IO Bool+access name flags = + withFilePath name $ \s -> do+ r <- c_access s (fromIntegral flags)+ if (r == 0)+ then return True+ else do err <- getErrno+ if (err == eACCES)+ then return False+ else throwErrnoPath "fileAccess" name+++-- | @getFileStatus path@ calls gets the @FileStatus@ information (user ID,+-- size, access times, etc.) for the file @path@.+--+-- Note: calls @stat@.+getFileStatus :: RawFilePath -> IO FileStatus+getFileStatus path = do+ fp <- mallocForeignPtrBytes (#const sizeof(struct stat)) + withForeignPtr fp $ \p ->+ withFilePath path $ \s -> + throwErrnoPathIfMinus1_ "getFileStatus" path (c_stat s p)+ return (FileStatus fp)++-- | Acts as 'getFileStatus' except when the 'RawFilePath' refers to a symbolic+-- link. In that case the @FileStatus@ information of the symbolic link itself+-- is returned instead of that of the file it points to.+--+-- Note: calls @lstat@.+getSymbolicLinkStatus :: RawFilePath -> IO FileStatus+getSymbolicLinkStatus path = do+ fp <- mallocForeignPtrBytes (#const sizeof(struct stat)) + withForeignPtr fp $ \p ->+ withFilePath path $ \s -> + throwErrnoPathIfMinus1_ "getSymbolicLinkStatus" path (c_lstat s p)+ return (FileStatus fp)++foreign import ccall unsafe "__hsunix_lstat"+ c_lstat :: CString -> Ptr CStat -> IO CInt++-- | @createNamedPipe fifo mode@+-- creates a new named pipe, @fifo@, with permissions based on+-- @mode@. May fail with 'throwErrnoPathIfMinus1_' if a file named @name@+-- already exists or if the effective user ID of the current process doesn't+-- have permission to create the pipe.+--+-- Note: calls @mkfifo@.+createNamedPipe :: RawFilePath -> FileMode -> IO ()+createNamedPipe name mode = do+ withFilePath name $ \s -> + throwErrnoPathIfMinus1_ "createNamedPipe" name (c_mkfifo s mode)++-- | @createDevice path mode dev@ creates either a regular or a special file+-- depending on the value of @mode@ (and @dev@). @mode@ will normally be either+-- 'blockSpecialMode' or 'characterSpecialMode'. May fail with+-- 'throwErrnoPathIfMinus1_' if a file named @name@ already exists or if the+-- effective user ID of the current process doesn't have permission to create+-- the file.+--+-- Note: calls @mknod@.+createDevice :: RawFilePath -> FileMode -> DeviceID -> IO ()+createDevice path mode dev =+ withFilePath path $ \s ->+ throwErrnoPathIfMinus1_ "createDevice" path (c_mknod s mode dev)++foreign import ccall unsafe "__hsunix_mknod" + c_mknod :: CString -> CMode -> CDev -> IO CInt++-- -----------------------------------------------------------------------------+-- Hard links++-- | @createLink old new@ creates a new path, @new@, linked to an existing file,+-- @old@.+--+-- Note: calls @link@.+createLink :: RawFilePath -> RawFilePath -> IO ()+createLink name1 name2 =+ withFilePath name1 $ \s1 ->+ withFilePath name2 $ \s2 ->+ throwErrnoPathIfMinus1_ "createLink" name1 (c_link s1 s2)++-- | @removeLink path@ removes the link named @path@.+--+-- Note: calls @unlink@.+removeLink :: RawFilePath -> IO ()+removeLink name =+ withFilePath name $ \s ->+ throwErrnoPathIfMinus1_ "removeLink" name (c_unlink s)++-- -----------------------------------------------------------------------------+-- Symbolic Links++-- | @createSymbolicLink file1 file2@ creates a symbolic link named @file2@+-- which points to the file @file1@.+--+-- Symbolic links are interpreted at run-time as if the contents of the link+-- had been substituted into the path being followed to find a file or directory.+--+-- Note: calls @symlink@.+createSymbolicLink :: RawFilePath -> RawFilePath -> IO ()+createSymbolicLink file1 file2 =+ withFilePath file1 $ \s1 ->+ withFilePath file2 $ \s2 ->+ throwErrnoPathIfMinus1_ "createSymbolicLink" file1 (c_symlink s1 s2)++foreign import ccall unsafe "symlink"+ c_symlink :: CString -> CString -> IO CInt++-- ToDo: should really use SYMLINK_MAX, but not everyone supports it yet,+-- and it seems that the intention is that SYMLINK_MAX is no larger than+-- PATH_MAX.+#if !defined(PATH_MAX)+-- PATH_MAX is not defined on systems with unlimited path length.+-- Ugly. Fix this.+#define PATH_MAX 4096+#endif++-- | Reads the @RawFilePath@ pointed to by the symbolic link and returns it.+--+-- Note: calls @readlink@.+readSymbolicLink :: RawFilePath -> IO RawFilePath+readSymbolicLink file =+ allocaArray0 (#const PATH_MAX) $ \buf -> do+ withFilePath file $ \s -> do+ len <- throwErrnoPathIfMinus1 "readSymbolicLink" file $ + c_readlink s buf (#const PATH_MAX)+ peekFilePathLen (buf,fromIntegral len)++foreign import ccall unsafe "readlink"+ c_readlink :: CString -> CString -> CSize -> IO CInt++-- -----------------------------------------------------------------------------+-- Renaming files++-- | @rename old new@ renames a file or directory from @old@ to @new@.+--+-- Note: calls @rename@.+rename :: RawFilePath -> RawFilePath -> IO ()+rename name1 name2 =+ withFilePath name1 $ \s1 ->+ withFilePath name2 $ \s2 ->+ throwErrnoPathIfMinus1_ "rename" name1 (c_rename s1 s2)++foreign import ccall unsafe "rename"+ c_rename :: CString -> CString -> IO CInt++-- -----------------------------------------------------------------------------+-- chown()++-- | @setOwnerAndGroup path uid gid@ changes the owner and group of @path@ to+-- @uid@ and @gid@, respectively.+--+-- If @uid@ or @gid@ is specified as -1, then that ID is not changed.+--+-- Note: calls @chown@.+setOwnerAndGroup :: RawFilePath -> UserID -> GroupID -> IO ()+setOwnerAndGroup name uid gid = do+ withFilePath name $ \s ->+ throwErrnoPathIfMinus1_ "setOwnerAndGroup" name (c_chown s uid gid)++foreign import ccall unsafe "chown"+ c_chown :: CString -> CUid -> CGid -> IO CInt++#if HAVE_LCHOWN+-- | Acts as 'setOwnerAndGroup' but does not follow symlinks (and thus+-- changes permissions on the link itself).+--+-- Note: calls @lchown@.+setSymbolicLinkOwnerAndGroup :: RawFilePath -> UserID -> GroupID -> IO ()+setSymbolicLinkOwnerAndGroup name uid gid = do+ withFilePath name $ \s ->+ throwErrnoPathIfMinus1_ "setSymbolicLinkOwnerAndGroup" name+ (c_lchown s uid gid)++foreign import ccall unsafe "lchown"+ c_lchown :: CString -> CUid -> CGid -> IO CInt+#endif++-- -----------------------------------------------------------------------------+-- utime()++-- | @setFileTimes path atime mtime@ sets the access and modification times+-- associated with file @path@ to @atime@ and @mtime@, respectively.+--+-- Note: calls @utime@.+setFileTimes :: RawFilePath -> EpochTime -> EpochTime -> IO ()+setFileTimes name atime mtime = do+ withFilePath name $ \s ->+ allocaBytes (#const sizeof(struct utimbuf)) $ \p -> do+ (#poke struct utimbuf, actime) p atime+ (#poke struct utimbuf, modtime) p mtime+ throwErrnoPathIfMinus1_ "setFileTimes" name (c_utime s p)++-- | @touchFile path@ sets the access and modification times associated with+-- file @path@ to the current time.+--+-- Note: calls @utime@.+touchFile :: RawFilePath -> IO ()+touchFile name = do+ withFilePath name $ \s ->+ throwErrnoPathIfMinus1_ "touchFile" name (c_utime s nullPtr)++-- -----------------------------------------------------------------------------+-- Setting file sizes++-- | Truncates the file down to the specified length. If the file was larger+-- than the given length before this operation was performed the extra is lost.+--+-- Note: calls @truncate@.+setFileSize :: RawFilePath -> FileOffset -> IO ()+setFileSize file off = + withFilePath file $ \s ->+ throwErrnoPathIfMinus1_ "setFileSize" file (c_truncate s off)++foreign import ccall unsafe "truncate"+ c_truncate :: CString -> COff -> IO CInt++-- -----------------------------------------------------------------------------+-- pathconf()/fpathconf() support++-- | @getPathVar var path@ obtains the dynamic value of the requested+-- configurable file limit or option associated with file or directory @path@.+-- For defined file limits, @getPathVar@ returns the associated+-- value. For defined file options, the result of @getPathVar@+-- is undefined, but not failure.+--+-- Note: calls @pathconf@.+getPathVar :: RawFilePath -> PathVar -> IO Limit+getPathVar name v = do+ withFilePath name $ \ nameP -> + throwErrnoPathIfMinus1 "getPathVar" name $ + c_pathconf nameP (pathVarConst v)++foreign import ccall unsafe "pathconf" + c_pathconf :: CString -> CInt -> IO CLong
+ System/Posix/Files/Common.hsc view
@@ -0,0 +1,408 @@+{-# LANGUAGE ForeignFunctionInterface #-}+{-# OPTIONS_GHC -fno-warn-unused-imports #-}+#if __GLASGOW_HASKELL__ >= 701+{-# LANGUAGE Trustworthy #-}+#endif+-----------------------------------------------------------------------------+-- |+-- Module : System.Posix.Files.Common+-- 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)+--+-- Functions defined by the POSIX standards for manipulating and querying the+-- file system. Names of underlying POSIX functions are indicated whenever+-- possible. A more complete documentation of the POSIX functions together+-- with a more detailed description of different error conditions are usually+-- available in the system's manual pages or from+-- <http://www.unix.org/version3/online.html> (free registration required).+--+-- When a function that calls an underlying POSIX function fails, the errno+-- code is converted to an 'IOError' using 'Foreign.C.Error.errnoToIOError'.+-- For a list of which errno codes may be generated, consult the POSIX+-- documentation for the underlying function.+--+-----------------------------------------------------------------------------++#include "HsUnix.h"++module System.Posix.Files.Common (+ -- * File modes+ -- FileMode exported by System.Posix.Types+ unionFileModes, intersectFileModes,+ nullFileMode,+ ownerReadMode, ownerWriteMode, ownerExecuteMode, ownerModes,+ groupReadMode, groupWriteMode, groupExecuteMode, groupModes,+ otherReadMode, otherWriteMode, otherExecuteMode, otherModes,+ setUserIDMode, setGroupIDMode,+ stdFileMode, accessModes,+ fileTypeModes,+ blockSpecialMode, characterSpecialMode, namedPipeMode, regularFileMode,+ directoryMode, symbolicLinkMode, socketMode,++ -- ** Setting file modes+ setFdMode, setFileCreationMask,++ -- * File status+ FileStatus(..),+ -- ** Obtaining file status+ getFdStatus,+ -- ** Querying file status+ deviceID, fileID, fileMode, linkCount, fileOwner, fileGroup,+ specialDeviceID, fileSize, accessTime, modificationTime,+ statusChangeTime,+ isBlockDevice, isCharacterDevice, isNamedPipe, isRegularFile,+ isDirectory, isSymbolicLink, isSocket,++ -- * Setting file sizes+ setFdSize,++ -- * Changing file ownership+ setFdOwnerAndGroup,++ -- * Find system-specific limits for a file+ PathVar(..), getFdPathVar, pathVarConst,+ ) where++import System.Posix.Error+import System.Posix.Types+import System.IO.Unsafe+import Data.Bits+import System.Posix.Internals+import Foreign hiding (unsafePerformIO)+import Foreign.C++-- -----------------------------------------------------------------------------+-- POSIX file modes++-- The abstract type 'FileMode', constants and operators for+-- manipulating the file modes defined by POSIX.++-- | No permissions.+nullFileMode :: FileMode+nullFileMode = 0++-- | Owner has read permission.+ownerReadMode :: FileMode+ownerReadMode = (#const S_IRUSR)++-- | Owner has write permission.+ownerWriteMode :: FileMode+ownerWriteMode = (#const S_IWUSR)++-- | Owner has execute permission.+ownerExecuteMode :: FileMode+ownerExecuteMode = (#const S_IXUSR)++-- | Group has read permission.+groupReadMode :: FileMode+groupReadMode = (#const S_IRGRP)++-- | Group has write permission.+groupWriteMode :: FileMode+groupWriteMode = (#const S_IWGRP)++-- | Group has execute permission.+groupExecuteMode :: FileMode+groupExecuteMode = (#const S_IXGRP)++-- | Others have read permission.+otherReadMode :: FileMode+otherReadMode = (#const S_IROTH)++-- | Others have write permission.+otherWriteMode :: FileMode+otherWriteMode = (#const S_IWOTH)++-- | Others have execute permission.+otherExecuteMode :: FileMode+otherExecuteMode = (#const S_IXOTH)++-- | Set user ID on execution.+setUserIDMode :: FileMode+setUserIDMode = (#const S_ISUID)++-- | Set group ID on execution.+setGroupIDMode :: FileMode+setGroupIDMode = (#const S_ISGID)++-- | Owner, group and others have read and write permission.+stdFileMode :: FileMode+stdFileMode = ownerReadMode .|. ownerWriteMode .|. + groupReadMode .|. groupWriteMode .|. + otherReadMode .|. otherWriteMode++-- | Owner has read, write and execute permission.+ownerModes :: FileMode+ownerModes = (#const S_IRWXU)++-- | Group has read, write and execute permission.+groupModes :: FileMode+groupModes = (#const S_IRWXG)++-- | Others have read, write and execute permission.+otherModes :: FileMode+otherModes = (#const S_IRWXO)++-- | Owner, group and others have read, write and execute permission.+accessModes :: FileMode+accessModes = ownerModes .|. groupModes .|. otherModes++-- | Combines the two file modes into one that contains modes that appear in+-- either.+unionFileModes :: FileMode -> FileMode -> FileMode+unionFileModes m1 m2 = m1 .|. m2++-- | Combines two file modes into one that only contains modes that appear in+-- both.+intersectFileModes :: FileMode -> FileMode -> FileMode+intersectFileModes m1 m2 = m1 .&. m2++fileTypeModes :: FileMode+fileTypeModes = (#const S_IFMT)++blockSpecialMode :: FileMode+blockSpecialMode = (#const S_IFBLK)++characterSpecialMode :: FileMode+characterSpecialMode = (#const S_IFCHR)++namedPipeMode :: FileMode+namedPipeMode = (#const S_IFIFO)++regularFileMode :: FileMode+regularFileMode = (#const S_IFREG)++directoryMode :: FileMode+directoryMode = (#const S_IFDIR)++symbolicLinkMode :: FileMode+symbolicLinkMode = (#const S_IFLNK)++socketMode :: FileMode+socketMode = (#const S_IFSOCK)++-- | @setFdMode fd mode@ acts like 'setFileMode' but uses a file descriptor+-- @fd@ instead of a 'FilePath'.+--+-- Note: calls @fchmod@.+setFdMode :: Fd -> FileMode -> IO ()+setFdMode (Fd fd) m =+ throwErrnoIfMinus1_ "setFdMode" (c_fchmod fd m)++foreign import ccall unsafe "fchmod" + c_fchmod :: CInt -> CMode -> IO CInt++-- | @setFileCreationMask mode@ sets the file mode creation mask to @mode@.+-- Modes set by this operation are subtracted from files and directories upon+-- creation. The previous file creation mask is returned.+--+-- Note: calls @umask@.+setFileCreationMask :: FileMode -> IO FileMode+setFileCreationMask mask = c_umask mask++-- -----------------------------------------------------------------------------+-- stat() support++-- | POSIX defines operations to get information, such as owner, permissions,+-- size and access times, about a file. This information is represented by the+-- 'FileStatus' type.+--+-- Note: see @chmod@.+newtype FileStatus = FileStatus (ForeignPtr CStat)++-- | ID of the device on which this file resides.+deviceID :: FileStatus -> DeviceID+-- | inode number+fileID :: FileStatus -> FileID+-- | File mode (such as permissions).+fileMode :: FileStatus -> FileMode+-- | Number of hard links to this file.+linkCount :: FileStatus -> LinkCount+-- | ID of owner.+fileOwner :: FileStatus -> UserID+-- | ID of group.+fileGroup :: FileStatus -> GroupID+-- | Describes the device that this file represents.+specialDeviceID :: FileStatus -> DeviceID+-- | Size of the file in bytes. If this file is a symbolic link the size is+-- the length of the pathname it contains.+fileSize :: FileStatus -> FileOffset+-- | Time of last access.+accessTime :: FileStatus -> EpochTime+-- | Time of last modification.+modificationTime :: FileStatus -> EpochTime+-- | Time of last status change (i.e. owner, group, link count, mode, etc.).+statusChangeTime :: FileStatus -> EpochTime++deviceID (FileStatus stat) = + unsafePerformIO $ withForeignPtr stat $ (#peek struct stat, st_dev)+fileID (FileStatus stat) = + unsafePerformIO $ withForeignPtr stat $ (#peek struct stat, st_ino)+fileMode (FileStatus stat) =+ unsafePerformIO $ withForeignPtr stat $ (#peek struct stat, st_mode)+linkCount (FileStatus stat) =+ unsafePerformIO $ withForeignPtr stat $ (#peek struct stat, st_nlink)+fileOwner (FileStatus stat) =+ unsafePerformIO $ withForeignPtr stat $ (#peek struct stat, st_uid)+fileGroup (FileStatus stat) =+ unsafePerformIO $ withForeignPtr stat $ (#peek struct stat, st_gid)+specialDeviceID (FileStatus stat) =+ unsafePerformIO $ withForeignPtr stat $ (#peek struct stat, st_rdev)+fileSize (FileStatus stat) =+ unsafePerformIO $ withForeignPtr stat $ (#peek struct stat, st_size)+accessTime (FileStatus stat) =+ unsafePerformIO $ withForeignPtr stat $ (#peek struct stat, st_atime)+modificationTime (FileStatus stat) =+ unsafePerformIO $ withForeignPtr stat $ (#peek struct stat, st_mtime)+statusChangeTime (FileStatus stat) =+ unsafePerformIO $ withForeignPtr stat $ (#peek struct stat, st_ctime)++-- | Checks if this file is a block device.+isBlockDevice :: FileStatus -> Bool+-- | Checks if this file is a character device.+isCharacterDevice :: FileStatus -> Bool+-- | Checks if this file is a named pipe device.+isNamedPipe :: FileStatus -> Bool+-- | Checks if this file is a regular file device.+isRegularFile :: FileStatus -> Bool+-- | Checks if this file is a directory device.+isDirectory :: FileStatus -> Bool+-- | Checks if this file is a symbolic link device.+isSymbolicLink :: FileStatus -> Bool+-- | Checks if this file is a socket device.+isSocket :: FileStatus -> Bool++isBlockDevice stat = + (fileMode stat `intersectFileModes` fileTypeModes) == blockSpecialMode+isCharacterDevice stat = + (fileMode stat `intersectFileModes` fileTypeModes) == characterSpecialMode+isNamedPipe stat = + (fileMode stat `intersectFileModes` fileTypeModes) == namedPipeMode+isRegularFile stat = + (fileMode stat `intersectFileModes` fileTypeModes) == regularFileMode+isDirectory stat = + (fileMode stat `intersectFileModes` fileTypeModes) == directoryMode+isSymbolicLink stat = + (fileMode stat `intersectFileModes` fileTypeModes) == symbolicLinkMode+isSocket stat = + (fileMode stat `intersectFileModes` fileTypeModes) == socketMode++-- | @getFdStatus fd@ acts as 'getFileStatus' but uses a file descriptor @fd@.+--+-- Note: calls @fstat@.+getFdStatus :: Fd -> IO FileStatus+getFdStatus (Fd fd) = do+ fp <- mallocForeignPtrBytes (#const sizeof(struct stat)) + withForeignPtr fp $ \p ->+ throwErrnoIfMinus1_ "getFdStatus" (c_fstat fd p)+ return (FileStatus fp)++-- -----------------------------------------------------------------------------+-- fchown()++-- | Acts as 'setOwnerAndGroup' but uses a file descriptor instead of a+-- 'FilePath'.+--+-- Note: calls @fchown@.+setFdOwnerAndGroup :: Fd -> UserID -> GroupID -> IO ()+setFdOwnerAndGroup (Fd fd) uid gid = + throwErrnoIfMinus1_ "setFdOwnerAndGroup" (c_fchown fd uid gid)++foreign import ccall unsafe "fchown"+ c_fchown :: CInt -> CUid -> CGid -> IO CInt++-- -----------------------------------------------------------------------------+-- ftruncate()++-- | Acts as 'setFileSize' but uses a file descriptor instead of a 'FilePath'.+--+-- Note: calls @ftruncate@.+setFdSize :: Fd -> FileOffset -> IO ()+setFdSize (Fd fd) off =+ throwErrnoIfMinus1_ "setFdSize" (c_ftruncate fd off)++-- -----------------------------------------------------------------------------+-- pathconf()/fpathconf() support++data PathVar+ = FileSizeBits {- _PC_FILESIZEBITS -}+ | LinkLimit {- _PC_LINK_MAX -}+ | InputLineLimit {- _PC_MAX_CANON -}+ | InputQueueLimit {- _PC_MAX_INPUT -}+ | FileNameLimit {- _PC_NAME_MAX -}+ | PathNameLimit {- _PC_PATH_MAX -}+ | PipeBufferLimit {- _PC_PIPE_BUF -}+ -- These are described as optional in POSIX:+ {- _PC_ALLOC_SIZE_MIN -}+ {- _PC_REC_INCR_XFER_SIZE -}+ {- _PC_REC_MAX_XFER_SIZE -}+ {- _PC_REC_MIN_XFER_SIZE -}+ {- _PC_REC_XFER_ALIGN -}+ | SymbolicLinkLimit {- _PC_SYMLINK_MAX -}+ | SetOwnerAndGroupIsRestricted {- _PC_CHOWN_RESTRICTED -}+ | FileNamesAreNotTruncated {- _PC_NO_TRUNC -}+ | VDisableChar {- _PC_VDISABLE -}+ | AsyncIOAvailable {- _PC_ASYNC_IO -}+ | PrioIOAvailable {- _PC_PRIO_IO -}+ | SyncIOAvailable {- _PC_SYNC_IO -}++pathVarConst :: PathVar -> CInt+pathVarConst v = case v of+ LinkLimit -> (#const _PC_LINK_MAX)+ InputLineLimit -> (#const _PC_MAX_CANON)+ InputQueueLimit -> (#const _PC_MAX_INPUT)+ FileNameLimit -> (#const _PC_NAME_MAX)+ PathNameLimit -> (#const _PC_PATH_MAX)+ PipeBufferLimit -> (#const _PC_PIPE_BUF)+ SetOwnerAndGroupIsRestricted -> (#const _PC_CHOWN_RESTRICTED)+ FileNamesAreNotTruncated -> (#const _PC_NO_TRUNC)+ VDisableChar -> (#const _PC_VDISABLE)++#ifdef _PC_SYNC_IO+ SyncIOAvailable -> (#const _PC_SYNC_IO)+#else+ SyncIOAvailable -> error "_PC_SYNC_IO not available"+#endif++#ifdef _PC_ASYNC_IO+ AsyncIOAvailable -> (#const _PC_ASYNC_IO)+#else+ AsyncIOAvailable -> error "_PC_ASYNC_IO not available"+#endif++#ifdef _PC_PRIO_IO+ PrioIOAvailable -> (#const _PC_PRIO_IO)+#else+ PrioIOAvailable -> error "_PC_PRIO_IO not available"+#endif++#if _PC_FILESIZEBITS+ FileSizeBits -> (#const _PC_FILESIZEBITS)+#else+ FileSizeBits -> error "_PC_FILESIZEBITS not available"+#endif++#if _PC_SYMLINK_MAX+ SymbolicLinkLimit -> (#const _PC_SYMLINK_MAX)+#else+ SymbolicLinkLimit -> error "_PC_SYMLINK_MAX not available"+#endif++-- | @getFdPathVar var fd@ obtains the dynamic value of the requested+-- configurable file limit or option associated with the file or directory+-- attached to the open channel @fd@. For defined file limits, @getFdPathVar@+-- returns the associated value. For defined file options, the result of+-- @getFdPathVar@ is undefined, but not failure.+--+-- Note: calls @fpathconf@.+getFdPathVar :: Fd -> PathVar -> IO Limit+getFdPathVar (Fd fd) v =+ throwErrnoIfMinus1 "getFdPathVar" $ + c_fpathconf fd (pathVarConst v)++foreign import ccall unsafe "fpathconf" + c_fpathconf :: CInt -> CInt -> IO CLong
System/Posix/IO.hsc view
@@ -1,6 +1,9 @@ {-# LANGUAGE ForeignFunctionInterface #-} {-# OPTIONS_GHC -fno-warn-unused-imports #-} {-# OPTIONS_GHC -XRecordWildCards #-}+#if __GLASGOW_HASKELL__ >= 701+{-# LANGUAGE Trustworthy #-}+#endif ----------------------------------------------------------------------------- -- | -- Module : System.Posix.IO@@ -18,6 +21,8 @@ -- ----------------------------------------------------------------------------- +#include "HsUnix.h"+ module System.Posix.IO ( -- * Input \/ Output @@ -63,36 +68,9 @@ ) where -import System.IO-import System.IO.Error import System.Posix.Types import System.Posix.Error-import qualified System.Posix.Internals as Base--import Foreign-import Foreign.C-import Data.Bits--#ifdef __GLASGOW_HASKELL__-#if __GLASGOW_HASKELL__ >= 611-import GHC.IO.Handle-import GHC.IO.Handle.Internals-import GHC.IO.Handle.Types-import qualified GHC.IO.FD as FD-import qualified GHC.IO.Handle.FD as FD-import GHC.IO.Exception-import Data.Typeable (cast)-#else-import GHC.IOBase-import GHC.Handle hiding (fdToHandle)-import qualified GHC.Handle-#endif-#endif--#ifdef __HUGS__-import Hugs.Prelude (IOException(..), IOErrorType(..))-import qualified Hugs.IO (handleToFd, openFd)-#endif+import System.Posix.IO.Common #if __GLASGOW_HASKELL__ > 611 import System.Posix.Internals ( withFilePath )@@ -101,81 +79,6 @@ withFilePath = withCString #endif -#include "HsUnix.h"---- -------------------------------------------------------------------------------- Pipes--- |The 'createPipe' function creates a pair of connected file--- descriptors. The first component is the fd to read from, the second--- is the write end. Although pipes may be bidirectional, this--- behaviour is not portable and programmers should use two separate--- pipes for this purpose. May throw an exception if this is an--- invalid descriptor.--createPipe :: IO (Fd, Fd)-createPipe =- allocaArray 2 $ \p_fd -> do- throwErrnoIfMinus1_ "createPipe" (c_pipe p_fd)- rfd <- peekElemOff p_fd 0- wfd <- peekElemOff p_fd 1- return (Fd rfd, Fd wfd)--foreign import ccall unsafe "pipe"- c_pipe :: Ptr CInt -> IO CInt---- -------------------------------------------------------------------------------- Duplicating file descriptors---- | May throw an exception if this is an invalid descriptor.-dup :: Fd -> IO Fd-dup (Fd fd) = do r <- throwErrnoIfMinus1 "dup" (c_dup fd); return (Fd r)---- | May throw an exception if this is an invalid descriptor.-dupTo :: Fd -> Fd -> IO Fd-dupTo (Fd fd1) (Fd fd2) = do- r <- throwErrnoIfMinus1 "dupTo" (c_dup2 fd1 fd2)- return (Fd r)--foreign import ccall unsafe "dup"- c_dup :: CInt -> IO CInt--foreign import ccall unsafe "dup2"- c_dup2 :: CInt -> CInt -> IO CInt---- -------------------------------------------------------------------------------- Opening and closing files--stdInput, stdOutput, stdError :: Fd-stdInput = Fd (#const STDIN_FILENO)-stdOutput = Fd (#const STDOUT_FILENO)-stdError = Fd (#const STDERR_FILENO)--data OpenMode = ReadOnly | WriteOnly | ReadWrite---- |Correspond to some of the int flags from C's fcntl.h.-data OpenFileFlags =- OpenFileFlags {- append :: Bool, -- ^ O_APPEND- exclusive :: Bool, -- ^ O_EXCL- noctty :: Bool, -- ^ O_NOCTTY- nonBlock :: Bool, -- ^ O_NONBLOCK- trunc :: Bool -- ^ O_TRUNC- }----- |Default values for the 'OpenFileFlags' type. False for each of--- append, exclusive, noctty, nonBlock, and trunc.-defaultFileFlags :: OpenFileFlags-defaultFileFlags =- OpenFileFlags {- append = False,- exclusive = False,- noctty = False,- nonBlock = False,- trunc = False- }-- -- |Open and optionally create this file. See 'System.Posix.Files' -- for information on how to use the 'FileMode' type. openFd :: FilePath@@ -183,32 +86,10 @@ -> Maybe FileMode -- ^Just x => creates the file with the given modes, Nothing => the file must exist. -> OpenFileFlags -> IO Fd-openFd name how maybe_mode (OpenFileFlags appendFlag exclusiveFlag nocttyFlag- nonBlockFlag truncateFlag) = do- withFilePath name $ \s -> do- fd <- throwErrnoPathIfMinus1Retry "openFd" name (c_open s all_flags mode_w)- return (Fd fd)- where- all_flags = creat .|. flags .|. open_mode-- flags =- (if appendFlag then (#const O_APPEND) else 0) .|.- (if exclusiveFlag then (#const O_EXCL) else 0) .|.- (if nocttyFlag then (#const O_NOCTTY) else 0) .|.- (if nonBlockFlag then (#const O_NONBLOCK) else 0) .|.- (if truncateFlag then (#const O_TRUNC) else 0)-- (creat, mode_w) = case maybe_mode of - Nothing -> (0,0)- Just x -> ((#const O_CREAT), x)-- open_mode = case how of- ReadOnly -> (#const O_RDONLY)- WriteOnly -> (#const O_WRONLY)- ReadWrite -> (#const O_RDWR)--foreign import ccall unsafe "__hscore_open"- c_open :: CString -> CInt -> CMode -> IO CInt+openFd name how maybe_mode flags = do+ withFilePath name $ \str -> do+ throwErrnoPathIfMinus1Retry "openFd" name $+ open_ str how maybe_mode flags -- |Create and open this file in WriteOnly mode. A special case of -- 'openFd'. See 'System.Posix.Files' for information on how to use@@ -217,267 +98,3 @@ createFile :: FilePath -> FileMode -> IO Fd createFile name mode = openFd name WriteOnly (Just mode) defaultFileFlags{ trunc=True } ---- |Close this file descriptor. May throw an exception if this is an--- invalid descriptor.--closeFd :: Fd -> IO ()-closeFd (Fd fd) = throwErrnoIfMinus1_ "closeFd" (c_close fd)--foreign import ccall unsafe "HsBase.h close"- c_close :: CInt -> IO CInt---- -------------------------------------------------------------------------------- Converting file descriptors to/from Handles---- | Extracts the 'Fd' from a 'Handle'. This function has the side effect--- of closing the 'Handle' and flushing its write buffer, if necessary.-handleToFd :: Handle -> IO Fd---- | Converts an 'Fd' into a 'Handle' that can be used with the--- standard Haskell IO library (see "System.IO"). ------ GHC only: this function has the side effect of putting the 'Fd'--- into non-blocking mode (@O_NONBLOCK@) due to the way the standard--- IO library implements multithreaded I\/O.----fdToHandle :: Fd -> IO Handle--#ifdef __GLASGOW_HASKELL__-#if __GLASGOW_HASKELL__ >= 611-handleToFd h@(FileHandle _ m) = do- withHandle' "handleToFd" h m $ handleToFd' h-handleToFd h@(DuplexHandle _ r w) = do- _ <- withHandle' "handleToFd" h r $ handleToFd' h- withHandle' "handleToFd" h w $ handleToFd' h- -- for a DuplexHandle, make sure we mark both sides as closed,- -- otherwise a finalizer will come along later and close the other- -- side. (#3914)--handleToFd' :: Handle -> Handle__ -> IO (Handle__, Fd)-handleToFd' h h_@Handle__{haType=_,..} = do- case cast haDevice of- Nothing -> ioError (ioeSetErrorString (mkIOError IllegalOperation- "handleToFd" (Just h) Nothing) - "handle is not a file descriptor")- Just fd -> do- -- converting a Handle into an Fd effectively means- -- letting go of the Handle; it is put into a closed- -- state as a result. - flushWriteBuffer h_- FD.release fd- return (Handle__{haType=ClosedHandle,..}, Fd (FD.fdFD fd))--fdToHandle fd = FD.fdToHandle (fromIntegral fd)--#else--handleToFd h = withHandle "handleToFd" h $ \ h_ -> do- -- converting a Handle into an Fd effectively means- -- letting go of the Handle; it is put into a closed- -- state as a result. - let fd = haFD h_- flushWriteBufferOnly h_- unlockFile (fromIntegral fd)- -- setting the Handle's fd to (-1) as well as its 'type'- -- to closed, is enough to disable the finalizer that- -- eventually is run on the Handle.- return (h_{haFD= (-1),haType=ClosedHandle}, Fd (fromIntegral fd))--fdToHandle fd = GHC.Handle.fdToHandle (fromIntegral fd)-#endif-#endif--#ifdef __HUGS__-handleToFd h = do- fd <- Hugs.IO.handleToFd h- return (fromIntegral fd)--fdToHandle fd = do- mode <- fdGetMode (fromIntegral fd)- Hugs.IO.openFd (fromIntegral fd) False mode True-#endif---- -------------------------------------------------------------------------------- Fd options--data FdOption = AppendOnWrite -- ^O_APPEND- | CloseOnExec -- ^FD_CLOEXEC- | NonBlockingRead -- ^O_NONBLOCK- | SynchronousWrites -- ^O_SYNC--fdOption2Int :: FdOption -> CInt-fdOption2Int CloseOnExec = (#const FD_CLOEXEC)-fdOption2Int AppendOnWrite = (#const O_APPEND)-fdOption2Int NonBlockingRead = (#const O_NONBLOCK)-fdOption2Int SynchronousWrites = (#const O_SYNC)---- | May throw an exception if this is an invalid descriptor.-queryFdOption :: Fd -> FdOption -> IO Bool-queryFdOption (Fd fd) opt = do- r <- throwErrnoIfMinus1 "queryFdOption" (c_fcntl_read fd flag)- return ((r .&. fdOption2Int opt) /= 0)- where- flag = case opt of- CloseOnExec -> (#const F_GETFD)- _ -> (#const F_GETFL)---- | May throw an exception if this is an invalid descriptor.-setFdOption :: Fd -> FdOption -> Bool -> IO ()-setFdOption (Fd fd) opt val = do- r <- throwErrnoIfMinus1 "setFdOption" (c_fcntl_read fd getflag)- let r' | val = r .|. opt_val- | otherwise = r .&. (complement opt_val)- throwErrnoIfMinus1_ "setFdOption"- (c_fcntl_write fd setflag (fromIntegral r'))- where- (getflag,setflag)= case opt of- CloseOnExec -> ((#const F_GETFD),(#const F_SETFD)) - _ -> ((#const F_GETFL),(#const F_SETFL))- opt_val = fdOption2Int opt--foreign import ccall unsafe "HsBase.h fcntl_read"- c_fcntl_read :: CInt -> CInt -> IO CInt--foreign import ccall unsafe "HsBase.h fcntl_write"- c_fcntl_write :: CInt -> CInt -> CLong -> IO CInt---- -------------------------------------------------------------------------------- Seeking --mode2Int :: SeekMode -> CInt-mode2Int AbsoluteSeek = (#const SEEK_SET)-mode2Int RelativeSeek = (#const SEEK_CUR)-mode2Int SeekFromEnd = (#const SEEK_END)---- | May throw an exception if this is an invalid descriptor.-fdSeek :: Fd -> SeekMode -> FileOffset -> IO FileOffset-fdSeek (Fd fd) mode off =- throwErrnoIfMinus1 "fdSeek" (Base.c_lseek fd off (mode2Int mode))---- -------------------------------------------------------------------------------- Locking--data LockRequest = ReadLock- | WriteLock- | Unlock--type FileLock = (LockRequest, SeekMode, FileOffset, FileOffset)---- | May throw an exception if this is an invalid descriptor.-getLock :: Fd -> FileLock -> IO (Maybe (ProcessID, FileLock))-getLock (Fd fd) lock =- allocaLock lock $ \p_flock -> do- throwErrnoIfMinus1_ "getLock" (c_fcntl_lock fd (#const F_GETLK) p_flock)- result <- bytes2ProcessIDAndLock p_flock- return (maybeResult result)- where- maybeResult (_, (Unlock, _, _, _)) = Nothing- maybeResult x = Just x--type CFLock = ()--foreign import ccall unsafe "HsBase.h fcntl_lock"- c_fcntl_lock :: CInt -> CInt -> Ptr CFLock -> IO CInt--allocaLock :: FileLock -> (Ptr CFLock -> IO a) -> IO a-allocaLock (lockreq, mode, start, len) io = - allocaBytes (#const sizeof(struct flock)) $ \p -> do- (#poke struct flock, l_type) p (lockReq2Int lockreq :: CShort)- (#poke struct flock, l_whence) p (fromIntegral (mode2Int mode) :: CShort)- (#poke struct flock, l_start) p start- (#poke struct flock, l_len) p len- io p--lockReq2Int :: LockRequest -> CShort-lockReq2Int ReadLock = (#const F_RDLCK)-lockReq2Int WriteLock = (#const F_WRLCK)-lockReq2Int Unlock = (#const F_UNLCK)--bytes2ProcessIDAndLock :: Ptr CFLock -> IO (ProcessID, FileLock)-bytes2ProcessIDAndLock p = do- req <- (#peek struct flock, l_type) p- mode <- (#peek struct flock, l_whence) p- start <- (#peek struct flock, l_start) p- len <- (#peek struct flock, l_len) p- pid <- (#peek struct flock, l_pid) p- return (pid, (int2req req, int2mode mode, start, len))- where- int2req :: CShort -> LockRequest- int2req (#const F_RDLCK) = ReadLock- int2req (#const F_WRLCK) = WriteLock- int2req (#const F_UNLCK) = Unlock- int2req _ = error $ "int2req: bad argument"-- int2mode :: CShort -> SeekMode- int2mode (#const SEEK_SET) = AbsoluteSeek- int2mode (#const SEEK_CUR) = RelativeSeek- int2mode (#const SEEK_END) = SeekFromEnd- int2mode _ = error $ "int2mode: bad argument"---- | May throw an exception if this is an invalid descriptor.-setLock :: Fd -> FileLock -> IO ()-setLock (Fd fd) lock = do- allocaLock lock $ \p_flock ->- throwErrnoIfMinus1_ "setLock" (c_fcntl_lock fd (#const F_SETLK) p_flock)---- | May throw an exception if this is an invalid descriptor.-waitToSetLock :: Fd -> FileLock -> IO ()-waitToSetLock (Fd fd) lock = do- allocaLock lock $ \p_flock ->- throwErrnoIfMinus1_ "waitToSetLock" - (c_fcntl_lock fd (#const F_SETLKW) p_flock)---- -------------------------------------------------------------------------------- fd{Read,Write}---- | Read data from an 'Fd' and convert it to a 'String' using the locale encoding.--- Throws an exception if this is an invalid descriptor, or EOF has been--- reached.-fdRead :: Fd- -> ByteCount -- ^How many bytes to read- -> IO (String, ByteCount) -- ^The bytes read, how many bytes were read.-fdRead _fd 0 = return ("", 0)-fdRead fd nbytes = do- allocaBytes (fromIntegral nbytes) $ \ buf -> do- rc <- fdReadBuf fd buf nbytes- case rc of- 0 -> ioError (ioeSetErrorString (mkIOError EOF "fdRead" Nothing Nothing) "EOF")- n -> do- s <- peekCStringLen (castPtr buf, fromIntegral n)- return (s, n)---- | Read data from an 'Fd' into memory. This is exactly equivalent--- to the POSIX @read@ function.-fdReadBuf :: Fd- -> Ptr Word8 -- ^ Memory in which to put the data- -> ByteCount -- ^ Maximum number of bytes to read- -> IO ByteCount -- ^ Number of bytes read (zero for EOF)-fdReadBuf _fd _buf 0 = return 0-fdReadBuf fd buf nbytes = - fmap fromIntegral $- throwErrnoIfMinus1Retry "fdReadBuf" $ - c_safe_read (fromIntegral fd) (castPtr buf) nbytes--foreign import ccall safe "read"- c_safe_read :: CInt -> Ptr CChar -> CSize -> IO CSsize---- | Write a 'String' to an 'Fd' using the locale encoding.-fdWrite :: Fd -> String -> IO ByteCount-fdWrite fd str = - withCStringLen str $ \ (buf,len) ->- fdWriteBuf fd (castPtr buf) (fromIntegral len)---- | Write data from memory to an 'Fd'. This is exactly equivalent--- to the POSIX @write@ function.-fdWriteBuf :: Fd- -> Ptr Word8 -- ^ Memory containing the data to write- -> ByteCount -- ^ Maximum number of bytes to write- -> IO ByteCount -- ^ Number of bytes written-fdWriteBuf fd buf len =- fmap fromIntegral $- throwErrnoIfMinus1Retry "fdWriteBuf" $ - c_safe_write (fromIntegral fd) (castPtr buf) len--foreign import ccall safe "write" - c_safe_write :: CInt -> Ptr CChar -> CSize -> IO CSsize
+ System/Posix/IO/ByteString.hsc view
@@ -0,0 +1,102 @@+{-# LANGUAGE ForeignFunctionInterface #-}+{-# OPTIONS_GHC -fno-warn-unused-imports #-}+{-# OPTIONS_GHC -XRecordWildCards #-}+#if __GLASGOW_HASKELL__ >= 701+{-# LANGUAGE Trustworthy #-}+#endif+-----------------------------------------------------------------------------+-- |+-- Module : System.Posix.IO.ByteString+-- 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 IO support. These types and functions correspond to the unix+-- functions open(2), close(2), etc. For more portable functions+-- which are more like fopen(3) and friends from stdio.h, see+-- "System.IO".+--+-----------------------------------------------------------------------------++#include "HsUnix.h"++module System.Posix.IO.ByteString (+ -- * Input \/ Output++ -- ** Standard file descriptors+ stdInput, stdOutput, stdError,++ -- ** Opening and closing files+ OpenMode(..),+ OpenFileFlags(..), defaultFileFlags,+ openFd, createFile,+ closeFd,++ -- ** Reading\/writing data+ -- |Programmers using the 'fdRead' and 'fdWrite' API should be aware that+ -- EAGAIN exceptions may occur for non-blocking IO!++ fdRead, fdWrite,+ fdReadBuf, fdWriteBuf,++ -- ** Seeking+ fdSeek,++ -- ** File options+ FdOption(..),+ queryFdOption,+ setFdOption,++ -- ** Locking+ FileLock,+ LockRequest(..),+ getLock, setLock,+ waitToSetLock,++ -- ** Pipes+ createPipe,++ -- ** Duplicating file descriptors+ dup, dupTo,++ -- ** Converting file descriptors to\/from Handles+ handleToFd,+ fdToHandle, ++ ) where++import System.Posix.Types+import System.Posix.IO.Common+import Foreign.C hiding (+ throwErrnoPath,+ throwErrnoPathIf,+ throwErrnoPathIf_,+ throwErrnoPathIfNull,+ throwErrnoPathIfMinus1,+ throwErrnoPathIfMinus1_ )++import System.Posix.ByteString.FilePath+++-- |Open and optionally create this file. See 'System.Posix.Files'+-- for information on how to use the 'FileMode' type.+openFd :: RawFilePath+ -> OpenMode+ -> Maybe FileMode -- ^Just x => creates the file with the given modes, Nothing => the file must exist.+ -> OpenFileFlags+ -> IO Fd+openFd name how maybe_mode flags = do+ withFilePath name $ \str -> do+ throwErrnoPathIfMinus1Retry "openFd" name $+ open_ str how maybe_mode flags++-- |Create and open this file in WriteOnly mode. A special case of+-- 'openFd'. See 'System.Posix.Files' for information on how to use+-- the 'FileMode' type.++createFile :: RawFilePath -> FileMode -> IO Fd+createFile name mode+ = openFd name WriteOnly (Just mode) defaultFileFlags{ trunc=True }
+ System/Posix/IO/Common.hsc view
@@ -0,0 +1,456 @@+{-# LANGUAGE ForeignFunctionInterface #-}+{-# OPTIONS_GHC -fno-warn-unused-imports #-}+{-# OPTIONS_GHC -XRecordWildCards #-}+#if __GLASGOW_HASKELL__ >= 701+{-# LANGUAGE Trustworthy #-}+#endif+-----------------------------------------------------------------------------+-- |+-- Module : System.Posix.IO.Common+-- 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)+--+-----------------------------------------------------------------------------++module System.Posix.IO.Common (+ -- * Input \/ Output++ -- ** Standard file descriptors+ stdInput, stdOutput, stdError,++ -- ** Opening and closing files+ OpenMode(..),+ OpenFileFlags(..), defaultFileFlags,+ open_,+ closeFd,++ -- ** Reading\/writing data+ -- |Programmers using the 'fdRead' and 'fdWrite' API should be aware that+ -- EAGAIN exceptions may occur for non-blocking IO!++ fdRead, fdWrite,+ fdReadBuf, fdWriteBuf,++ -- ** Seeking+ fdSeek,++ -- ** File options+ FdOption(..),+ queryFdOption,+ setFdOption,++ -- ** Locking+ FileLock,+ LockRequest(..),+ getLock, setLock,+ waitToSetLock,++ -- ** Pipes+ createPipe,++ -- ** Duplicating file descriptors+ dup, dupTo,++ -- ** Converting file descriptors to\/from Handles+ handleToFd,+ fdToHandle, ++ ) where++import System.IO+import System.IO.Error+import System.Posix.Types+import System.Posix.Error+import qualified System.Posix.Internals as Base++import Foreign+import Foreign.C+import Data.Bits++#ifdef __GLASGOW_HASKELL__+#if __GLASGOW_HASKELL__ >= 611+import GHC.IO.Handle+import GHC.IO.Handle.Internals+import GHC.IO.Handle.Types+import qualified GHC.IO.FD as FD+import qualified GHC.IO.Handle.FD as FD+import GHC.IO.Exception+import Data.Typeable (cast)+#else+import GHC.IOBase+import GHC.Handle hiding (fdToHandle)+import qualified GHC.Handle+#endif+#endif++#ifdef __HUGS__+import Hugs.Prelude (IOException(..), IOErrorType(..))+import qualified Hugs.IO (handleToFd, openFd)+#endif++#include "HsUnix.h"++-- -----------------------------------------------------------------------------+-- Pipes+-- |The 'createPipe' function creates a pair of connected file+-- descriptors. The first component is the fd to read from, the second+-- is the write end. Although pipes may be bidirectional, this+-- behaviour is not portable and programmers should use two separate+-- pipes for this purpose. May throw an exception if this is an+-- invalid descriptor.++createPipe :: IO (Fd, Fd)+createPipe =+ allocaArray 2 $ \p_fd -> do+ throwErrnoIfMinus1_ "createPipe" (c_pipe p_fd)+ rfd <- peekElemOff p_fd 0+ wfd <- peekElemOff p_fd 1+ return (Fd rfd, Fd wfd)++foreign import ccall unsafe "pipe"+ c_pipe :: Ptr CInt -> IO CInt++-- -----------------------------------------------------------------------------+-- Duplicating file descriptors++-- | May throw an exception if this is an invalid descriptor.+dup :: Fd -> IO Fd+dup (Fd fd) = do r <- throwErrnoIfMinus1 "dup" (c_dup fd); return (Fd r)++-- | May throw an exception if this is an invalid descriptor.+dupTo :: Fd -> Fd -> IO Fd+dupTo (Fd fd1) (Fd fd2) = do+ r <- throwErrnoIfMinus1 "dupTo" (c_dup2 fd1 fd2)+ return (Fd r)++foreign import ccall unsafe "dup"+ c_dup :: CInt -> IO CInt++foreign import ccall unsafe "dup2"+ c_dup2 :: CInt -> CInt -> IO CInt++-- -----------------------------------------------------------------------------+-- Opening and closing files++stdInput, stdOutput, stdError :: Fd+stdInput = Fd (#const STDIN_FILENO)+stdOutput = Fd (#const STDOUT_FILENO)+stdError = Fd (#const STDERR_FILENO)++data OpenMode = ReadOnly | WriteOnly | ReadWrite++-- |Correspond to some of the int flags from C's fcntl.h.+data OpenFileFlags =+ OpenFileFlags {+ append :: Bool, -- ^ O_APPEND+ exclusive :: Bool, -- ^ O_EXCL+ noctty :: Bool, -- ^ O_NOCTTY+ nonBlock :: Bool, -- ^ O_NONBLOCK+ trunc :: Bool -- ^ O_TRUNC+ }+++-- |Default values for the 'OpenFileFlags' type. False for each of+-- append, exclusive, noctty, nonBlock, and trunc.+defaultFileFlags :: OpenFileFlags+defaultFileFlags =+ OpenFileFlags {+ append = False,+ exclusive = False,+ noctty = False,+ nonBlock = False,+ trunc = False+ }+++-- |Open and optionally create this file. See 'System.Posix.Files'+-- for information on how to use the 'FileMode' type.+open_ :: CString+ -> OpenMode+ -> Maybe FileMode -- ^Just x => creates the file with the given modes, Nothing => the file must exist.+ -> OpenFileFlags+ -> IO Fd+open_ str how maybe_mode (OpenFileFlags appendFlag exclusiveFlag nocttyFlag+ nonBlockFlag truncateFlag) = do+ fd <- c_open str all_flags mode_w+ return (Fd fd)+ where+ all_flags = creat .|. flags .|. open_mode++ flags =+ (if appendFlag then (#const O_APPEND) else 0) .|.+ (if exclusiveFlag then (#const O_EXCL) else 0) .|.+ (if nocttyFlag then (#const O_NOCTTY) else 0) .|.+ (if nonBlockFlag then (#const O_NONBLOCK) else 0) .|.+ (if truncateFlag then (#const O_TRUNC) else 0)++ (creat, mode_w) = case maybe_mode of + Nothing -> (0,0)+ Just x -> ((#const O_CREAT), x)++ open_mode = case how of+ ReadOnly -> (#const O_RDONLY)+ WriteOnly -> (#const O_WRONLY)+ ReadWrite -> (#const O_RDWR)++foreign import ccall unsafe "__hscore_open"+ c_open :: CString -> CInt -> CMode -> IO CInt++-- |Close this file descriptor. May throw an exception if this is an+-- invalid descriptor.++closeFd :: Fd -> IO ()+closeFd (Fd fd) = throwErrnoIfMinus1_ "closeFd" (c_close fd)++foreign import ccall unsafe "HsUnix.h close"+ c_close :: CInt -> IO CInt++-- -----------------------------------------------------------------------------+-- Converting file descriptors to/from Handles++-- | Extracts the 'Fd' from a 'Handle'. This function has the side effect+-- of closing the 'Handle' and flushing its write buffer, if necessary.+handleToFd :: Handle -> IO Fd++-- | Converts an 'Fd' into a 'Handle' that can be used with the+-- standard Haskell IO library (see "System.IO"). +--+-- GHC only: this function has the side effect of putting the 'Fd'+-- into non-blocking mode (@O_NONBLOCK@) due to the way the standard+-- IO library implements multithreaded I\/O.+--+fdToHandle :: Fd -> IO Handle++#ifdef __GLASGOW_HASKELL__+#if __GLASGOW_HASKELL__ >= 611+handleToFd h@(FileHandle _ m) = do+ withHandle' "handleToFd" h m $ handleToFd' h+handleToFd h@(DuplexHandle _ r w) = do+ _ <- withHandle' "handleToFd" h r $ handleToFd' h+ withHandle' "handleToFd" h w $ handleToFd' h+ -- for a DuplexHandle, make sure we mark both sides as closed,+ -- otherwise a finalizer will come along later and close the other+ -- side. (#3914)++handleToFd' :: Handle -> Handle__ -> IO (Handle__, Fd)+handleToFd' h h_@Handle__{haType=_,..} = do+ case cast haDevice of+ Nothing -> ioError (ioeSetErrorString (mkIOError IllegalOperation+ "handleToFd" (Just h) Nothing) + "handle is not a file descriptor")+ Just fd -> do+ -- converting a Handle into an Fd effectively means+ -- letting go of the Handle; it is put into a closed+ -- state as a result. + flushWriteBuffer h_+ FD.release fd+ return (Handle__{haType=ClosedHandle,..}, Fd (FD.fdFD fd))++fdToHandle fd = FD.fdToHandle (fromIntegral fd)++#else++handleToFd h = withHandle "handleToFd" h $ \ h_ -> do+ -- converting a Handle into an Fd effectively means+ -- letting go of the Handle; it is put into a closed+ -- state as a result. + let fd = haFD h_+ flushWriteBufferOnly h_+ unlockFile (fromIntegral fd)+ -- setting the Handle's fd to (-1) as well as its 'type'+ -- to closed, is enough to disable the finalizer that+ -- eventually is run on the Handle.+ return (h_{haFD= (-1),haType=ClosedHandle}, Fd (fromIntegral fd))++fdToHandle fd = GHC.Handle.fdToHandle (fromIntegral fd)+#endif+#endif++#ifdef __HUGS__+handleToFd h = do+ fd <- Hugs.IO.handleToFd h+ return (fromIntegral fd)++fdToHandle fd = do+ mode <- fdGetMode (fromIntegral fd)+ Hugs.IO.openFd (fromIntegral fd) False mode True+#endif++-- -----------------------------------------------------------------------------+-- Fd options++data FdOption = AppendOnWrite -- ^O_APPEND+ | CloseOnExec -- ^FD_CLOEXEC+ | NonBlockingRead -- ^O_NONBLOCK+ | SynchronousWrites -- ^O_SYNC++fdOption2Int :: FdOption -> CInt+fdOption2Int CloseOnExec = (#const FD_CLOEXEC)+fdOption2Int AppendOnWrite = (#const O_APPEND)+fdOption2Int NonBlockingRead = (#const O_NONBLOCK)+fdOption2Int SynchronousWrites = (#const O_SYNC)++-- | May throw an exception if this is an invalid descriptor.+queryFdOption :: Fd -> FdOption -> IO Bool+queryFdOption (Fd fd) opt = do+ r <- throwErrnoIfMinus1 "queryFdOption" (Base.c_fcntl_read fd flag)+ return ((r .&. fdOption2Int opt) /= 0)+ where+ flag = case opt of+ CloseOnExec -> (#const F_GETFD)+ _ -> (#const F_GETFL)++-- | May throw an exception if this is an invalid descriptor.+setFdOption :: Fd -> FdOption -> Bool -> IO ()+setFdOption (Fd fd) opt val = do+ r <- throwErrnoIfMinus1 "setFdOption" (Base.c_fcntl_read fd getflag)+ let r' | val = r .|. opt_val+ | otherwise = r .&. (complement opt_val)+ throwErrnoIfMinus1_ "setFdOption"+ (Base.c_fcntl_write fd setflag (fromIntegral r'))+ where+ (getflag,setflag)= case opt of+ CloseOnExec -> ((#const F_GETFD),(#const F_SETFD)) + _ -> ((#const F_GETFL),(#const F_SETFL))+ opt_val = fdOption2Int opt++-- -----------------------------------------------------------------------------+-- Seeking ++mode2Int :: SeekMode -> CInt+mode2Int AbsoluteSeek = (#const SEEK_SET)+mode2Int RelativeSeek = (#const SEEK_CUR)+mode2Int SeekFromEnd = (#const SEEK_END)++-- | May throw an exception if this is an invalid descriptor.+fdSeek :: Fd -> SeekMode -> FileOffset -> IO FileOffset+fdSeek (Fd fd) mode off =+ throwErrnoIfMinus1 "fdSeek" (Base.c_lseek fd off (mode2Int mode))++-- -----------------------------------------------------------------------------+-- Locking++data LockRequest = ReadLock+ | WriteLock+ | Unlock++type FileLock = (LockRequest, SeekMode, FileOffset, FileOffset)++-- | May throw an exception if this is an invalid descriptor.+getLock :: Fd -> FileLock -> IO (Maybe (ProcessID, FileLock))+getLock (Fd fd) lock =+ allocaLock lock $ \p_flock -> do+ throwErrnoIfMinus1_ "getLock" (Base.c_fcntl_lock fd (#const F_GETLK) p_flock)+ result <- bytes2ProcessIDAndLock p_flock+ return (maybeResult result)+ where+ maybeResult (_, (Unlock, _, _, _)) = Nothing+ maybeResult x = Just x++type CFLock = ()++allocaLock :: FileLock -> (Ptr CFLock -> IO a) -> IO a+allocaLock (lockreq, mode, start, len) io = + allocaBytes (#const sizeof(struct flock)) $ \p -> do+ (#poke struct flock, l_type) p (lockReq2Int lockreq :: CShort)+ (#poke struct flock, l_whence) p (fromIntegral (mode2Int mode) :: CShort)+ (#poke struct flock, l_start) p start+ (#poke struct flock, l_len) p len+ io p++lockReq2Int :: LockRequest -> CShort+lockReq2Int ReadLock = (#const F_RDLCK)+lockReq2Int WriteLock = (#const F_WRLCK)+lockReq2Int Unlock = (#const F_UNLCK)++bytes2ProcessIDAndLock :: Ptr CFLock -> IO (ProcessID, FileLock)+bytes2ProcessIDAndLock p = do+ req <- (#peek struct flock, l_type) p+ mode <- (#peek struct flock, l_whence) p+ start <- (#peek struct flock, l_start) p+ len <- (#peek struct flock, l_len) p+ pid <- (#peek struct flock, l_pid) p+ return (pid, (int2req req, int2mode mode, start, len))+ where+ int2req :: CShort -> LockRequest+ int2req (#const F_RDLCK) = ReadLock+ int2req (#const F_WRLCK) = WriteLock+ int2req (#const F_UNLCK) = Unlock+ int2req _ = error $ "int2req: bad argument"++ int2mode :: CShort -> SeekMode+ int2mode (#const SEEK_SET) = AbsoluteSeek+ int2mode (#const SEEK_CUR) = RelativeSeek+ int2mode (#const SEEK_END) = SeekFromEnd+ int2mode _ = error $ "int2mode: bad argument"++-- | May throw an exception if this is an invalid descriptor.+setLock :: Fd -> FileLock -> IO ()+setLock (Fd fd) lock = do+ allocaLock lock $ \p_flock ->+ throwErrnoIfMinus1_ "setLock" (Base.c_fcntl_lock fd (#const F_SETLK) p_flock)++-- | May throw an exception if this is an invalid descriptor.+waitToSetLock :: Fd -> FileLock -> IO ()+waitToSetLock (Fd fd) lock = do+ allocaLock lock $ \p_flock ->+ throwErrnoIfMinus1_ "waitToSetLock" + (Base.c_fcntl_lock fd (#const F_SETLKW) p_flock)++-- -----------------------------------------------------------------------------+-- fd{Read,Write}++-- | Read data from an 'Fd' and convert it to a 'String' using the locale encoding.+-- Throws an exception if this is an invalid descriptor, or EOF has been+-- reached.+fdRead :: Fd+ -> ByteCount -- ^How many bytes to read+ -> IO (String, ByteCount) -- ^The bytes read, how many bytes were read.+fdRead _fd 0 = return ("", 0)+fdRead fd nbytes = do+ allocaBytes (fromIntegral nbytes) $ \ buf -> do+ rc <- fdReadBuf fd buf nbytes+ case rc of+ 0 -> ioError (ioeSetErrorString (mkIOError EOF "fdRead" Nothing Nothing) "EOF")+ n -> do+ s <- peekCStringLen (castPtr buf, fromIntegral n)+ return (s, n)++-- | Read data from an 'Fd' into memory. This is exactly equivalent+-- to the POSIX @read@ function.+fdReadBuf :: Fd+ -> Ptr Word8 -- ^ Memory in which to put the data+ -> ByteCount -- ^ Maximum number of bytes to read+ -> IO ByteCount -- ^ Number of bytes read (zero for EOF)+fdReadBuf _fd _buf 0 = return 0+fdReadBuf fd buf nbytes = + fmap fromIntegral $+ throwErrnoIfMinus1Retry "fdReadBuf" $ + c_safe_read (fromIntegral fd) (castPtr buf) nbytes++foreign import ccall safe "read"+ c_safe_read :: CInt -> Ptr CChar -> CSize -> IO CSsize++-- | Write a 'String' to an 'Fd' using the locale encoding.+fdWrite :: Fd -> String -> IO ByteCount+fdWrite fd str = + withCStringLen str $ \ (buf,len) ->+ fdWriteBuf fd (castPtr buf) (fromIntegral len)++-- | Write data from memory to an 'Fd'. This is exactly equivalent+-- to the POSIX @write@ function.+fdWriteBuf :: Fd+ -> Ptr Word8 -- ^ Memory containing the data to write+ -> ByteCount -- ^ Maximum number of bytes to write+ -> IO ByteCount -- ^ Number of bytes written+fdWriteBuf fd buf len =+ fmap fromIntegral $+ throwErrnoIfMinus1Retry "fdWriteBuf" $ + c_safe_write (fromIntegral fd) (castPtr buf) len++foreign import ccall safe "write" + c_safe_write :: CInt -> Ptr CChar -> CSize -> IO CSsize
System/Posix/Process.hsc view
@@ -1,4 +1,7 @@ {-# LANGUAGE ForeignFunctionInterface #-}+#if __GLASGOW_HASKELL__ >= 701+{-# LANGUAGE Trustworthy #-}+#endif ----------------------------------------------------------------------------- -- | -- Module : System.Posix.Process@@ -67,23 +70,10 @@ #include "HsUnix.h" -import Foreign.C.Error-import Foreign.C.String-import Foreign.C.Types ( CInt, CClock )-import Foreign.Marshal.Alloc ( alloca, allocaBytes )-import Foreign.Marshal.Array ( withArray0 )-import Foreign.Marshal.Utils ( withMany )-import Foreign.Ptr ( Ptr, nullPtr )-import Foreign.StablePtr ( StablePtr, newStablePtr, freeStablePtr )-import Foreign.Storable ( Storable(..) )-import System.Exit+import Foreign+import Foreign.C import System.Posix.Process.Internals-import System.Posix.Types-import Control.Monad--#ifdef __GLASGOW_HASKELL__-import GHC.TopHandler ( runIO )-#endif+import System.Posix.Process.Common #if __GLASGOW_HASKELL__ > 611 import System.Posix.Internals ( withFilePath )@@ -96,216 +86,6 @@ {-# CFILES cbits/HsUnix.c #-} #endif --- -------------------------------------------------------------------------------- Process environment---- | 'getProcessID' calls @getpid@ to obtain the 'ProcessID' for--- the current process.-getProcessID :: IO ProcessID-getProcessID = c_getpid--foreign import ccall unsafe "getpid"- c_getpid :: IO CPid---- | 'getProcessID' calls @getppid@ to obtain the 'ProcessID' for--- the parent of the current process.-getParentProcessID :: IO ProcessID-getParentProcessID = c_getppid--foreign import ccall unsafe "getppid"- c_getppid :: IO CPid---- | 'getProcessGroupID' calls @getpgrp@ to obtain the--- 'ProcessGroupID' for the current process.-getProcessGroupID :: IO ProcessGroupID-getProcessGroupID = c_getpgrp--foreign import ccall unsafe "getpgrp"- c_getpgrp :: IO CPid---- | @'getProcessGroupIDOf' pid@ calls @getpgid@ to obtain the--- 'ProcessGroupID' for process @pid@.-getProcessGroupIDOf :: ProcessID -> IO ProcessGroupID-getProcessGroupIDOf pid =- throwErrnoIfMinus1 "getProcessGroupIDOf" (c_getpgid pid)--foreign import ccall unsafe "getpgid"- c_getpgid :: CPid -> IO CPid--{-- To be added in the future, after the deprecation period for the- existing createProcessGroup has elapsed:---- | 'createProcessGroup' calls @setpgid(0,0)@ to make--- the current process a new process group leader.-createProcessGroup :: IO ProcessGroupID-createProcessGroup = do- throwErrnoIfMinus1_ "createProcessGroup" (c_setpgid 0 0)- pgid <- getProcessGroupID- return pgid--}---- | @'createProcessGroupFor' pid@ calls @setpgid@ to make--- process @pid@ a new process group leader.-createProcessGroupFor :: ProcessID -> IO ProcessGroupID-createProcessGroupFor pid = do- throwErrnoIfMinus1_ "createProcessGroupFor" (c_setpgid pid 0)- return pid---- | @'joinProcessGroup' pgid@ calls @setpgid@ to set the--- 'ProcessGroupID' of the current process to @pgid@.-joinProcessGroup :: ProcessGroupID -> IO ()-joinProcessGroup pgid =- throwErrnoIfMinus1_ "joinProcessGroup" (c_setpgid 0 pgid)--{-- To be added in the future, after the deprecation period for the- existing setProcessGroupID has elapsed:---- | @'setProcessGroupID' pgid@ calls @setpgid@ to set the--- 'ProcessGroupID' of the current process to @pgid@.-setProcessGroupID :: ProcessGroupID -> IO ()-setProcessGroupID pgid =- throwErrnoIfMinus1_ "setProcessGroupID" (c_setpgid 0 pgid)--}---- | @'setProcessGroupIDOf' pid pgid@ calls @setpgid@ to set the--- 'ProcessGroupIDOf' for process @pid@ to @pgid@.-setProcessGroupIDOf :: ProcessID -> ProcessGroupID -> IO ()-setProcessGroupIDOf pid pgid =- throwErrnoIfMinus1_ "setProcessGroupIDOf" (c_setpgid pid pgid)--foreign import ccall unsafe "setpgid"- c_setpgid :: CPid -> CPid -> IO CInt---- | 'createSession' calls @setsid@ to create a new session--- with the current process as session leader.-createSession :: IO ProcessGroupID-createSession = throwErrnoIfMinus1 "createSession" c_setsid--foreign import ccall unsafe "setsid"- c_setsid :: IO CPid---- -------------------------------------------------------------------------------- Process times---- All times in clock ticks (see getClockTick)--data ProcessTimes- = ProcessTimes { elapsedTime :: ClockTick- , userTime :: ClockTick- , systemTime :: ClockTick- , childUserTime :: ClockTick- , childSystemTime :: ClockTick- }---- | 'getProcessTimes' calls @times@ to obtain time-accounting--- information for the current process and its children.-getProcessTimes :: IO ProcessTimes-getProcessTimes = do- allocaBytes (#const sizeof(struct tms)) $ \p_tms -> do- elapsed <- throwErrnoIfMinus1 "getProcessTimes" (c_times p_tms)- ut <- (#peek struct tms, tms_utime) p_tms- st <- (#peek struct tms, tms_stime) p_tms- cut <- (#peek struct tms, tms_cutime) p_tms- cst <- (#peek struct tms, tms_cstime) p_tms- return (ProcessTimes{ elapsedTime = elapsed,- userTime = ut,- systemTime = st,- childUserTime = cut,- childSystemTime = cst- })--type CTms = ()--foreign import ccall unsafe "__hsunix_times"- c_times :: Ptr CTms -> IO CClock---- -------------------------------------------------------------------------------- Process scheduling priority--nice :: Int -> IO ()-nice prio = do- resetErrno- res <- c_nice (fromIntegral prio)- when (res == -1) $ do- err <- getErrno- when (err /= eOK) (throwErrno "nice")--foreign import ccall unsafe "nice"- c_nice :: CInt -> IO CInt--getProcessPriority :: ProcessID -> IO Int-getProcessGroupPriority :: ProcessGroupID -> IO Int-getUserPriority :: UserID -> IO Int--getProcessPriority pid = do- r <- throwErrnoIfMinus1 "getProcessPriority" $- c_getpriority (#const PRIO_PROCESS) (fromIntegral pid)- return (fromIntegral r)--getProcessGroupPriority pid = do- r <- throwErrnoIfMinus1 "getProcessPriority" $- c_getpriority (#const PRIO_PGRP) (fromIntegral pid)- return (fromIntegral r)--getUserPriority uid = do- r <- throwErrnoIfMinus1 "getUserPriority" $- c_getpriority (#const PRIO_USER) (fromIntegral uid)- return (fromIntegral r)--foreign import ccall unsafe "getpriority"- c_getpriority :: CInt -> CInt -> IO CInt--setProcessPriority :: ProcessID -> Int -> IO ()-setProcessGroupPriority :: ProcessGroupID -> Int -> IO ()-setUserPriority :: UserID -> Int -> IO ()--setProcessPriority pid val = - throwErrnoIfMinus1_ "setProcessPriority" $- c_setpriority (#const PRIO_PROCESS) (fromIntegral pid) (fromIntegral val)--setProcessGroupPriority pid val =- throwErrnoIfMinus1_ "setProcessPriority" $- c_setpriority (#const PRIO_PGRP) (fromIntegral pid) (fromIntegral val)--setUserPriority uid val =- throwErrnoIfMinus1_ "setUserPriority" $- c_setpriority (#const PRIO_USER) (fromIntegral uid) (fromIntegral val)--foreign import ccall unsafe "setpriority"- c_setpriority :: CInt -> CInt -> CInt -> IO CInt---- -------------------------------------------------------------------------------- Forking, execution--#ifdef __GLASGOW_HASKELL__-{- | 'forkProcess' corresponds to the POSIX @fork@ system call.-The 'IO' action passed as an argument is executed in the child process; no other-threads will be copied to the child process.-On success, 'forkProcess' returns the child's 'ProcessID' to the parent process;-in case of an error, an exception is thrown.--'forkProcess' comes with a giant warning: since any other running-threads are not copied into the child process, it's easy to go wrong:-e.g. by accessing some shared resource that was held by another thread-in the parent.--GHC note: 'forkProcess' is not currently supported when using multiple-processors (@+RTS -N@), although it is supported with @-threaded@ as-long as only one processor is being used.--}--forkProcess :: IO () -> IO ProcessID-forkProcess action = do- stable <- newStablePtr (runIO action)- pid <- throwErrnoIfMinus1 "forkProcess" (forkProcessPrim stable)- freeStablePtr stable- return pid--foreign import ccall "forkProcess" forkProcessPrim :: StablePtr (IO ()) -> IO CPid-#endif /* __GLASGOW_HASKELL__ */- -- | @'executeFile' cmd args env@ calls one of the -- @execv*@ family, depending on whether or not the current -- PATH is to be searched for the command, and whether or not an@@ -353,108 +133,3 @@ foreign import ccall unsafe "execve" c_execve :: CString -> Ptr CString -> Ptr CString -> IO CInt --- -------------------------------------------------------------------------------- Waiting for process termination---- | @'getProcessStatus' blk stopped pid@ calls @waitpid@, returning--- @'Just' tc@, the 'ProcessStatus' for process @pid@ if it is--- available, 'Nothing' otherwise. If @blk@ is 'False', then--- @WNOHANG@ is set in the options for @waitpid@, otherwise not.--- If @stopped@ is 'True', then @WUNTRACED@ is set in the--- options for @waitpid@, otherwise not.-getProcessStatus :: Bool -> Bool -> ProcessID -> IO (Maybe ProcessStatus)-getProcessStatus block stopped pid =- alloca $ \wstatp -> do- pid' <- throwErrnoIfMinus1Retry "getProcessStatus"- (c_waitpid pid wstatp (waitOptions block stopped))- case pid' of- 0 -> return Nothing- _ -> do ps <- readWaitStatus wstatp- return (Just ps)---- safe, because this call might block-foreign import ccall safe "waitpid"- c_waitpid :: CPid -> Ptr CInt -> CInt -> IO CPid---- | @'getGroupProcessStatus' blk stopped pgid@ calls @waitpid@,--- returning @'Just' (pid, tc)@, the 'ProcessID' and--- 'ProcessStatus' for any process in group @pgid@ if one is--- available, 'Nothing' otherwise. If @blk@ is 'False', then--- @WNOHANG@ is set in the options for @waitpid@, otherwise not.--- If @stopped@ is 'True', then @WUNTRACED@ is set in the--- options for @waitpid@, otherwise not.-getGroupProcessStatus :: Bool- -> Bool- -> ProcessGroupID- -> IO (Maybe (ProcessID, ProcessStatus))-getGroupProcessStatus block stopped pgid =- alloca $ \wstatp -> do- pid <- throwErrnoIfMinus1Retry "getGroupProcessStatus"- (c_waitpid (-pgid) wstatp (waitOptions block stopped))- case pid of- 0 -> return Nothing- _ -> do ps <- readWaitStatus wstatp- return (Just (pid, ps))--- | @'getAnyProcessStatus' blk stopped@ calls @waitpid@, returning--- @'Just' (pid, tc)@, the 'ProcessID' and 'ProcessStatus' for any--- child process if one is available, 'Nothing' otherwise. If--- @blk@ is 'False', then @WNOHANG@ is set in the options for--- @waitpid@, otherwise not. If @stopped@ is 'True', then--- @WUNTRACED@ is set in the options for @waitpid@, otherwise not.-getAnyProcessStatus :: Bool -> Bool -> IO (Maybe (ProcessID, ProcessStatus))-getAnyProcessStatus block stopped = getGroupProcessStatus block stopped 1--waitOptions :: Bool -> Bool -> CInt--- block stopped-waitOptions False False = (#const WNOHANG)-waitOptions False True = (#const (WNOHANG|WUNTRACED))-waitOptions True False = 0-waitOptions True True = (#const WUNTRACED)---- Turn a (ptr to a) wait status into a ProcessStatus--readWaitStatus :: Ptr CInt -> IO ProcessStatus-readWaitStatus wstatp = do- wstat <- peek wstatp- decipherWaitStatus wstat---- -------------------------------------------------------------------------------- Exiting---- | @'exitImmediately' status@ calls @_exit@ to terminate the process--- with the indicated exit @status@.--- The operation never returns.-exitImmediately :: ExitCode -> IO ()-exitImmediately exitcode = c_exit (exitcode2Int exitcode)- where- exitcode2Int ExitSuccess = 0- exitcode2Int (ExitFailure n) = fromIntegral n--foreign import ccall unsafe "exit"- c_exit :: CInt -> IO ()---- -------------------------------------------------------------------------------- Deprecated or subject to change--{-# DEPRECATED createProcessGroup "This function is scheduled to be replaced by something different in the future, we therefore recommend that you do not use this version and use createProcessGroupFor instead." #-}--- | @'createProcessGroup' pid@ calls @setpgid@ to make--- process @pid@ a new process group leader.--- This function is currently deprecated,--- and might be changed to making the current--- process a new process group leader in future versions.-createProcessGroup :: ProcessID -> IO ProcessGroupID-createProcessGroup pid = do- throwErrnoIfMinus1_ "createProcessGroup" (c_setpgid pid 0)- return pid--{-# DEPRECATED setProcessGroupID "This function is scheduled to be replaced by something different in the future, we therefore recommend that you do not use this version and use setProcessGroupIdOf instead." #-}--- | @'setProcessGroupID' pid pgid@ calls @setpgid@ to set the--- 'ProcessGroupID' for process @pid@ to @pgid@.--- This function is currently deprecated,--- and might be changed to setting the 'ProcessGroupID'--- for the current process in future versions.-setProcessGroupID :: ProcessID -> ProcessGroupID -> IO ()-setProcessGroupID pid pgid =- throwErrnoIfMinus1_ "setProcessGroupID" (c_setpgid pid pgid)---- -----------------------------------------------------------------------------
+ System/Posix/Process/ByteString.hsc view
@@ -0,0 +1,140 @@+{-# LANGUAGE ForeignFunctionInterface #-}+#if __GLASGOW_HASKELL__ >= 701+{-# LANGUAGE Trustworthy #-}+#endif+-----------------------------------------------------------------------------+-- |+-- Module : System.Posix.Process.ByteString+-- 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 process support. See also the System.Cmd and System.Process+-- modules in the process package.+--+-----------------------------------------------------------------------------++module System.Posix.Process.ByteString (+ -- * Processes++ -- ** Forking and executing+#ifdef __GLASGOW_HASKELL__+ forkProcess,+#endif+ executeFile,+ + -- ** Exiting+ exitImmediately,++ -- ** Process environment+ getProcessID,+ getParentProcessID,++ -- ** Process groups+ getProcessGroupID,+ getProcessGroupIDOf,+ createProcessGroupFor,+ joinProcessGroup,+ setProcessGroupIDOf,++ -- ** Sessions+ createSession,++ -- ** Process times+ ProcessTimes(..),+ getProcessTimes,++ -- ** Scheduling priority+ nice,+ getProcessPriority,+ getProcessGroupPriority,+ getUserPriority,+ setProcessPriority,+ setProcessGroupPriority,+ setUserPriority,++ -- ** Process status+ ProcessStatus(..),+ getProcessStatus,+ getAnyProcessStatus,+ getGroupProcessStatus,++ -- ** Deprecated+ createProcessGroup,+ setProcessGroupID,++ ) where++#include "HsUnix.h"++import Foreign+import System.Posix.Process.Internals+import System.Posix.Process.Common++import Foreign.C hiding (+ throwErrnoPath,+ throwErrnoPathIf,+ throwErrnoPathIf_,+ throwErrnoPathIfNull,+ throwErrnoPathIfMinus1,+ throwErrnoPathIfMinus1_ )++import Data.ByteString (ByteString)+import qualified Data.ByteString.Char8 as BC++import System.Posix.ByteString.FilePath++#ifdef __HUGS__+{-# CFILES cbits/HsUnix.c #-}+#endif++-- | @'executeFile' cmd args env@ calls one of the+-- @execv*@ family, depending on whether or not the current+-- PATH is to be searched for the command, and whether or not an+-- environment is provided to supersede the process's current+-- environment. The basename (leading directory names suppressed) of+-- the command is passed to @execv*@ as @arg[0]@;+-- the argument list passed to 'executeFile' therefore +-- begins with @arg[1]@.+executeFile :: RawFilePath -- ^ Command+ -> Bool -- ^ Search PATH?+ -> [ByteString] -- ^ Arguments+ -> Maybe [(ByteString, ByteString)] -- ^ Environment+ -> IO a+executeFile path search args Nothing = do+ withFilePath path $ \s ->+ withMany withFilePath (path:args) $ \cstrs ->+ withArray0 nullPtr cstrs $ \arr -> do+ pPrPr_disableITimers+ if search + then throwErrnoPathIfMinus1_ "executeFile" path (c_execvp s arr)+ else throwErrnoPathIfMinus1_ "executeFile" path (c_execv s arr)+ return undefined -- never reached++executeFile path search args (Just env) = do+ withFilePath path $ \s ->+ withMany withFilePath (path:args) $ \cstrs ->+ withArray0 nullPtr cstrs $ \arg_arr ->+ let env' = map (\ (name, val) -> name `BC.append` ('=' `BC.cons` val)) env in+ withMany withFilePath env' $ \cenv ->+ withArray0 nullPtr cenv $ \env_arr -> do+ pPrPr_disableITimers+ if search + then throwErrnoPathIfMinus1_ "executeFile" path+ (c_execvpe s arg_arr env_arr)+ else throwErrnoPathIfMinus1_ "executeFile" path+ (c_execve s arg_arr env_arr)+ return undefined -- never reached++foreign import ccall unsafe "execvp"+ c_execvp :: CString -> Ptr CString -> IO CInt++foreign import ccall unsafe "execv"+ c_execv :: CString -> Ptr CString -> IO CInt++foreign import ccall unsafe "execve"+ c_execve :: CString -> Ptr CString -> Ptr CString -> IO CInt+
+ System/Posix/Process/Common.hsc view
@@ -0,0 +1,401 @@+{-# LANGUAGE ForeignFunctionInterface #-}+#if __GLASGOW_HASKELL__ >= 701+{-# LANGUAGE Trustworthy #-}+#endif+-----------------------------------------------------------------------------+-- |+-- Module : System.Posix.Process.Common+-- 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 process support. See also the System.Cmd and System.Process+-- modules in the process package.+--+-----------------------------------------------------------------------------++module System.Posix.Process.Common (+ -- * Processes++ -- ** Forking and executing+#ifdef __GLASGOW_HASKELL__+ forkProcess,+#endif++ -- ** Exiting+ exitImmediately,++ -- ** Process environment+ getProcessID,+ getParentProcessID,++ -- ** Process groups+ getProcessGroupID,+ getProcessGroupIDOf,+ createProcessGroupFor,+ joinProcessGroup,+ setProcessGroupIDOf,++ -- ** Sessions+ createSession,++ -- ** Process times+ ProcessTimes(..),+ getProcessTimes,++ -- ** Scheduling priority+ nice,+ getProcessPriority,+ getProcessGroupPriority,+ getUserPriority,+ setProcessPriority,+ setProcessGroupPriority,+ setUserPriority,++ -- ** Process status+ ProcessStatus(..),+ getProcessStatus,+ getAnyProcessStatus,+ getGroupProcessStatus,++ -- ** Deprecated+ createProcessGroup,+ setProcessGroupID,++ ) where++#include "HsUnix.h"++import Foreign.C.Error+import Foreign.C.Types+import Foreign.Marshal.Alloc ( alloca, allocaBytes )+import Foreign.Ptr ( Ptr )+import Foreign.StablePtr ( StablePtr, newStablePtr, freeStablePtr )+import Foreign.Storable ( Storable(..) )+import System.Exit+import System.Posix.Process.Internals+import System.Posix.Types+import Control.Monad++#ifdef __GLASGOW_HASKELL__+import GHC.TopHandler ( runIO )+#endif++#ifdef __HUGS__+{-# CFILES cbits/HsUnix.c #-}+#endif++-- -----------------------------------------------------------------------------+-- Process environment++-- | 'getProcessID' calls @getpid@ to obtain the 'ProcessID' for+-- the current process.+getProcessID :: IO ProcessID+getProcessID = c_getpid++foreign import ccall unsafe "getpid"+ c_getpid :: IO CPid++-- | 'getProcessID' calls @getppid@ to obtain the 'ProcessID' for+-- the parent of the current process.+getParentProcessID :: IO ProcessID+getParentProcessID = c_getppid++foreign import ccall unsafe "getppid"+ c_getppid :: IO CPid++-- | 'getProcessGroupID' calls @getpgrp@ to obtain the+-- 'ProcessGroupID' for the current process.+getProcessGroupID :: IO ProcessGroupID+getProcessGroupID = c_getpgrp++foreign import ccall unsafe "getpgrp"+ c_getpgrp :: IO CPid++-- | @'getProcessGroupIDOf' pid@ calls @getpgid@ to obtain the+-- 'ProcessGroupID' for process @pid@.+getProcessGroupIDOf :: ProcessID -> IO ProcessGroupID+getProcessGroupIDOf pid =+ throwErrnoIfMinus1 "getProcessGroupIDOf" (c_getpgid pid)++foreign import ccall unsafe "getpgid"+ c_getpgid :: CPid -> IO CPid++{-+ To be added in the future, after the deprecation period for the+ existing createProcessGroup has elapsed:++-- | 'createProcessGroup' calls @setpgid(0,0)@ to make+-- the current process a new process group leader.+createProcessGroup :: IO ProcessGroupID+createProcessGroup = do+ throwErrnoIfMinus1_ "createProcessGroup" (c_setpgid 0 0)+ pgid <- getProcessGroupID+ return pgid+-}++-- | @'createProcessGroupFor' pid@ calls @setpgid@ to make+-- process @pid@ a new process group leader.+createProcessGroupFor :: ProcessID -> IO ProcessGroupID+createProcessGroupFor pid = do+ throwErrnoIfMinus1_ "createProcessGroupFor" (c_setpgid pid 0)+ return pid++-- | @'joinProcessGroup' pgid@ calls @setpgid@ to set the+-- 'ProcessGroupID' of the current process to @pgid@.+joinProcessGroup :: ProcessGroupID -> IO ()+joinProcessGroup pgid =+ throwErrnoIfMinus1_ "joinProcessGroup" (c_setpgid 0 pgid)++{-+ To be added in the future, after the deprecation period for the+ existing setProcessGroupID has elapsed:++-- | @'setProcessGroupID' pgid@ calls @setpgid@ to set the+-- 'ProcessGroupID' of the current process to @pgid@.+setProcessGroupID :: ProcessGroupID -> IO ()+setProcessGroupID pgid =+ throwErrnoIfMinus1_ "setProcessGroupID" (c_setpgid 0 pgid)+-}++-- | @'setProcessGroupIDOf' pid pgid@ calls @setpgid@ to set the+-- 'ProcessGroupIDOf' for process @pid@ to @pgid@.+setProcessGroupIDOf :: ProcessID -> ProcessGroupID -> IO ()+setProcessGroupIDOf pid pgid =+ throwErrnoIfMinus1_ "setProcessGroupIDOf" (c_setpgid pid pgid)++foreign import ccall unsafe "setpgid"+ c_setpgid :: CPid -> CPid -> IO CInt++-- | 'createSession' calls @setsid@ to create a new session+-- with the current process as session leader.+createSession :: IO ProcessGroupID+createSession = throwErrnoIfMinus1 "createSession" c_setsid++foreign import ccall unsafe "setsid"+ c_setsid :: IO CPid++-- -----------------------------------------------------------------------------+-- Process times++-- All times in clock ticks (see getClockTick)++data ProcessTimes+ = ProcessTimes { elapsedTime :: ClockTick+ , userTime :: ClockTick+ , systemTime :: ClockTick+ , childUserTime :: ClockTick+ , childSystemTime :: ClockTick+ }++-- | 'getProcessTimes' calls @times@ to obtain time-accounting+-- information for the current process and its children.+getProcessTimes :: IO ProcessTimes+getProcessTimes = do+ allocaBytes (#const sizeof(struct tms)) $ \p_tms -> do+ elapsed <- throwErrnoIfMinus1 "getProcessTimes" (c_times p_tms)+ ut <- (#peek struct tms, tms_utime) p_tms+ st <- (#peek struct tms, tms_stime) p_tms+ cut <- (#peek struct tms, tms_cutime) p_tms+ cst <- (#peek struct tms, tms_cstime) p_tms+ return (ProcessTimes{ elapsedTime = elapsed,+ userTime = ut,+ systemTime = st,+ childUserTime = cut,+ childSystemTime = cst+ })++type CTms = ()++foreign import ccall unsafe "__hsunix_times"+ c_times :: Ptr CTms -> IO CClock++-- -----------------------------------------------------------------------------+-- Process scheduling priority++nice :: Int -> IO ()+nice prio = do+ resetErrno+ res <- c_nice (fromIntegral prio)+ when (res == -1) $ do+ err <- getErrno+ when (err /= eOK) (throwErrno "nice")++foreign import ccall unsafe "nice"+ c_nice :: CInt -> IO CInt++getProcessPriority :: ProcessID -> IO Int+getProcessGroupPriority :: ProcessGroupID -> IO Int+getUserPriority :: UserID -> IO Int++getProcessPriority pid = do+ r <- throwErrnoIfMinus1 "getProcessPriority" $+ c_getpriority (#const PRIO_PROCESS) (fromIntegral pid)+ return (fromIntegral r)++getProcessGroupPriority pid = do+ r <- throwErrnoIfMinus1 "getProcessPriority" $+ c_getpriority (#const PRIO_PGRP) (fromIntegral pid)+ return (fromIntegral r)++getUserPriority uid = do+ r <- throwErrnoIfMinus1 "getUserPriority" $+ c_getpriority (#const PRIO_USER) (fromIntegral uid)+ return (fromIntegral r)++foreign import ccall unsafe "getpriority"+ c_getpriority :: CInt -> CInt -> IO CInt++setProcessPriority :: ProcessID -> Int -> IO ()+setProcessGroupPriority :: ProcessGroupID -> Int -> IO ()+setUserPriority :: UserID -> Int -> IO ()++setProcessPriority pid val = + throwErrnoIfMinus1_ "setProcessPriority" $+ c_setpriority (#const PRIO_PROCESS) (fromIntegral pid) (fromIntegral val)++setProcessGroupPriority pid val =+ throwErrnoIfMinus1_ "setProcessPriority" $+ c_setpriority (#const PRIO_PGRP) (fromIntegral pid) (fromIntegral val)++setUserPriority uid val =+ throwErrnoIfMinus1_ "setUserPriority" $+ c_setpriority (#const PRIO_USER) (fromIntegral uid) (fromIntegral val)++foreign import ccall unsafe "setpriority"+ c_setpriority :: CInt -> CInt -> CInt -> IO CInt++-- -----------------------------------------------------------------------------+-- Forking, execution++#ifdef __GLASGOW_HASKELL__+{- | 'forkProcess' corresponds to the POSIX @fork@ system call.+The 'IO' action passed as an argument is executed in the child process; no other+threads will be copied to the child process.+On success, 'forkProcess' returns the child's 'ProcessID' to the parent process;+in case of an error, an exception is thrown.++'forkProcess' comes with a giant warning: since any other running+threads are not copied into the child process, it's easy to go wrong:+e.g. by accessing some shared resource that was held by another thread+in the parent.+-}++forkProcess :: IO () -> IO ProcessID+forkProcess action = do+ stable <- newStablePtr (runIO action)+ pid <- throwErrnoIfMinus1 "forkProcess" (forkProcessPrim stable)+ freeStablePtr stable+ return pid++foreign import ccall "forkProcess" forkProcessPrim :: StablePtr (IO ()) -> IO CPid+#endif /* __GLASGOW_HASKELL__ */++-- -----------------------------------------------------------------------------+-- Waiting for process termination++-- | @'getProcessStatus' blk stopped pid@ calls @waitpid@, returning+-- @'Just' tc@, the 'ProcessStatus' for process @pid@ if it is+-- available, 'Nothing' otherwise. If @blk@ is 'False', then+-- @WNOHANG@ is set in the options for @waitpid@, otherwise not.+-- If @stopped@ is 'True', then @WUNTRACED@ is set in the+-- options for @waitpid@, otherwise not.+getProcessStatus :: Bool -> Bool -> ProcessID -> IO (Maybe ProcessStatus)+getProcessStatus block stopped pid =+ alloca $ \wstatp -> do+ pid' <- throwErrnoIfMinus1Retry "getProcessStatus"+ (c_waitpid pid wstatp (waitOptions block stopped))+ case pid' of+ 0 -> return Nothing+ _ -> do ps <- readWaitStatus wstatp+ return (Just ps)++-- safe, because this call might block+foreign import ccall safe "waitpid"+ c_waitpid :: CPid -> Ptr CInt -> CInt -> IO CPid++-- | @'getGroupProcessStatus' blk stopped pgid@ calls @waitpid@,+-- returning @'Just' (pid, tc)@, the 'ProcessID' and+-- 'ProcessStatus' for any process in group @pgid@ if one is+-- available, 'Nothing' otherwise. If @blk@ is 'False', then+-- @WNOHANG@ is set in the options for @waitpid@, otherwise not.+-- If @stopped@ is 'True', then @WUNTRACED@ is set in the+-- options for @waitpid@, otherwise not.+getGroupProcessStatus :: Bool+ -> Bool+ -> ProcessGroupID+ -> IO (Maybe (ProcessID, ProcessStatus))+getGroupProcessStatus block stopped pgid =+ alloca $ \wstatp -> do+ pid <- throwErrnoIfMinus1Retry "getGroupProcessStatus"+ (c_waitpid (-pgid) wstatp (waitOptions block stopped))+ case pid of+ 0 -> return Nothing+ _ -> do ps <- readWaitStatus wstatp+ return (Just (pid, ps))+-- | @'getAnyProcessStatus' blk stopped@ calls @waitpid@, returning+-- @'Just' (pid, tc)@, the 'ProcessID' and 'ProcessStatus' for any+-- child process if one is available, 'Nothing' otherwise. If+-- @blk@ is 'False', then @WNOHANG@ is set in the options for+-- @waitpid@, otherwise not. If @stopped@ is 'True', then+-- @WUNTRACED@ is set in the options for @waitpid@, otherwise not.+getAnyProcessStatus :: Bool -> Bool -> IO (Maybe (ProcessID, ProcessStatus))+getAnyProcessStatus block stopped = getGroupProcessStatus block stopped 1++waitOptions :: Bool -> Bool -> CInt+-- block stopped+waitOptions False False = (#const WNOHANG)+waitOptions False True = (#const (WNOHANG|WUNTRACED))+waitOptions True False = 0+waitOptions True True = (#const WUNTRACED)++-- Turn a (ptr to a) wait status into a ProcessStatus++readWaitStatus :: Ptr CInt -> IO ProcessStatus+readWaitStatus wstatp = do+ wstat <- peek wstatp+ decipherWaitStatus wstat++-- -----------------------------------------------------------------------------+-- Exiting++-- | @'exitImmediately' status@ calls @_exit@ to terminate the process+-- with the indicated exit @status@.+-- The operation never returns.+exitImmediately :: ExitCode -> IO ()+exitImmediately exitcode = c_exit (exitcode2Int exitcode)+ where+ exitcode2Int ExitSuccess = 0+ exitcode2Int (ExitFailure n) = fromIntegral n++foreign import ccall unsafe "exit"+ c_exit :: CInt -> IO ()++-- -----------------------------------------------------------------------------+-- Deprecated or subject to change++{-# DEPRECATED createProcessGroup "This function is scheduled to be replaced by something different in the future, we therefore recommend that you do not use this version and use createProcessGroupFor instead." #-}+-- | @'createProcessGroup' pid@ calls @setpgid@ to make+-- process @pid@ a new process group leader.+-- This function is currently deprecated,+-- and might be changed to making the current+-- process a new process group leader in future versions.+createProcessGroup :: ProcessID -> IO ProcessGroupID+createProcessGroup pid = do+ throwErrnoIfMinus1_ "createProcessGroup" (c_setpgid pid 0)+ return pid++{-# DEPRECATED setProcessGroupID "This function is scheduled to be replaced by something different in the future, we therefore recommend that you do not use this version and use setProcessGroupIdOf instead." #-}+-- | @'setProcessGroupID' pid pgid@ calls @setpgid@ to set the+-- 'ProcessGroupID' for process @pid@ to @pgid@.+-- This function is currently deprecated,+-- and might be changed to setting the 'ProcessGroupID'+-- for the current process in future versions.+setProcessGroupID :: ProcessID -> ProcessGroupID -> IO ()+setProcessGroupID pid pgid =+ throwErrnoIfMinus1_ "setProcessGroupID" (c_setpgid pid pgid)++-- -----------------------------------------------------------------------------
System/Posix/Process/Internals.hs view
@@ -1,3 +1,6 @@+#if __GLASGOW_HASKELL__ >= 701+{-# LANGUAGE Trustworthy #-}+#endif module System.Posix.Process.Internals ( pPrPr_disableITimers, c_execvpe,
System/Posix/Resource.hsc view
@@ -1,5 +1,8 @@ {-# LANGUAGE ForeignFunctionInterface #-} {-# OPTIONS_GHC -w #-}+#if __GLASGOW_HASKELL__ >= 701+{-# LANGUAGE Trustworthy #-}+#endif -- The above warning supression flag is a temporary kludge. -- While working on this module you are encouraged to remove it and fix -- any warnings in the module. See
System/Posix/Semaphore.hsc view
@@ -1,5 +1,7 @@ {-# LANGUAGE ForeignFunctionInterface #-}-+#if __GLASGOW_HASKELL__ >= 701+{-# LANGUAGE Trustworthy #-}+#endif ----------------------------------------------------------------------------- -- | -- Module : System.Posix.Semaphore
@@ -1,6 +1,8 @@ {-# LANGUAGE ForeignFunctionInterface #-} {-# OPTIONS_GHC -fno-warn-unused-imports #-}-+#if __GLASGOW_HASKELL__ >= 701+{-# LANGUAGE Trustworthy #-}+#endif ----------------------------------------------------------------------------- -- | -- Module : System.Posix.SharedMem
System/Posix/Signals.hsc view
@@ -1,5 +1,8 @@-{-# LANGUAGE DeriveDataTypeable,PatternGuards #-}+{-# LANGUAGE DeriveDataTypeable, PatternGuards, CApiFFI #-} {-# OPTIONS_GHC -fno-cse #-} -- global variables+#if __GLASGOW_HASKELL__ >= 701+{-# LANGUAGE Trustworthy #-}+#endif ----------------------------------------------------------------------------- -- | -- Module : System.Posix.Signals@@ -296,7 +299,7 @@ raiseSignal :: Signal -> IO () raiseSignal sig = throwErrnoIfMinus1_ "raiseSignal" (c_raise sig) -#if defined(__GLASGOW_HASKELL__) && (defined(openbsd_HOST_OS) || defined(freebsd_HOST_OS) || defined(dragonfly_HOST_OS))+#if defined(__GLASGOW_HASKELL__) && (defined(openbsd_HOST_OS) || defined(freebsd_HOST_OS) || defined(dragonfly_HOST_OS)) || defined(netbsd_HOST_OS) foreign import ccall unsafe "genericRaise" c_raise :: CInt -> IO CInt #else@@ -594,7 +597,7 @@ -- (-1) with errno set to EINTR. -- XXX My manpage says it can also return EFAULT. And why is ignoring -- EINTR the right thing to do?- + foreign import ccall unsafe "sigsuspend" c_sigsuspend :: Ptr CSigset -> IO CInt #endif
System/Posix/Signals/Exts.hsc view
@@ -1,4 +1,7 @@ {-# LANGUAGE ForeignFunctionInterface #-}+#if __GLASGOW_HASKELL__ >= 701+{-# LANGUAGE Trustworthy #-}+#endif ----------------------------------------------------------------------------- -- | -- Module : System.Posix.Signals.Exts@@ -27,7 +30,7 @@ ) where -import Foreign.C ( CInt )+import Foreign.C import System.Posix.Signals #ifdef __HUGS__
System/Posix/Temp.hsc view
@@ -1,4 +1,7 @@ {-# LANGUAGE ForeignFunctionInterface #-}+#if __GLASGOW_HASKELL__ >= 701+{-# LANGUAGE Trustworthy #-}+#endif ----------------------------------------------------------------------------- -- | -- Module : System.Posix.Temp
+ System/Posix/Temp/ByteString.hsc view
@@ -0,0 +1,82 @@+{-# LANGUAGE ForeignFunctionInterface #-}+#if __GLASGOW_HASKELL__ >= 701+{-# LANGUAGE Trustworthy #-}+#endif+-----------------------------------------------------------------------------+-- |+-- Module : System.Posix.Temp.ByteString+-- Copyright : (c) Volker Stolz <vs@foldr.org>+-- License : BSD-style (see the file libraries/base/LICENSE)+--+-- Maintainer : vs@foldr.org+-- Stability : provisional+-- Portability : non-portable (requires POSIX)+--+-- POSIX environment support+--+-----------------------------------------------------------------------------++module System.Posix.Temp.ByteString (++ mkstemp++{- Not ported (yet?):+ tmpfile: can we handle FILE*?+ tmpnam: ISO C, should go in base?+ tempname: dito+-}++) where++#include "HsUnix.h"++import System.IO (Handle)+import System.Posix.IO+import System.Posix.Types++import Foreign.C hiding (+ throwErrnoPath,+ throwErrnoPathIf,+ throwErrnoPathIf_,+ throwErrnoPathIfNull,+ throwErrnoPathIfMinus1,+ throwErrnoPathIfMinus1_ )++import System.Posix.ByteString.FilePath++import Data.ByteString (ByteString)+++-- |'mkstemp' - make a unique filename and open it for+-- reading\/writing (only safe on GHC & Hugs).+-- The returned 'RawFilePath' is the (possibly relative) path of+-- the created file, which is padded with 6 random characters.+mkstemp :: ByteString -> IO (RawFilePath, Handle)+mkstemp template = do+#if defined(__GLASGOW_HASKELL__) || defined(__HUGS__)+ withFilePath template $ \ ptr -> do+ fd <- throwErrnoIfMinus1 "mkstemp" (c_mkstemp ptr)+ name <- peekFilePath ptr+ h <- fdToHandle (Fd fd)+ return (name, h)+#else+ name <- mktemp (template ++ "XXXXXX")+ h <- openFile name ReadWriteMode+ return (name, h)++-- |'mktemp' - make a unique file name+-- This function should be considered deprecated++mktemp :: ByteString -> IO RawFilePath+mktemp template = do+ withFilePath template $ \ ptr -> do+ ptr <- throwErrnoIfNull "mktemp" (c_mktemp ptr)+ peekFilePath ptr++foreign import ccall unsafe "mktemp"+ c_mktemp :: CString -> IO CString+#endif++foreign import ccall unsafe "HsUnix.h __hscore_mkstemp"+ c_mkstemp :: CString -> IO CInt+
System/Posix/Terminal.hsc view
@@ -1,5 +1,8 @@ {-# LANGUAGE ForeignFunctionInterface #-} {-# OPTIONS_GHC -fno-warn-unused-imports #-}+#if __GLASGOW_HASKELL__ >= 701+{-# LANGUAGE Trustworthy #-}+#endif ----------------------------------------------------------------------------- -- | -- Module : System.Posix.Terminal@@ -70,439 +73,32 @@ #include "HsUnix.h" -import Data.Bits-import Data.Char-import Foreign.C.Error ( errnoToIOError, throwErrnoIfMinus1,- throwErrnoIfMinus1_, throwErrnoIfNull )-#ifndef HAVE_PTSNAME-import Foreign.C.Error ( eNOSYS )-#endif-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 Foreign+import Foreign.C+import System.Posix.Terminal.Common 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 (#const BRKINT) termios-withoutMode termios MapCRtoLF = clearInputFlag (#const ICRNL) termios-withoutMode termios IgnoreBreak = clearInputFlag (#const IGNBRK) termios-withoutMode termios IgnoreCR = clearInputFlag (#const IGNCR) termios-withoutMode termios IgnoreParityErrors = clearInputFlag (#const IGNPAR) termios-withoutMode termios MapLFtoCR = clearInputFlag (#const INLCR) termios-withoutMode termios CheckParity = clearInputFlag (#const INPCK) termios-withoutMode termios StripHighBit = clearInputFlag (#const ISTRIP) termios-withoutMode termios StartStopInput = clearInputFlag (#const IXOFF) termios-withoutMode termios StartStopOutput = clearInputFlag (#const IXON) termios-withoutMode termios MarkParityErrors = clearInputFlag (#const PARMRK) termios-withoutMode termios ProcessOutput = clearOutputFlag (#const OPOST) termios-withoutMode termios LocalMode = clearControlFlag (#const CLOCAL) termios-withoutMode termios ReadEnable = clearControlFlag (#const CREAD) termios-withoutMode termios TwoStopBits = clearControlFlag (#const CSTOPB) termios-withoutMode termios HangupOnClose = clearControlFlag (#const HUPCL) termios-withoutMode termios EnableParity = clearControlFlag (#const PARENB) termios-withoutMode termios OddParity = clearControlFlag (#const PARODD) termios-withoutMode termios EnableEcho = clearLocalFlag (#const ECHO) termios-withoutMode termios EchoErase = clearLocalFlag (#const ECHOE) termios-withoutMode termios EchoKill = clearLocalFlag (#const ECHOK) termios-withoutMode termios EchoLF = clearLocalFlag (#const ECHONL) termios-withoutMode termios ProcessInput = clearLocalFlag (#const ICANON) termios-withoutMode termios ExtendedFunctions = clearLocalFlag (#const IEXTEN) termios-withoutMode termios KeyboardInterrupts = clearLocalFlag (#const ISIG) termios-withoutMode termios NoFlushOnInterrupt = setLocalFlag (#const NOFLSH) termios-withoutMode termios BackgroundWriteInterrupt = clearLocalFlag (#const TOSTOP) termios--withMode :: TerminalAttributes -> TerminalMode -> TerminalAttributes-withMode termios InterruptOnBreak = setInputFlag (#const BRKINT) termios-withMode termios MapCRtoLF = setInputFlag (#const ICRNL) termios-withMode termios IgnoreBreak = setInputFlag (#const IGNBRK) termios-withMode termios IgnoreCR = setInputFlag (#const IGNCR) termios-withMode termios IgnoreParityErrors = setInputFlag (#const IGNPAR) termios-withMode termios MapLFtoCR = setInputFlag (#const INLCR) termios-withMode termios CheckParity = setInputFlag (#const INPCK) termios-withMode termios StripHighBit = setInputFlag (#const ISTRIP) termios-withMode termios StartStopInput = setInputFlag (#const IXOFF) termios-withMode termios StartStopOutput = setInputFlag (#const IXON) termios-withMode termios MarkParityErrors = setInputFlag (#const PARMRK) termios-withMode termios ProcessOutput = setOutputFlag (#const OPOST) termios-withMode termios LocalMode = setControlFlag (#const CLOCAL) termios-withMode termios ReadEnable = setControlFlag (#const CREAD) termios-withMode termios TwoStopBits = setControlFlag (#const CSTOPB) termios-withMode termios HangupOnClose = setControlFlag (#const HUPCL) termios-withMode termios EnableParity = setControlFlag (#const PARENB) termios-withMode termios OddParity = setControlFlag (#const PARODD) termios-withMode termios EnableEcho = setLocalFlag (#const ECHO) termios-withMode termios EchoErase = setLocalFlag (#const ECHOE) termios-withMode termios EchoKill = setLocalFlag (#const ECHOK) termios-withMode termios EchoLF = setLocalFlag (#const ECHONL) termios-withMode termios ProcessInput = setLocalFlag (#const ICANON) termios-withMode termios ExtendedFunctions = setLocalFlag (#const IEXTEN) termios-withMode termios KeyboardInterrupts = setLocalFlag (#const ISIG) termios-withMode termios NoFlushOnInterrupt = clearLocalFlag (#const NOFLSH) termios-withMode termios BackgroundWriteInterrupt = setLocalFlag (#const TOSTOP) termios--terminalMode :: TerminalMode -> TerminalAttributes -> Bool-terminalMode InterruptOnBreak = testInputFlag (#const BRKINT)-terminalMode MapCRtoLF = testInputFlag (#const ICRNL)-terminalMode IgnoreBreak = testInputFlag (#const IGNBRK)-terminalMode IgnoreCR = testInputFlag (#const IGNCR)-terminalMode IgnoreParityErrors = testInputFlag (#const IGNPAR)-terminalMode MapLFtoCR = testInputFlag (#const INLCR)-terminalMode CheckParity = testInputFlag (#const INPCK)-terminalMode StripHighBit = testInputFlag (#const ISTRIP)-terminalMode StartStopInput = testInputFlag (#const IXOFF)-terminalMode StartStopOutput = testInputFlag (#const IXON)-terminalMode MarkParityErrors = testInputFlag (#const PARMRK)-terminalMode ProcessOutput = testOutputFlag (#const OPOST)-terminalMode LocalMode = testControlFlag (#const CLOCAL)-terminalMode ReadEnable = testControlFlag (#const CREAD)-terminalMode TwoStopBits = testControlFlag (#const CSTOPB)-terminalMode HangupOnClose = testControlFlag (#const HUPCL)-terminalMode EnableParity = testControlFlag (#const PARENB)-terminalMode OddParity = testControlFlag (#const PARODD)-terminalMode EnableEcho = testLocalFlag (#const ECHO)-terminalMode EchoErase = testLocalFlag (#const ECHOE)-terminalMode EchoKill = testLocalFlag (#const ECHOK)-terminalMode EchoLF = testLocalFlag (#const ECHONL)-terminalMode ProcessInput = testLocalFlag (#const ICANON)-terminalMode ExtendedFunctions = testLocalFlag (#const IEXTEN)-terminalMode KeyboardInterrupts = testLocalFlag (#const ISIG)-terminalMode NoFlushOnInterrupt = not . testLocalFlag (#const NOFLSH)-terminalMode BackgroundWriteInterrupt = testLocalFlag (#const TOSTOP)--bitsPerByte :: TerminalAttributes -> Int-bitsPerByte termios = unsafePerformIO $ do- withTerminalAttributes termios $ \p -> do- cflag <- (#peek struct termios, c_cflag) p- return $! (word2Bits (cflag .&. (#const CSIZE)))- where- word2Bits :: CTcflag -> Int- word2Bits x =- if x == (#const CS5) then 5- else if x == (#const CS6) then 6- else if x == (#const CS7) then 7- else if x == (#const CS8) then 8- else 0--withBits :: TerminalAttributes -> Int -> TerminalAttributes-withBits termios bits = unsafePerformIO $ do- withNewTermios termios $ \p -> do- cflag <- (#peek struct termios, c_cflag) p- (#poke struct termios, c_cflag) p- ((cflag .&. complement (#const CSIZE)) .|. mask bits)- where- mask :: Int -> CTcflag- mask 5 = (#const CS5)- mask 6 = (#const CS6)- mask 7 = (#const CS7)- mask 8 = (#const CS8)- 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 = (#ptr struct termios, c_cc) p- val <- peekElemOff c_cc (cc2Word cc)- if val == ((#const _POSIX_VDISABLE)::CCc)- 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 = (#ptr struct termios, c_cc) p- 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 = (#ptr struct termios, c_cc) p- pokeElemOff c_cc (cc2Word cc) ((#const _POSIX_VDISABLE) :: CCc)--inputTime :: TerminalAttributes -> Int-inputTime termios = unsafePerformIO $ do- withTerminalAttributes termios $ \p -> do- c <- peekElemOff ((#ptr struct termios, c_cc) p) (#const VTIME)- return (fromEnum (c :: CCc))--withTime :: TerminalAttributes -> Int -> TerminalAttributes-withTime termios time = unsafePerformIO $ do- withNewTermios termios $ \p -> do- let c_cc = (#ptr struct termios, c_cc) p- pokeElemOff c_cc (#const VTIME) (fromIntegral time :: CCc)--minInput :: TerminalAttributes -> Int-minInput termios = unsafePerformIO $ do- withTerminalAttributes termios $ \p -> do- c <- peekElemOff ((#ptr struct termios, c_cc) p) (#const VMIN)- return (fromEnum (c :: CCc))--withMinInput :: TerminalAttributes -> Int -> TerminalAttributes-withMinInput termios count = unsafePerformIO $ do- withNewTermios termios $ \p -> do- let c_cc = (#ptr struct termios, c_cc) p- pokeElemOff c_cc (#const VMIN) (fromIntegral count :: CCc)--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 (#const sizeof(struct termios))- 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 = (#const TCSANOW)- state2Int WhenDrained = (#const TCSADRAIN)- state2Int WhenFlushed = (#const TCSAFLUSH)--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 = (#const TCIFLUSH)- queue2Int OutputQueue = (#const TCOFLUSH)- queue2Int BothQueues = (#const TCIOFLUSH)--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 = (#const TCOOFF)- action2Int RestartOutput = (#const TCOON)- action2Int TransmitStop = (#const TCIOFF)- action2Int TransmitStart = (#const TCION)--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+import System.Posix.IO --- | @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)+#if __GLASGOW_HASKELL__ > 700+import System.Posix.Internals (withFilePath, peekFilePath)+#elif __GLASGOW_HASKELL__ > 611+import System.Posix.Internals (withFilePath) -foreign import ccall unsafe "tcsetpgrp"- c_tcsetpgrp :: CInt -> CPid -> IO CInt+peekFilePath :: CString -> IO FilePath+peekFilePath = peekCString --- -------------------------------------------------------------------------------- file descriptor queries+peekFilePathLen :: CStringLen -> IO FilePath+peekFilePathLen = peekCStringLen+#else+withFilePath :: FilePath -> (CString -> IO a) -> IO a+withFilePath = withCString --- | @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+peekFilePath :: CString -> IO FilePath+peekFilePath = peekCString -foreign import ccall unsafe "isatty"- c_isatty :: CInt -> IO CInt+peekFilePathLen :: CStringLen -> IO FilePath+peekFilePathLen = peekCStringLen+#endif -- | @getTerminalName fd@ calls @ttyname@ to obtain a name associated -- with the terminal for @Fd@ @fd@. If @fd@ is associated@@ -511,7 +107,7 @@ getTerminalName :: Fd -> IO FilePath getTerminalName (Fd fd) = do s <- throwErrnoIfNull "getTerminalName" (c_ttyname fd)- peekCString s + peekFilePath s foreign import ccall unsafe "ttyname" c_ttyname :: CInt -> IO CString@@ -524,7 +120,7 @@ getControllingTerminalName :: IO FilePath getControllingTerminalName = do s <- throwErrnoIfNull "getControllingTerminalName" (c_ctermid nullPtr)- peekCString s+ peekFilePath s foreign import ccall unsafe "ctermid" c_ctermid :: CString -> IO CString@@ -537,7 +133,7 @@ #ifdef HAVE_PTSNAME getSlaveTerminalName (Fd fd) = do s <- throwErrnoIfNull "getSlaveTerminalName" (c_ptsname fd)- peekCString s+ peekFilePath s foreign import ccall unsafe "__hsunix_ptsname" c_ptsname :: CInt -> IO CString@@ -546,6 +142,10 @@ ioError (errnoToIOError "getSlaveTerminalName" eNOSYS Nothing Nothing) #endif +-- -----------------------------------------------------------------------------+-- openPseudoTerminal needs to be here because it depends on+-- getSlaveTerminalName.+ -- | @openPseudoTerminal@ creates a pseudoterminal (pty) pair, and -- returns the newly created pair as a (@master@, @slave@) tuple. openPseudoTerminal :: IO (Fd, Fd)@@ -603,204 +203,3 @@ #endif /* HAVE_PTSNAME */ #endif /* !HAVE_OPENPTY */ --- -------------------------------------------------------------------------------- Local utility functions---- Convert Haskell ControlCharacter to Int--cc2Word :: ControlCharacter -> Int-cc2Word EndOfFile = (#const VEOF)-cc2Word EndOfLine = (#const VEOL)-cc2Word Erase = (#const VERASE)-cc2Word Interrupt = (#const VINTR)-cc2Word Kill = (#const VKILL)-cc2Word Quit = (#const VQUIT)-cc2Word Suspend = (#const VSUSP)-cc2Word Start = (#const VSTART)-cc2Word Stop = (#const VSTOP)---- Convert Haskell BaudRate to unsigned integral type (Word)--baud2Word :: BaudRate -> CSpeed-baud2Word B0 = (#const B0)-baud2Word B50 = (#const B50)-baud2Word B75 = (#const B75)-baud2Word B110 = (#const B110)-baud2Word B134 = (#const B134)-baud2Word B150 = (#const B150)-baud2Word B200 = (#const B200)-baud2Word B300 = (#const B300)-baud2Word B600 = (#const B600)-baud2Word B1200 = (#const B1200)-baud2Word B1800 = (#const B1800)-baud2Word B2400 = (#const B2400)-baud2Word B4800 = (#const B4800)-baud2Word B9600 = (#const B9600)-baud2Word B19200 = (#const B19200)-baud2Word B38400 = (#const B38400)-baud2Word B57600 = (#const B57600)-baud2Word B115200 = (#const B115200)---- And convert a word back to a baud rate--- We really need some cpp macros here.--word2Baud :: CSpeed -> BaudRate-word2Baud x =- if x == (#const B0) then B0- else if x == (#const B50) then B50- else if x == (#const B75) then B75- else if x == (#const B110) then B110- else if x == (#const B134) then B134- else if x == (#const B150) then B150- else if x == (#const B200) then B200- else if x == (#const B300) then B300- else if x == (#const B600) then B600- else if x == (#const B1200) then B1200- else if x == (#const B1800) then B1800- else if x == (#const B2400) then B2400- else if x == (#const B4800) then B4800- else if x == (#const B9600) then B9600- else if x == (#const B19200) then B19200- else if x == (#const B38400) then B38400- else if x == (#const B57600) then B57600- else if x == (#const B115200) then B115200- else error "unknown baud rate"---- Clear termios i_flag--clearInputFlag :: CTcflag -> TerminalAttributes -> TerminalAttributes-clearInputFlag flag termios = unsafePerformIO $ do- fp <- mallocForeignPtrBytes (#const sizeof(struct termios))- withForeignPtr fp $ \p1 -> do- withTerminalAttributes termios $ \p2 -> do- copyBytes p1 p2 (#const sizeof(struct termios)) - iflag <- (#peek struct termios, c_iflag) p2- (#poke struct termios, c_iflag) p1 (iflag .&. complement flag)- return $ makeTerminalAttributes fp---- Set termios i_flag--setInputFlag :: CTcflag -> TerminalAttributes -> TerminalAttributes-setInputFlag flag termios = unsafePerformIO $ do- fp <- mallocForeignPtrBytes (#const sizeof(struct termios))- withForeignPtr fp $ \p1 -> do- withTerminalAttributes termios $ \p2 -> do- copyBytes p1 p2 (#const sizeof(struct termios)) - iflag <- (#peek struct termios, c_iflag) p2- (#poke struct termios, c_iflag) p1 (iflag .|. flag)- return $ makeTerminalAttributes fp---- Examine termios i_flag--testInputFlag :: CTcflag -> TerminalAttributes -> Bool-testInputFlag flag termios = unsafePerformIO $- withTerminalAttributes termios $ \p -> do- iflag <- (#peek struct termios, c_iflag) p- return $! ((iflag .&. flag) /= 0)---- Clear termios c_flag--clearControlFlag :: CTcflag -> TerminalAttributes -> TerminalAttributes-clearControlFlag flag termios = unsafePerformIO $ do- fp <- mallocForeignPtrBytes (#const sizeof(struct termios))- withForeignPtr fp $ \p1 -> do- withTerminalAttributes termios $ \p2 -> do- copyBytes p1 p2 (#const sizeof(struct termios)) - cflag <- (#peek struct termios, c_cflag) p2- (#poke struct termios, c_cflag) p1 (cflag .&. complement flag)- return $ makeTerminalAttributes fp---- Set termios c_flag--setControlFlag :: CTcflag -> TerminalAttributes -> TerminalAttributes-setControlFlag flag termios = unsafePerformIO $ do- fp <- mallocForeignPtrBytes (#const sizeof(struct termios))- withForeignPtr fp $ \p1 -> do- withTerminalAttributes termios $ \p2 -> do- copyBytes p1 p2 (#const sizeof(struct termios)) - cflag <- (#peek struct termios, c_cflag) p2- (#poke struct termios, c_cflag) p1 (cflag .|. flag)- return $ makeTerminalAttributes fp---- Examine termios c_flag--testControlFlag :: CTcflag -> TerminalAttributes -> Bool-testControlFlag flag termios = unsafePerformIO $- withTerminalAttributes termios $ \p -> do- cflag <- (#peek struct termios, c_cflag) p- return $! ((cflag .&. flag) /= 0)---- Clear termios l_flag--clearLocalFlag :: CTcflag -> TerminalAttributes -> TerminalAttributes-clearLocalFlag flag termios = unsafePerformIO $ do- fp <- mallocForeignPtrBytes (#const sizeof(struct termios))- withForeignPtr fp $ \p1 -> do- withTerminalAttributes termios $ \p2 -> do- copyBytes p1 p2 (#const sizeof(struct termios)) - lflag <- (#peek struct termios, c_lflag) p2- (#poke struct termios, c_lflag) p1 (lflag .&. complement flag)- return $ makeTerminalAttributes fp---- Set termios l_flag--setLocalFlag :: CTcflag -> TerminalAttributes -> TerminalAttributes-setLocalFlag flag termios = unsafePerformIO $ do- fp <- mallocForeignPtrBytes (#const sizeof(struct termios))- withForeignPtr fp $ \p1 -> do- withTerminalAttributes termios $ \p2 -> do- copyBytes p1 p2 (#const sizeof(struct termios)) - lflag <- (#peek struct termios, c_lflag) p2- (#poke struct termios, c_lflag) p1 (lflag .|. flag)- return $ makeTerminalAttributes fp---- Examine termios l_flag--testLocalFlag :: CTcflag -> TerminalAttributes -> Bool-testLocalFlag flag termios = unsafePerformIO $- withTerminalAttributes termios $ \p -> do- lflag <- (#peek struct termios, c_lflag) p- return $! ((lflag .&. flag) /= 0)---- Clear termios o_flag--clearOutputFlag :: CTcflag -> TerminalAttributes -> TerminalAttributes-clearOutputFlag flag termios = unsafePerformIO $ do- fp <- mallocForeignPtrBytes (#const sizeof(struct termios))- withForeignPtr fp $ \p1 -> do- withTerminalAttributes termios $ \p2 -> do- copyBytes p1 p2 (#const sizeof(struct termios)) - oflag <- (#peek struct termios, c_oflag) p2- (#poke struct termios, c_oflag) p1 (oflag .&. complement flag)- return $ makeTerminalAttributes fp---- Set termios o_flag--setOutputFlag :: CTcflag -> TerminalAttributes -> TerminalAttributes-setOutputFlag flag termios = unsafePerformIO $ do- fp <- mallocForeignPtrBytes (#const sizeof(struct termios))- withForeignPtr fp $ \p1 -> do- withTerminalAttributes termios $ \p2 -> do- copyBytes p1 p2 (#const sizeof(struct termios)) - oflag <- (#peek struct termios, c_oflag) p2- (#poke struct termios, c_oflag) p1 (oflag .|. flag)- return $ makeTerminalAttributes fp---- Examine termios o_flag--testOutputFlag :: CTcflag -> TerminalAttributes -> Bool-testOutputFlag flag termios = unsafePerformIO $- withTerminalAttributes termios $ \p -> do- oflag <- (#peek struct termios, c_oflag) p- return $! ((oflag .&. flag) /= 0)--withNewTermios :: TerminalAttributes -> (Ptr CTermios -> IO a) - -> IO TerminalAttributes-withNewTermios termios action = do- fp1 <- mallocForeignPtrBytes (#const sizeof(struct termios))- withForeignPtr fp1 $ \p1 -> do- withTerminalAttributes termios $ \p2 -> do- copyBytes p1 p2 (#const sizeof(struct termios))- _ <- action p1- return ()- return $ makeTerminalAttributes fp1
+ System/Posix/Terminal/ByteString.hsc view
@@ -0,0 +1,194 @@+{-# LANGUAGE ForeignFunctionInterface #-}+{-# OPTIONS_GHC -fno-warn-unused-imports #-}+#if __GLASGOW_HASKELL__ >= 701+{-# LANGUAGE Trustworthy #-}+#endif+-----------------------------------------------------------------------------+-- |+-- Module : System.Posix.Terminal.ByteString+-- 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.ByteString (+ -- * 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++#include "HsUnix.h"++import Foreign+import System.Posix.Types+import System.Posix.Terminal.Common+import System.Posix.IO.ByteString+import Data.ByteString.Char8 as B++import Foreign.C hiding (+ throwErrnoPath,+ throwErrnoPathIf,+ throwErrnoPathIf_,+ throwErrnoPathIfNull,+ throwErrnoPathIfMinus1,+ throwErrnoPathIfMinus1_ )++import System.Posix.ByteString.FilePath+++-- | @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 RawFilePath+getTerminalName (Fd fd) = do+ s <- throwErrnoIfNull "getTerminalName" (c_ttyname fd)+ peekFilePath 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 RawFilePath+getControllingTerminalName = do+ s <- throwErrnoIfNull "getControllingTerminalName" (c_ctermid nullPtr)+ peekFilePath 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 RawFilePath++#ifdef HAVE_PTSNAME+getSlaveTerminalName (Fd fd) = do+ s <- throwErrnoIfNull "getSlaveTerminalName" (c_ptsname fd)+ peekFilePath s++foreign import ccall unsafe "__hsunix_ptsname"+ c_ptsname :: CInt -> IO CString+#else+getSlaveTerminalName _ =+ ioError (errnoToIOError "getSlaveTerminalName" eNOSYS Nothing Nothing)+#endif++-- -----------------------------------------------------------------------------+-- openPseudoTerminal needs to be here because it depends on+-- getSlaveTerminalName.++-- | @openPseudoTerminal@ creates a pseudoterminal (pty) pair, and+-- returns the newly created pair as a (@master@, @slave@) tuple.+openPseudoTerminal :: IO (Fd, Fd)++#ifdef HAVE_OPENPTY+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+#else+openPseudoTerminal = do+ (Fd master) <- openFd (B.pack "/dev/ptmx") ReadWrite Nothing+ defaultFileFlags{noctty=True}+ throwErrnoIfMinus1_ "openPseudoTerminal" (c_grantpt master)+ throwErrnoIfMinus1_ "openPseudoTerminal" (c_unlockpt master)+ slaveName <- getSlaveTerminalName (Fd master)+ slave <- openFd slaveName ReadWrite Nothing defaultFileFlags{noctty=True}+ pushModule slave "ptem"+ pushModule slave "ldterm"+# ifndef __hpux+ pushModule slave "ttcompat"+# endif /* __hpux */+ return (Fd master, slave)++-- Push a STREAMS module, for System V systems.+pushModule :: Fd -> String -> IO ()+pushModule (Fd fd) name =+ withCString name $ \p_name ->+ throwErrnoIfMinus1_ "openPseudoTerminal"+ (c_push_module fd p_name)++foreign import ccall unsafe "__hsunix_push_module"+ c_push_module :: CInt -> CString -> IO CInt++#ifdef HAVE_PTSNAME+foreign import ccall unsafe "__hsunix_grantpt"+ c_grantpt :: CInt -> IO CInt++foreign import ccall unsafe "__hsunix_unlockpt"+ c_unlockpt :: CInt -> IO CInt+#else+c_grantpt :: CInt -> IO CInt+c_grantpt _ = return (fromIntegral 0)++c_unlockpt :: CInt -> IO CInt+c_unlockpt _ = return (fromIntegral 0)+#endif /* HAVE_PTSNAME */+#endif /* !HAVE_OPENPTY */
+ System/Posix/Terminal/Common.hsc view
@@ -0,0 +1,705 @@+{-# LANGUAGE ForeignFunctionInterface #-}+{-# OPTIONS_GHC -fno-warn-unused-imports #-}+#if __GLASGOW_HASKELL__ >= 701+{-# LANGUAGE Trustworthy #-}+#endif+-----------------------------------------------------------------------------+-- |+-- Module : System.Posix.Terminal.Common+-- 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.Common (+ -- * Terminal support++ -- ** Terminal attributes+ TerminalAttributes,+ getTerminalAttributes,+ TerminalState(..),+ setTerminalAttributes,++ CTermios,+ 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,+ ) where++#include "HsUnix.h"++import Data.Bits+import Data.Char+import Foreign.C.Error ( errnoToIOError, throwErrnoIfMinus1,+ throwErrnoIfMinus1_, throwErrnoIfNull )+#ifndef HAVE_PTSNAME+import Foreign.C.Error ( eNOSYS )+#endif+import Foreign.C.String ( CString, peekCString, withCString )+import Foreign.C.Types+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 (#const BRKINT) termios+withoutMode termios MapCRtoLF = clearInputFlag (#const ICRNL) termios+withoutMode termios IgnoreBreak = clearInputFlag (#const IGNBRK) termios+withoutMode termios IgnoreCR = clearInputFlag (#const IGNCR) termios+withoutMode termios IgnoreParityErrors = clearInputFlag (#const IGNPAR) termios+withoutMode termios MapLFtoCR = clearInputFlag (#const INLCR) termios+withoutMode termios CheckParity = clearInputFlag (#const INPCK) termios+withoutMode termios StripHighBit = clearInputFlag (#const ISTRIP) termios+withoutMode termios StartStopInput = clearInputFlag (#const IXOFF) termios+withoutMode termios StartStopOutput = clearInputFlag (#const IXON) termios+withoutMode termios MarkParityErrors = clearInputFlag (#const PARMRK) termios+withoutMode termios ProcessOutput = clearOutputFlag (#const OPOST) termios+withoutMode termios LocalMode = clearControlFlag (#const CLOCAL) termios+withoutMode termios ReadEnable = clearControlFlag (#const CREAD) termios+withoutMode termios TwoStopBits = clearControlFlag (#const CSTOPB) termios+withoutMode termios HangupOnClose = clearControlFlag (#const HUPCL) termios+withoutMode termios EnableParity = clearControlFlag (#const PARENB) termios+withoutMode termios OddParity = clearControlFlag (#const PARODD) termios+withoutMode termios EnableEcho = clearLocalFlag (#const ECHO) termios+withoutMode termios EchoErase = clearLocalFlag (#const ECHOE) termios+withoutMode termios EchoKill = clearLocalFlag (#const ECHOK) termios+withoutMode termios EchoLF = clearLocalFlag (#const ECHONL) termios+withoutMode termios ProcessInput = clearLocalFlag (#const ICANON) termios+withoutMode termios ExtendedFunctions = clearLocalFlag (#const IEXTEN) termios+withoutMode termios KeyboardInterrupts = clearLocalFlag (#const ISIG) termios+withoutMode termios NoFlushOnInterrupt = setLocalFlag (#const NOFLSH) termios+withoutMode termios BackgroundWriteInterrupt = clearLocalFlag (#const TOSTOP) termios++withMode :: TerminalAttributes -> TerminalMode -> TerminalAttributes+withMode termios InterruptOnBreak = setInputFlag (#const BRKINT) termios+withMode termios MapCRtoLF = setInputFlag (#const ICRNL) termios+withMode termios IgnoreBreak = setInputFlag (#const IGNBRK) termios+withMode termios IgnoreCR = setInputFlag (#const IGNCR) termios+withMode termios IgnoreParityErrors = setInputFlag (#const IGNPAR) termios+withMode termios MapLFtoCR = setInputFlag (#const INLCR) termios+withMode termios CheckParity = setInputFlag (#const INPCK) termios+withMode termios StripHighBit = setInputFlag (#const ISTRIP) termios+withMode termios StartStopInput = setInputFlag (#const IXOFF) termios+withMode termios StartStopOutput = setInputFlag (#const IXON) termios+withMode termios MarkParityErrors = setInputFlag (#const PARMRK) termios+withMode termios ProcessOutput = setOutputFlag (#const OPOST) termios+withMode termios LocalMode = setControlFlag (#const CLOCAL) termios+withMode termios ReadEnable = setControlFlag (#const CREAD) termios+withMode termios TwoStopBits = setControlFlag (#const CSTOPB) termios+withMode termios HangupOnClose = setControlFlag (#const HUPCL) termios+withMode termios EnableParity = setControlFlag (#const PARENB) termios+withMode termios OddParity = setControlFlag (#const PARODD) termios+withMode termios EnableEcho = setLocalFlag (#const ECHO) termios+withMode termios EchoErase = setLocalFlag (#const ECHOE) termios+withMode termios EchoKill = setLocalFlag (#const ECHOK) termios+withMode termios EchoLF = setLocalFlag (#const ECHONL) termios+withMode termios ProcessInput = setLocalFlag (#const ICANON) termios+withMode termios ExtendedFunctions = setLocalFlag (#const IEXTEN) termios+withMode termios KeyboardInterrupts = setLocalFlag (#const ISIG) termios+withMode termios NoFlushOnInterrupt = clearLocalFlag (#const NOFLSH) termios+withMode termios BackgroundWriteInterrupt = setLocalFlag (#const TOSTOP) termios++terminalMode :: TerminalMode -> TerminalAttributes -> Bool+terminalMode InterruptOnBreak = testInputFlag (#const BRKINT)+terminalMode MapCRtoLF = testInputFlag (#const ICRNL)+terminalMode IgnoreBreak = testInputFlag (#const IGNBRK)+terminalMode IgnoreCR = testInputFlag (#const IGNCR)+terminalMode IgnoreParityErrors = testInputFlag (#const IGNPAR)+terminalMode MapLFtoCR = testInputFlag (#const INLCR)+terminalMode CheckParity = testInputFlag (#const INPCK)+terminalMode StripHighBit = testInputFlag (#const ISTRIP)+terminalMode StartStopInput = testInputFlag (#const IXOFF)+terminalMode StartStopOutput = testInputFlag (#const IXON)+terminalMode MarkParityErrors = testInputFlag (#const PARMRK)+terminalMode ProcessOutput = testOutputFlag (#const OPOST)+terminalMode LocalMode = testControlFlag (#const CLOCAL)+terminalMode ReadEnable = testControlFlag (#const CREAD)+terminalMode TwoStopBits = testControlFlag (#const CSTOPB)+terminalMode HangupOnClose = testControlFlag (#const HUPCL)+terminalMode EnableParity = testControlFlag (#const PARENB)+terminalMode OddParity = testControlFlag (#const PARODD)+terminalMode EnableEcho = testLocalFlag (#const ECHO)+terminalMode EchoErase = testLocalFlag (#const ECHOE)+terminalMode EchoKill = testLocalFlag (#const ECHOK)+terminalMode EchoLF = testLocalFlag (#const ECHONL)+terminalMode ProcessInput = testLocalFlag (#const ICANON)+terminalMode ExtendedFunctions = testLocalFlag (#const IEXTEN)+terminalMode KeyboardInterrupts = testLocalFlag (#const ISIG)+terminalMode NoFlushOnInterrupt = not . testLocalFlag (#const NOFLSH)+terminalMode BackgroundWriteInterrupt = testLocalFlag (#const TOSTOP)++bitsPerByte :: TerminalAttributes -> Int+bitsPerByte termios = unsafePerformIO $ do+ withTerminalAttributes termios $ \p -> do+ cflag <- (#peek struct termios, c_cflag) p+ return $! (word2Bits (cflag .&. (#const CSIZE)))+ where+ word2Bits :: CTcflag -> Int+ word2Bits x =+ if x == (#const CS5) then 5+ else if x == (#const CS6) then 6+ else if x == (#const CS7) then 7+ else if x == (#const CS8) then 8+ else 0++withBits :: TerminalAttributes -> Int -> TerminalAttributes+withBits termios bits = unsafePerformIO $ do+ withNewTermios termios $ \p -> do+ cflag <- (#peek struct termios, c_cflag) p+ (#poke struct termios, c_cflag) p+ ((cflag .&. complement (#const CSIZE)) .|. mask bits)+ where+ mask :: Int -> CTcflag+ mask 5 = (#const CS5)+ mask 6 = (#const CS6)+ mask 7 = (#const CS7)+ mask 8 = (#const CS8)+ 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 = (#ptr struct termios, c_cc) p+ val <- peekElemOff c_cc (cc2Word cc)+ if val == ((#const _POSIX_VDISABLE)::CCc)+ 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 = (#ptr struct termios, c_cc) p+ 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 = (#ptr struct termios, c_cc) p+ pokeElemOff c_cc (cc2Word cc) ((#const _POSIX_VDISABLE) :: CCc)++inputTime :: TerminalAttributes -> Int+inputTime termios = unsafePerformIO $ do+ withTerminalAttributes termios $ \p -> do+ c <- peekElemOff ((#ptr struct termios, c_cc) p) (#const VTIME)+ return (fromEnum (c :: CCc))++withTime :: TerminalAttributes -> Int -> TerminalAttributes+withTime termios time = unsafePerformIO $ do+ withNewTermios termios $ \p -> do+ let c_cc = (#ptr struct termios, c_cc) p+ pokeElemOff c_cc (#const VTIME) (fromIntegral time :: CCc)++minInput :: TerminalAttributes -> Int+minInput termios = unsafePerformIO $ do+ withTerminalAttributes termios $ \p -> do+ c <- peekElemOff ((#ptr struct termios, c_cc) p) (#const VMIN)+ return (fromEnum (c :: CCc))++withMinInput :: TerminalAttributes -> Int -> TerminalAttributes+withMinInput termios count = unsafePerformIO $ do+ withNewTermios termios $ \p -> do+ let c_cc = (#ptr struct termios, c_cc) p+ pokeElemOff c_cc (#const VMIN) (fromIntegral count :: CCc)++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 (#const sizeof(struct termios))+ 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 = (#const TCSANOW)+ state2Int WhenDrained = (#const TCSADRAIN)+ state2Int WhenFlushed = (#const TCSAFLUSH)++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 = (#const TCIFLUSH)+ queue2Int OutputQueue = (#const TCOFLUSH)+ queue2Int BothQueues = (#const TCIOFLUSH)++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 = (#const TCOOFF)+ action2Int RestartOutput = (#const TCOON)+ action2Int TransmitStop = (#const TCIOFF)+ action2Int TransmitStart = (#const TCION)++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++-- -----------------------------------------------------------------------------+-- Local utility functions++-- Convert Haskell ControlCharacter to Int++cc2Word :: ControlCharacter -> Int+cc2Word EndOfFile = (#const VEOF)+cc2Word EndOfLine = (#const VEOL)+cc2Word Erase = (#const VERASE)+cc2Word Interrupt = (#const VINTR)+cc2Word Kill = (#const VKILL)+cc2Word Quit = (#const VQUIT)+cc2Word Suspend = (#const VSUSP)+cc2Word Start = (#const VSTART)+cc2Word Stop = (#const VSTOP)++-- Convert Haskell BaudRate to unsigned integral type (Word)++baud2Word :: BaudRate -> CSpeed+baud2Word B0 = (#const B0)+baud2Word B50 = (#const B50)+baud2Word B75 = (#const B75)+baud2Word B110 = (#const B110)+baud2Word B134 = (#const B134)+baud2Word B150 = (#const B150)+baud2Word B200 = (#const B200)+baud2Word B300 = (#const B300)+baud2Word B600 = (#const B600)+baud2Word B1200 = (#const B1200)+baud2Word B1800 = (#const B1800)+baud2Word B2400 = (#const B2400)+baud2Word B4800 = (#const B4800)+baud2Word B9600 = (#const B9600)+baud2Word B19200 = (#const B19200)+baud2Word B38400 = (#const B38400)+baud2Word B57600 = (#const B57600)+baud2Word B115200 = (#const B115200)++-- And convert a word back to a baud rate+-- We really need some cpp macros here.++word2Baud :: CSpeed -> BaudRate+word2Baud x =+ if x == (#const B0) then B0+ else if x == (#const B50) then B50+ else if x == (#const B75) then B75+ else if x == (#const B110) then B110+ else if x == (#const B134) then B134+ else if x == (#const B150) then B150+ else if x == (#const B200) then B200+ else if x == (#const B300) then B300+ else if x == (#const B600) then B600+ else if x == (#const B1200) then B1200+ else if x == (#const B1800) then B1800+ else if x == (#const B2400) then B2400+ else if x == (#const B4800) then B4800+ else if x == (#const B9600) then B9600+ else if x == (#const B19200) then B19200+ else if x == (#const B38400) then B38400+ else if x == (#const B57600) then B57600+ else if x == (#const B115200) then B115200+ else error "unknown baud rate"++-- Clear termios i_flag++clearInputFlag :: CTcflag -> TerminalAttributes -> TerminalAttributes+clearInputFlag flag termios = unsafePerformIO $ do+ fp <- mallocForeignPtrBytes (#const sizeof(struct termios))+ withForeignPtr fp $ \p1 -> do+ withTerminalAttributes termios $ \p2 -> do+ copyBytes p1 p2 (#const sizeof(struct termios)) + iflag <- (#peek struct termios, c_iflag) p2+ (#poke struct termios, c_iflag) p1 (iflag .&. complement flag)+ return $ makeTerminalAttributes fp++-- Set termios i_flag++setInputFlag :: CTcflag -> TerminalAttributes -> TerminalAttributes+setInputFlag flag termios = unsafePerformIO $ do+ fp <- mallocForeignPtrBytes (#const sizeof(struct termios))+ withForeignPtr fp $ \p1 -> do+ withTerminalAttributes termios $ \p2 -> do+ copyBytes p1 p2 (#const sizeof(struct termios)) + iflag <- (#peek struct termios, c_iflag) p2+ (#poke struct termios, c_iflag) p1 (iflag .|. flag)+ return $ makeTerminalAttributes fp++-- Examine termios i_flag++testInputFlag :: CTcflag -> TerminalAttributes -> Bool+testInputFlag flag termios = unsafePerformIO $+ withTerminalAttributes termios $ \p -> do+ iflag <- (#peek struct termios, c_iflag) p+ return $! ((iflag .&. flag) /= 0)++-- Clear termios c_flag++clearControlFlag :: CTcflag -> TerminalAttributes -> TerminalAttributes+clearControlFlag flag termios = unsafePerformIO $ do+ fp <- mallocForeignPtrBytes (#const sizeof(struct termios))+ withForeignPtr fp $ \p1 -> do+ withTerminalAttributes termios $ \p2 -> do+ copyBytes p1 p2 (#const sizeof(struct termios)) + cflag <- (#peek struct termios, c_cflag) p2+ (#poke struct termios, c_cflag) p1 (cflag .&. complement flag)+ return $ makeTerminalAttributes fp++-- Set termios c_flag++setControlFlag :: CTcflag -> TerminalAttributes -> TerminalAttributes+setControlFlag flag termios = unsafePerformIO $ do+ fp <- mallocForeignPtrBytes (#const sizeof(struct termios))+ withForeignPtr fp $ \p1 -> do+ withTerminalAttributes termios $ \p2 -> do+ copyBytes p1 p2 (#const sizeof(struct termios)) + cflag <- (#peek struct termios, c_cflag) p2+ (#poke struct termios, c_cflag) p1 (cflag .|. flag)+ return $ makeTerminalAttributes fp++-- Examine termios c_flag++testControlFlag :: CTcflag -> TerminalAttributes -> Bool+testControlFlag flag termios = unsafePerformIO $+ withTerminalAttributes termios $ \p -> do+ cflag <- (#peek struct termios, c_cflag) p+ return $! ((cflag .&. flag) /= 0)++-- Clear termios l_flag++clearLocalFlag :: CTcflag -> TerminalAttributes -> TerminalAttributes+clearLocalFlag flag termios = unsafePerformIO $ do+ fp <- mallocForeignPtrBytes (#const sizeof(struct termios))+ withForeignPtr fp $ \p1 -> do+ withTerminalAttributes termios $ \p2 -> do+ copyBytes p1 p2 (#const sizeof(struct termios)) + lflag <- (#peek struct termios, c_lflag) p2+ (#poke struct termios, c_lflag) p1 (lflag .&. complement flag)+ return $ makeTerminalAttributes fp++-- Set termios l_flag++setLocalFlag :: CTcflag -> TerminalAttributes -> TerminalAttributes+setLocalFlag flag termios = unsafePerformIO $ do+ fp <- mallocForeignPtrBytes (#const sizeof(struct termios))+ withForeignPtr fp $ \p1 -> do+ withTerminalAttributes termios $ \p2 -> do+ copyBytes p1 p2 (#const sizeof(struct termios)) + lflag <- (#peek struct termios, c_lflag) p2+ (#poke struct termios, c_lflag) p1 (lflag .|. flag)+ return $ makeTerminalAttributes fp++-- Examine termios l_flag++testLocalFlag :: CTcflag -> TerminalAttributes -> Bool+testLocalFlag flag termios = unsafePerformIO $+ withTerminalAttributes termios $ \p -> do+ lflag <- (#peek struct termios, c_lflag) p+ return $! ((lflag .&. flag) /= 0)++-- Clear termios o_flag++clearOutputFlag :: CTcflag -> TerminalAttributes -> TerminalAttributes+clearOutputFlag flag termios = unsafePerformIO $ do+ fp <- mallocForeignPtrBytes (#const sizeof(struct termios))+ withForeignPtr fp $ \p1 -> do+ withTerminalAttributes termios $ \p2 -> do+ copyBytes p1 p2 (#const sizeof(struct termios)) + oflag <- (#peek struct termios, c_oflag) p2+ (#poke struct termios, c_oflag) p1 (oflag .&. complement flag)+ return $ makeTerminalAttributes fp++-- Set termios o_flag++setOutputFlag :: CTcflag -> TerminalAttributes -> TerminalAttributes+setOutputFlag flag termios = unsafePerformIO $ do+ fp <- mallocForeignPtrBytes (#const sizeof(struct termios))+ withForeignPtr fp $ \p1 -> do+ withTerminalAttributes termios $ \p2 -> do+ copyBytes p1 p2 (#const sizeof(struct termios)) + oflag <- (#peek struct termios, c_oflag) p2+ (#poke struct termios, c_oflag) p1 (oflag .|. flag)+ return $ makeTerminalAttributes fp++-- Examine termios o_flag++testOutputFlag :: CTcflag -> TerminalAttributes -> Bool+testOutputFlag flag termios = unsafePerformIO $+ withTerminalAttributes termios $ \p -> do+ oflag <- (#peek struct termios, c_oflag) p+ return $! ((oflag .&. flag) /= 0)++withNewTermios :: TerminalAttributes -> (Ptr CTermios -> IO a) + -> IO TerminalAttributes+withNewTermios termios action = do+ fp1 <- mallocForeignPtrBytes (#const sizeof(struct termios))+ withForeignPtr fp1 $ \p1 -> do+ withTerminalAttributes termios $ \p2 -> do+ copyBytes p1 p2 (#const sizeof(struct termios))+ _ <- action p1+ return ()+ return $ makeTerminalAttributes fp1
System/Posix/Time.hsc view
@@ -1,4 +1,7 @@ {-# LANGUAGE ForeignFunctionInterface #-}+#if __GLASGOW_HASKELL__ >= 701+{-# LANGUAGE Trustworthy #-}+#endif ----------------------------------------------------------------------------- -- | -- Module : System.Posix.Time
System/Posix/Unistd.hsc view
@@ -1,5 +1,8 @@ {-# LANGUAGE ForeignFunctionInterface #-} {-# OPTIONS_GHC -fno-warn-unused-imports -fno-warn-unused-binds #-}+#if __GLASGOW_HASKELL__ >= 701+{-# LANGUAGE Trustworthy #-}+#endif ----------------------------------------------------------------------------- -- | -- Module : System.Posix.Unistd
System/Posix/User.hsc view
@@ -1,4 +1,7 @@ {-# LANGUAGE ForeignFunctionInterface #-}+#if __GLASGOW_HASKELL__ >= 701+{-# LANGUAGE Trustworthy #-}+#endif ----------------------------------------------------------------------------- -- | -- Module : System.Posix.User
cbits/HsUnix.c view
@@ -24,10 +24,10 @@ #endif #ifdef SIGINFO-int __hsunix_SIGINFO() { return SIGINFO; }+int __hsunix_SIGINFO(void) { return SIGINFO; } #endif #ifdef SIGWINCH-int __hsunix_SIGWINCH() { return SIGWINCH; }+int __hsunix_SIGWINCH(void) { return SIGWINCH; } #endif // lstat is a macro on some platforms, so we need a wrapper:@@ -158,7 +158,7 @@ * (PATH_MAX is not defined on systems with unlimited path length, * e.g. the Hurd). */-HsInt __hsunix_long_path_size() {+HsInt __hsunix_long_path_size(void) { #ifdef PATH_MAX return PATH_MAX; #else
unix.cabal view
@@ -1,5 +1,5 @@ name: unix-version: 2.5.0.0+version: 2.5.1.0 license: BSD3 license-file: LICENSE maintainer: libraries@haskell.org@@ -27,19 +27,10 @@ Library exposed-modules: System.Posix- System.Posix.DynamicLinker.Module- System.Posix.DynamicLinker.Prim- System.Posix.Directory- System.Posix.DynamicLinker- System.Posix.Env+ System.Posix.ByteString+ System.Posix.Error- System.Posix.Files- System.Posix.IO- System.Posix.Process- System.Posix.Process.Internals System.Posix.Resource- System.Posix.Temp- System.Posix.Terminal System.Posix.Time System.Posix.Unistd System.Posix.User@@ -47,7 +38,47 @@ System.Posix.Signals.Exts System.Posix.Semaphore System.Posix.SharedMem- build-depends: base >= 4.2 && < 4.5++ System.Posix.ByteString.FilePath++ System.Posix.Directory+ System.Posix.Directory.ByteString++ System.Posix.DynamicLinker.Module+ System.Posix.DynamicLinker.Module.ByteString+ System.Posix.DynamicLinker.Prim+ System.Posix.DynamicLinker.ByteString+ System.Posix.DynamicLinker++ System.Posix.Files+ System.Posix.Files.ByteString++ System.Posix.IO+ System.Posix.IO.ByteString++ System.Posix.Env+ System.Posix.Env.ByteString++ System.Posix.Process+ System.Posix.Process.Internals+ System.Posix.Process.ByteString++ System.Posix.Temp+ System.Posix.Temp.ByteString++ System.Posix.Terminal+ System.Posix.Terminal.ByteString++ other-modules:+ System.Posix.Directory.Common+ System.Posix.DynamicLinker.Common+ System.Posix.Files.Common+ System.Posix.IO.Common+ System.Posix.Process.Common+ System.Posix.Terminal.Common++ build-depends: base >= 4.2 && < 4.6,+ bytestring >= 0.9.2.0 && < 0.10 extensions: CPP, ForeignFunctionInterface, EmptyDataDecls if impl(ghc >= 7.1) extensions: NondecreasingIndentation