{-# LINE 1 "System/Unix/FilePath.hsc" #-}
{-# LANGUAGE ForeignFunctionInterface #-}
{-# LINE 2 "System/Unix/FilePath.hsc" #-}
-- | The function splitFileName is taken from missingh, at the moment
-- missingh will not build under sid.

module System.Unix.FilePath 
    (dirName,
     baseName,
     (+/+),
     realpath,
     -- * From MissingH
     splitFileName)
    where

import Data.List
import Text.Regex
import Foreign.C
import Foreign.Marshal.Array


{-# LINE 20 "System/Unix/FilePath.hsc" #-}

{-# LINE 21 "System/Unix/FilePath.hsc" #-}

(+/+) :: FilePath -> FilePath -> FilePath
(+/+) path1 "" = path1
(+/+) "" path2 = path2
(+/+) path1 path2 =
    case (head (reverse path1), head path2) of
      ('/', '/') -> path1 ++ drop 1 path2
      (_, '/') -> path1 ++ path2
      ('/', _) -> path1 ++ path2
      (_, _) -> path1 ++ "/" ++ path2

dirName :: FilePath -> FilePath
dirName path = fst (splitFileName path)

baseName :: FilePath -> String
baseName path = snd (splitFileName path)

canon :: FilePath -> FilePath
-- ^ Weak attempt at canonicalizing a file path.
canon path =
    let re = mkRegex "/" in
    let names = splitRegex re path in
    concat (intersperse "/" (merge names))
    where
      merge (".." : xs) = ".." : (merge xs)
      merge ("." : xs) = "." : (merge xs)
      merge (_ : ".." : xs) = (merge xs)
      merge (x : "." : xs) = (merge (x : xs))
      merge (x : xs) = x : merge xs
      merge [] = []

-------------- From MissingH --------------


-- | Split the path into directory and file name
--
-- Examples:
--
-- \[Posix\]
--
-- > splitFileName "/"            == ("/",    ".")
-- > splitFileName "/foo/bar.ext" == ("/foo", "bar.ext")
-- > splitFileName "bar.ext"      == (".",    "bar.ext")
-- > splitFileName "/foo/."       == ("/foo", ".")
-- > splitFileName "/foo/.."      == ("/foo", "..")
--
-- \[Windows\]
--
-- > splitFileName "\\"               == ("\\",      "")
-- > splitFileName "c:\\foo\\bar.ext" == ("c:\\foo", "bar.ext")
-- > splitFileName "bar.ext"          == (".",       "bar.ext")
-- > splitFileName "c:\\foo\\."       == ("c:\\foo", ".")
-- > splitFileName "c:\\foo\\.."      == ("c:\\foo", "..")
--
-- The first case in the Windows examples returns an empty file name.
-- This is a special case because the \"\\\\\" path doesn\'t refer to
-- an object (file or directory) which resides within a directory.
splitFileName :: FilePath -> (String, String)
splitFileName p = (reverse path1, reverse fname1)
  where
    (fname,path) = break isPathSeparator (reverse p)
    path1 = case path of
      "" -> "."
      _  -> case dropWhile isPathSeparator path of
	"" -> [pathSeparator]
	p  -> p
    fname1 = case fname of
      "" -> "."
      _  -> fname

-- | Checks whether the character is a valid path separator for the host
-- platform. The valid character is a 'pathSeparator' but since the Windows
-- operating system also accepts a slash (\"\/\") since DOS 2, the function
-- checks for it on this platform, too.
isPathSeparator :: Char -> Bool
isPathSeparator ch =
  ch == '/'

-- | Provides a platform-specific character used to separate directory levels in
-- a path string that reflects a hierarchical file system organization. The
-- separator is a slash (@\"\/\"@) on Unix and Macintosh, and a backslash
-- (@\"\\\"@) on the Windows operating system.
pathSeparator :: Char
pathSeparator = '/'

-- |resolve all references to /./, /../, extra slashes, and symlinks
realpath :: FilePath -> IO FilePath
realpath fp =
    withCString fp $ \cfp ->
        allocaArray (4096) $ \res ->
{-# LINE 111 "System/Unix/FilePath.hsc" #-}
            throwErrnoIfNull "realpath" (c_realpath cfp res) >>= peekCString

foreign import ccall unsafe "realpath" c_realpath :: CString -> CString -> IO CString