summaryrefslogtreecommitdiff
path: root/Coolbal/Target/Utils.hs
blob: 432a8a8c7464bffa32e4f59b8d88d7911e0a79f3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
{-# LANGUAGE LambdaCase #-}
module Coolbal.Target.Utils where

import Data.Char (ord)
import Data.List (intercalate)
import Data.Time.Clock (UTCTime)
import Numeric (showHex)
import System.Directory (doesFileExist, getModificationTime)
import System.Exit (ExitCode(..), die, exitWith)
import System.FilePath ((</>))
import System.IO.Error (catchIOError)

import Coolbal.Util


checkExitCode :: ExitCode -> IO ()
checkExitCode ExitSuccess = return ()
checkExitCode c@(ExitFailure _) = exitWith c

escapeFileName :: String -> FilePath
escapeFileName =
    -- NTFS/POSIX not allows: 0x00-0x1F 0x7F- : / " * < > ? \ |
    -- We use ! as an escape character, and hence disallow that too.
    genericEscapeString
        (\c -> let n = ord c
               in n <= 0x1F || n >= 0x7F || c `elem` ":/\"*<>?\\|!")
        (\c -> case (c, ord c) of
            ('!', _) -> "!!"
            (_, n) | n <= 0xFF -> '!' : leftPad 2 '0' (showHex n "")
                   | n <= 0xFFFF -> '!' : 'u' : leftPad 4 '0' (showHex n "")
                   | n <= 0xFFFFFF -> '!' : 'U' : leftPad 6 '0' (showHex n "")
                   | otherwise -> error "Super-high unicode?")
  where
    leftPad n c s = replicate (max 0 (n - length s)) c ++ s

maybeModificationTime' :: FilePath -> IO UTCTime
maybeModificationTime' path = maybeModificationTime path >>= \case
    Just tm -> return tm
    Nothing -> die ("File not found: '" ++ path ++ "'")

maybeModificationTime :: FilePath -> IO (Maybe UTCTime)
maybeModificationTime path = 
    catchIOError (Just <$> getModificationTime path) (\_ -> return Nothing)

findSourceFile' :: [FilePath] -> [String] -> IO FilePath
findSourceFile' ds m = findSourceFile ds m >>= \case
    Just fp -> return fp
    Nothing -> die ("Module not found in source directories: " ++ intercalate "." m)

findSourceFile :: [FilePath] -> [String] -> IO (Maybe FilePath)
findSourceFile dirs modname = findFile dirs (foldr (</>) "" modname ++ ".hs")

findFile' :: [FilePath] -> FilePath -> IO FilePath
findFile' ds fname = findFile ds fname >>= \case
    Just fp -> return fp
    Nothing -> die ("File not found in source directories: '" ++ fname ++ "'")

findFile :: [FilePath] -> FilePath -> IO (Maybe FilePath)
findFile [] _ = return Nothing
findFile (dir:ds) fname = do
    ok <- doesFileExist (dir </> fname)
    if ok then return (Just (dir </> fname))
          else findFile ds fname

anyNewerThan :: UTCTime -> [IO FilePath] -> IO Bool
anyNewerThan _ [] = return False
anyNewerThan reftm (fp:fps) = do
    fp' <- fp
    tm <- maybeModificationTime' fp'
    if tm > reftm
        then return True
        else anyNewerThan reftm fps