module Network.MoHWS.Utility where
import Control.Exception (try, catchJust, )
import Control.Concurrent (newEmptyMVar, takeMVar, )
import Control.Monad (liftM, )
import Control.Monad.Trans.Maybe (MaybeT(MaybeT), runMaybeT, )
import Data.Maybe.HT (toMaybe, )
import Data.Maybe (fromMaybe, )
import Data.Tuple.HT (mapSnd, )
import Data.List (intersperse, )
import Data.List.HT (switchL, switchR, maybePrefixOf, dropWhileRev, takeWhileRev, inits, tails, )
import Data.Ratio (numerator, )
import Foreign.C.Error (getErrno, eNOENT, eNOTDIR, )
import Network.Socket as Socket
import System.IO
import System.Exit (exitFailure, )
import System.Locale (defaultTimeLocale, )
import System.Posix (EpochTime, FileStatus,
getFileStatus, getSymbolicLinkStatus, isSymbolicLink, )
import System.Time (CalendarTime, formatCalendarTime, ClockTime(TOD), )
deHex :: String -> String
deHex s = s
hPutStrCrLf :: Handle -> String -> IO ()
hPutStrCrLf h s = hPutStr h s >> hPutChar h '\r' >> hPutChar h '\n'
die :: String -> IO ()
die err = do hPutStrLn stderr err
exitFailure
readM :: (Read a, Monad m) => String -> m a
readM s = readSM reads s
readSM :: Monad m => ReadS a -> String -> m a
readSM f s =
case f s of
[] -> fail $ "No parse of " ++ show s
[(x,[])] -> return x
[(_,_)] -> fail $ "Junk at end of " ++ show s
_ -> fail $ "Ambiguous parse of " ++ show s
splitBy :: (a -> Bool) -> [a] -> [[a]]
splitBy f =
let recourse =
uncurry (:) .
mapSnd (switchL [] (const recourse)) .
break f
in recourse
glue :: [a] -> [[a]] -> [a]
glue g = concat . intersperse g
splits :: [a] -> [([a],[a])]
splits xs = zip (inits xs) (tails xs)
dropPrefix :: Eq a => [a] -> [a] -> [a]
dropPrefix xs pref =
fromMaybe xs $ maybePrefixOf pref xs
dropSuffix :: Eq a => [a] -> [a] -> [a]
dropSuffix xs suf = reverse (reverse xs `dropPrefix` reverse suf)
splitPath :: FilePath -> [String]
splitPath = splitBy (=='/')
joinPath :: [String] -> FilePath
joinPath = glue "/"
dirname :: FilePath -> FilePath
dirname = dropWhileRev (/= '/')
basename :: FilePath -> FilePath
basename = takeWhileRev (/= '/')
hasTrailingSlash :: FilePath -> Bool
hasTrailingSlash =
switchR False (\_ -> ('/'==))
formatTimeSensibly :: CalendarTime -> String
formatTimeSensibly time
= formatCalendarTime defaultTimeLocale "%a, %d %b %Y %H:%M:%S GMT" time
epochTimeToClockTime :: EpochTime -> ClockTime
epochTimeToClockTime epoch_time = TOD (numToInteger epoch_time) 0
where numToInteger = numerator . toRational
wait :: IO a
wait = newEmptyMVar >>= takeMVar
accept :: Socket
-> IO (Handle,SockAddr)
accept sock = do
(sock', addr) <- Socket.accept sock
hndle <- socketToHandle sock' ReadWriteMode
return (hndle,addr)
statFile :: String -> MaybeT IO FileStatus
statFile = stat_ getFileStatus
statSymLink :: String -> MaybeT IO FileStatus
statSymLink = stat_ getSymbolicLinkStatus
stat_ :: (FilePath -> IO FileStatus) -> String -> MaybeT IO FileStatus
stat_ f filename = MaybeT $ do
maybe_stat <- try (f filename)
case maybe_stat of
Left e -> do
errno <- getErrno
if errno == eNOENT || errno == eNOTDIR
then return Nothing
else ioError e
Right stat ->
return $ Just stat
isSymLink :: FilePath -> IO Bool
isSymLink = liftM (maybe False isSymbolicLink) . runMaybeT . statSymLink
catchSomeIOErrors :: (IOError -> Bool) -> IO a -> (IOError -> IO a) -> IO a
catchSomeIOErrors p =
catchJust (\e -> toMaybe (p e) e)