packages feed

KiCS-0.8.6: src/Curry/Compiler/KicsSubdir.hs

module Curry.Compiler.KicsSubdir where

import System.Directory
import System.FilePath
import System.Time (ClockTime)
import Control.Monad (when)
import List (intersperse,nubBy)

curDirPath :: FilePath
curDirPath = "."

path :: String -> [String]
path = canonPath . separateBy isPathSeparator 
  where
    canonPath (c:cs) = c:filter (not . null) cs

-- separate a list by separator predicate

separateBy :: (a -> Bool) -> [a] -> [[a]]
separateBy p = sep id 
  where
    sep xs [] = [xs []]
    sep xs (c:cs) = if p c then xs [] : sep id cs
                           else sep (xs . (c:)) cs

unpath :: [String] -> String
unpath = concat . intersperse [pathSeparator]

toPathList :: [String] -> String
toPathList = concat . intersperse [searchPathSeparator]


--When we split a path into its basename and directory we will make
--sure that the basename does not contain any path separators.
 
dirname, basename :: FilePath -> FilePath
dirname  = unpath . init . path
basename = last . path

-- add a subdirectory to a given filename 
-- if it is not already present

inSubdir :: String -> String -> String
inSubdir fn sub = unpath $ add (path fn) 
  where
    add ps@[n] = sub:ps
    add ps@[p,n] | p==sub = ps
    add (p:ps) = p:add ps

withoutSubdir :: String -> String -> String
withoutSubdir fn sub = unpath $ rmv (path fn) 
  where
    rmv [] = []
    rmv [p,n]  | p==sub = [n]
    rmv (p:ps) = p:rmv ps


--The sub directory to hide files in:

currySubdir :: String 
currySubdir = ".curry"

inCurrySubdir :: String -> String
inCurrySubdir = (`inSubdir` currySubdir)

kicsSubdir = "kics"
addKicsSubdir s = unpath [s,currySubdir,kicsSubdir]

pathWithSubdirs :: [FilePath] -> [FilePath]
pathWithSubdirs = concatMap dirWithSubdirs
  where
    dirWithSubdirs dir = [dir,unpath [dir,currySubdir,[pathSeparator]],
                              unpath [dir,currySubdir,kicsSubdir,[pathSeparator]]] 

inKicsSubdir :: String -> String
inKicsSubdir s = inCurrySubdir s `inSubdir` kicsSubdir

inModuleSubdir :: String -> String
inModuleSubdir s = s `inSubdir` "Curry" `inSubdir` "Module"

--write a file to curry subdirectory

writeKicsFile :: Bool -> String -> String -> IO String
writeKicsFile isHsModule filename contents = do
  let filename' | isHsModule = inModuleSubdir (inKicsSubdir filename)
                | otherwise  = inKicsSubdir filename 
      subdir = dirname filename'
  createDirectoryIfMissing True subdir
  writeFile filename' contents
  return filename'


-- do things with file in subdir

onExistingFileDo :: (String -> IO a) -> String -> IO a
onExistingFileDo act fn = do
  let filename = fn --(fn `withoutSubdir` kicsSubdir) 
  ex <- doesFileExist filename
  if ex then act filename 
    else do
      let filename' = inCurrySubdir filename
      ex <- doesFileExist filename'
      if ex then act filename' 
        else do
          let filename'' = inKicsSubdir filename
          act filename''

readModule :: String -> IO String
readModule = onExistingFileDo readFile

maybeReadModule :: String -> IO (Maybe String)
maybeReadModule filename = 
  catch (readModule filename >>= return . Just) (\_ -> return Nothing)

doesModuleExist :: String -> IO Bool
doesModuleExist = onExistingFileDo doesFileExist

getModuleModTime :: String -> IO ClockTime
getModuleModTime = onExistingFileDo getModificationTime

findFileInPath :: String -> [String] -> IO [String]
findFileInPath fn path = do
   if any isPathSeparator fn 
     then findFile fn
     else do
       let fs = nubBy equalFilePath $ map (++fn) path
       founds <- mapM findFile fs
       return (nubBy equalFilePath $ concat founds)

  where
    findFile = onExistingFileDo doesExist
    doesExist fn = do ex <- doesFileExist fn 
                      if ex then return [fn] else return []