    {-# OPTIONS_GHC -cpp #-}
    {-# LANGUAGE CPP #-}

    module Workaround ( renameFile, setExecutable, getCurrentDirectory,
                        installHandler, raiseSignal, Handler(..), Signal,
                        sigINT, sigHUP, sigABRT, sigALRM, sigTERM, sigPIPE ) where

    #ifdef WIN32
    import qualified System.Directory ( renameFile, getCurrentDirectory, removeFile )
    import qualified Control.Exception ( block )
    import qualified System.IO.Error ( isDoesNotExistError, ioError, catch )
    #else
    import System.Posix.Signals(installHandler, raiseSignal, Handler(..), Signal,
                                sigINT, sigHUP, sigABRT, sigALRM, sigTERM, sigPIPE)
    import System.Directory ( renameFile, getCurrentDirectory )
    import System.Posix.Files (fileMode,getFileStatus, setFileMode,
                               setFileCreationMask,
                               ownerReadMode, ownerWriteMode, ownerExecuteMode,
                               groupReadMode, groupWriteMode, groupExecuteMode,
                               otherReadMode, otherWriteMode, otherExecuteMode)
    import Data.Bits ( (.&.), (.|.), complement )
    #endif

    #ifdef WIN32
    -- Dummy implementation of POSIX signals
    data Handler = Default | Ignore | Catch (IO ())
    type Signal = Int

    installHandler :: Signal -> Handler -> Maybe () -> IO ()
    installHandler _ _ _ = return ()

    raiseSignal :: Signal -> IO ()
    raiseSignal _ = return ()

    sigINT, {- sigKILL, -} sigHUP, {- sigQUIT, -} sigABRT, sigALRM, sigTERM, sigPIPE :: Signal
    sigINT = 0
    -- not used: sigKILL = 0
    sigHUP = 0
    -- not used: sigQUIT = 0
    sigABRT = 0
    sigTERM = 0
    sigPIPE = 0
    sigALRM = 0

    {-
    System.Directory.renameFile incorrectly fails when the new file already
    exists.  This code works around that bug at the cost of losing atomic
    writes.
    -}

    renameFile :: FilePath -> FilePath -> IO ()
    renameFile old new = Control.Exception.block $
       System.Directory.renameFile old new
       `System.IO.Error.catch` \_ ->
       do System.Directory.removeFile new
            `System.IO.Error.catch`
             (\e -> if System.IO.Error.isDoesNotExistError e
                       then return ()
                       else System.IO.Error.ioError e)
          System.Directory.renameFile old new

    setExecutable :: FilePath -> Bool -> IO ()
    setExecutable _ _ = return ()

    {-
    System.Directory.getCurrentDirectory returns a path with backslashes in it
    under windows, and some of the code gets confused by that, so we override
    getCurrentDirectory and translates '\\' to '/'
    -}

    getCurrentDirectory :: IO FilePath
    getCurrentDirectory = do d <- System.Directory.getCurrentDirectory
                             return $ map rb d
        where rb '\\' = '/'
              rb c = c

    #else

    setExecutable :: FilePath -> Bool -> IO ()
    setExecutable f ex =
      do st <- getFileStatus f
         umask <- setFileCreationMask 0
         setFileCreationMask umask
         let rw = fileMode st .&.
                  (ownerReadMode .|. ownerWriteMode .|.
                   groupReadMode .|. groupWriteMode .|.
                   otherReadMode .|. otherWriteMode)
             total = if ex then rw .|.
                               ((ownerExecuteMode .|. groupExecuteMode .|. otherExecuteMode)
                                .&. complement umask)
                           else rw
         setFileMode f total

    #endif