| 1 |
{-# OPTIONS_GHC -fglasgow-exts -fallow-overlapping-instances -fallow-undecidable-instances #-} |
|---|
| 2 |
module Pugs.Prim.FileTest ( |
|---|
| 3 |
isReadable, isWritable, isExecutable, |
|---|
| 4 |
exists, isFile, isDirectory, |
|---|
| 5 |
fileSize, sizeIsZero, |
|---|
| 6 |
fileMTime, fileCTime, fileATime, |
|---|
| 7 |
fileTestViaPerl5 |
|---|
| 8 |
) where |
|---|
| 9 |
import Pugs.Internals |
|---|
| 10 |
import Pugs.Embed |
|---|
| 11 |
import Pugs.Types |
|---|
| 12 |
import Pugs.AST hiding (isWritable) |
|---|
| 13 |
|
|---|
| 14 |
-- filetest operators -- |
|---|
| 15 |
|
|---|
| 16 |
-- Officially, these should return a stat object, which sometimes pretends |
|---|
| 17 |
-- to be a boolean, and may(?) return the filename in string context. |
|---|
| 18 |
-- DARCS was working on stat, and we should perhaps grab their work: |
|---|
| 19 |
-- http://www.abridgegame.org/pipermail/darcs-users/2005-February/005499.html |
|---|
| 20 |
-- They currently (2004-04-05) seem to be using: |
|---|
| 21 |
-- http://abridgegame.org/cgi-bin/darcs.cgi/darcs/win32/System/Posix.hs |
|---|
| 22 |
-- For the moment, these return filename and false or undef. |
|---|
| 23 |
-- Known Bugs: multiple stat()s are done, and filename isnt a boolean. |
|---|
| 24 |
|
|---|
| 25 |
isReadable :: Val -> Eval Val |
|---|
| 26 |
isReadable = fileTestIO fileTestIsReadable |
|---|
| 27 |
isWritable :: Val -> Eval Val |
|---|
| 28 |
isWritable = fileTestIO fileTestIsWritable |
|---|
| 29 |
isExecutable :: Val -> Eval Val |
|---|
| 30 |
isExecutable = fileTestIO fileTestIsExecutable |
|---|
| 31 |
exists :: Val -> Eval Val |
|---|
| 32 |
exists = fileTestIO fileTestExists |
|---|
| 33 |
isFile :: Val -> Eval Val |
|---|
| 34 |
isFile = fileTestIO fileTestIsFile |
|---|
| 35 |
isDirectory :: Val -> Eval Val |
|---|
| 36 |
isDirectory = fileTestIO fileTestIsDirectory |
|---|
| 37 |
fileSize :: Val -> Eval Val |
|---|
| 38 |
fileSize = fileTestIO fileTestFileSize |
|---|
| 39 |
sizeIsZero :: Val -> Eval Val |
|---|
| 40 |
sizeIsZero = fileTestIO fileTestSizeIsZero |
|---|
| 41 |
fileMTime :: Val -> Eval Val |
|---|
| 42 |
fileMTime = fileTime statFileMTime |
|---|
| 43 |
fileCTime :: Val -> Eval Val |
|---|
| 44 |
fileCTime = fileTime statFileCTime |
|---|
| 45 |
fileATime :: Val -> Eval Val |
|---|
| 46 |
fileATime = fileTime statFileATime |
|---|
| 47 |
|
|---|
| 48 |
fileTestViaPerl5 :: String -> Val -> Eval Val |
|---|
| 49 |
fileTestViaPerl5 testOp v = do |
|---|
| 50 |
env <- ask |
|---|
| 51 |
envSV <- io $ mkEnv env |
|---|
| 52 |
argSV <- fromVal v |
|---|
| 53 |
subSV <- io $ evalPerl5 ("sub { -" ++ testOp ++ " $_[0] }") envSV (enumCxt cxtItemAny) |
|---|
| 54 |
rv <- runInvokePerl5 subSV nullSV [argSV] |
|---|
| 55 |
return $ case rv of |
|---|
| 56 |
VStr "" -> VBool False |
|---|
| 57 |
VNum 1 -> VBool True |
|---|
| 58 |
VInt 1 -> VBool True |
|---|
| 59 |
_ -> rv |
|---|
| 60 |
|
|---|
| 61 |
fileTime :: (FilePath -> IO Integer) -> Val -> Eval Val |
|---|
| 62 |
fileTime test f = do |
|---|
| 63 |
t <- fileTestIO (fileTestDo test) f |
|---|
| 64 |
if (t == undef) then return VUndef else do |
|---|
| 65 |
t' <- fromVal t :: Eval Integer |
|---|
| 66 |
b <- fromVal =<< readVar (cast "$*BASETIME") |
|---|
| 67 |
return $ VRat $ (b - (pugsTimeSpec . posixSecondsToUTCTime $ fromIntegral t')) / 86400 |
|---|
| 68 |
|
|---|
| 69 |
fileTestIO :: (Value n) => (n -> IO Val) -> Val -> Eval Val |
|---|
| 70 |
fileTestIO f v = do |
|---|
| 71 |
str <- fromVal =<< fromVal' v |
|---|
| 72 |
tryIO undef $ f str |
|---|
| 73 |
|
|---|
| 74 |
valFromBool :: Value a => a -> Bool -> Val |
|---|
| 75 |
valFromBool v b = if b then castV v else VBool False |
|---|
| 76 |
|
|---|
| 77 |
testPerms :: (Permissions -> Bool) -> FilePath -> IO Val |
|---|
| 78 |
testPerms t f = do |
|---|
| 79 |
p <- getPermissions f |
|---|
| 80 |
let b = t p |
|---|
| 81 |
return $ valFromBool f b |
|---|
| 82 |
|
|---|
| 83 |
fileTestIsReadable :: FilePath -> IO Val |
|---|
| 84 |
fileTestIsReadable = testPerms readable |
|---|
| 85 |
|
|---|
| 86 |
fileTestIsWritable :: FilePath -> IO Val |
|---|
| 87 |
fileTestIsWritable = testPerms writable |
|---|
| 88 |
|
|---|
| 89 |
fileTestIsExecutable :: FilePath -> IO Val |
|---|
| 90 |
fileTestIsExecutable = testPerms $ liftM2 (||) executable searchable |
|---|
| 91 |
|
|---|
| 92 |
fileTestExists :: FilePath -> IO Val |
|---|
| 93 |
fileTestExists f = doesExist f >>= return . (valFromBool f) |
|---|
| 94 |
|
|---|
| 95 |
fileTestIsFile :: FilePath -> IO Val |
|---|
| 96 |
fileTestIsFile f = doesFileExist f >>= return . (valFromBool f) |
|---|
| 97 |
|
|---|
| 98 |
fileTestIsDirectory :: FilePath -> IO Val |
|---|
| 99 |
fileTestIsDirectory f = doesDirectoryExist f >>= return . (valFromBool f) |
|---|
| 100 |
|
|---|
| 101 |
fileTestFileSize :: FilePath -> IO Val |
|---|
| 102 |
fileTestFileSize f = statFileSize f >>= return . VInt |
|---|
| 103 |
|
|---|
| 104 |
fileTestSizeIsZero :: FilePath -> IO Val |
|---|
| 105 |
fileTestSizeIsZero f = do |
|---|
| 106 |
n <- statFileSize f |
|---|
| 107 |
return $ if n == 0 then VBool True else VBool False |
|---|
| 108 |
|
|---|
| 109 |
fileTestDo :: (FilePath -> IO Integer) -> FilePath -> IO Val |
|---|
| 110 |
fileTestDo test f = test f >>= return . VInt |
|---|