Inotify.icl 3.78 KB
Newer Older
Camil Staps's avatar
Camil Staps committed
1 2 3 4
implementation module Inotify

import StdArray
import StdBool
5
import StdEnum
Camil Staps's avatar
Camil Staps committed
6 7 8
import StdFunc
import StdInt
import StdList
9
from StdOverloaded import class zero(zero)
Camil Staps's avatar
Camil Staps committed
10 11
import StdString

12 13 14 15 16
import Data.Either
import Data.List
import Data.Maybe
import System._Pointer
import System._Posix
Camil Staps's avatar
Camil Staps committed
17 18 19 20 21 22 23 24 25 26

import code from "inotify_c.o"

:: INWatch :== Int

(|-) infixl 6 :: (INMask INMask -> INMask)
(|-) = bitor

inotify_init :: st -> Maybe *(Inotify st)
inotify_init st
27 28 29 30 31
	# (fd,_) = c_init 0
	| fd < 0 = Nothing
	# (i,_)  = fcntlArg fd 00004000 0 37 // IN_NONBLOCK
	| i <> i = Nothing
	= Just {fd=fd, watches=[], state=st}
Camil Staps's avatar
Camil Staps committed
32
where
33
	c_init :: !Int -> (!Int, !Int)
Camil Staps's avatar
Camil Staps committed
34
	c_init i = code {
35
		ccall inotify_init ":I:I"
Camil Staps's avatar
Camil Staps committed
36 37 38 39 40
	}

inotify_close :: *(Inotify st) -> st
inotify_close {fd,state} = c_close fd state
where
41
	c_close :: !Int !st -> st
Camil Staps's avatar
Camil Staps committed
42 43 44 45
	c_close fd st = code {
		ccall close "I:V:A"
	}

46 47
inotify_add_watch :: (INCallback st) !INMask !String !*(Inotify st)
                  -> *(!Either Int INWatch, !*Inotify st)
Camil Staps's avatar
Camil Staps committed
48
inotify_add_watch f mask fname inot=:{fd,watches}
49 50 51 52 53
	# w = c_add_watch fd (packString fname) mask
	| w == -1
		# (err,inot) = errno inot
		= (Left err,inot)
	= (Right w, {inot & watches=[(w,f):watches]})
Camil Staps's avatar
Camil Staps committed
54
where
55
	c_add_watch :: !Int !String !Int -> Int
Camil Staps's avatar
Camil Staps committed
56
	c_add_watch inot fname mask = code {
57
		ccall inotify_add_watch "IsI:I"
Camil Staps's avatar
Camil Staps committed
58 59
	}

60
inotify_rm_watch :: !INWatch !*(Inotify st) -> *(!Bool, !*Inotify st)
Camil Staps's avatar
Camil Staps committed
61
inotify_rm_watch w inot=:{fd}
62 63 64
	= case c_inotify_rm_watch fd w of
		0 -> (True,  inot)
		_ -> (False, inot)
Camil Staps's avatar
Camil Staps committed
65
where
66
	c_inotify_rm_watch :: !Int !Int -> Int
Camil Staps's avatar
Camil Staps committed
67
	c_inotify_rm_watch w i = code {
68
		ccall inotify_rm_watch "II:I"
Camil Staps's avatar
Camil Staps committed
69 70
	}

71 72
inotify_poll :: !(Maybe Int) !*(Inotify st) -> *(!Int, !*Inotify st)
inotify_poll mbTo inot=:{fd} = let (n,fd`)=c_poll fd to in (n, {inot & fd=fd`})
Camil Staps's avatar
Camil Staps committed
73
where
74 75
	to = if (isNothing mbTo) -1 (fromJust mbTo)

76
	c_poll :: !Int !Int -> (!Int, !Int)
77 78
	c_poll fd timeout = code {
		ccall clean_poll "II:VII"
Camil Staps's avatar
Camil Staps committed
79 80
	}

81
inotify_check :: !*(Inotify st) !*World -> *(!*Inotify st, !*World)
Camil Staps's avatar
Camil Staps committed
82
inotify_check inot=:{fd,watches,state} w
83
	# (ok, wds, masks, fnames, fd) = c_check fd
84
	  inot & fd = fd
Camil Staps's avatar
Camil Staps committed
85 86
	| not ok = (inot, w)
	| (size wds) rem 4 <> 0 || (size masks) rem 4 <> 0 = (inot,w)
87
	# (wds,masks,fnames) = (split 4 wds, split 4 masks, splitOn '\0' fnames)
Camil Staps's avatar
Camil Staps committed
88
	| length wds <> length masks = (inot, w)
89
	# infos = zip3 (map bytesToInt wds) (map bytesToInt masks) fnames
90
	= seq (map (check infos) watches) (inot, w)
Camil Staps's avatar
Camil Staps committed
91
where
92 93 94
	check :: [(Int,Int,String)] (INWatch, INCallback st) *(*Inotify st, *World)
	      -> *(*Inotify st, *World)
	check infos (watch,f) (st,w)
Camil Staps's avatar
Camil Staps committed
95 96 97 98 99 100
		# (st,w) = seq
			[ \(st,w) -> f mask (toMaybe name) st w
			\\ (wd,mask,name) <- infos
			| wd == watch
			]
			(st,w)
101
		= (st,w)
102 103
	where
		toMaybe :: String -> Maybe String
Camil Staps's avatar
Camil Staps committed
104
		toMaybe s  = if (size s==0) Nothing (Just s)
Camil Staps's avatar
Camil Staps committed
105 106

	bytesToInt :: {#Char} -> Int
107
	bytesToInt cs = sum [toInt c << p \\ c <-: cs & p <- [0,8..]]
Camil Staps's avatar
Camil Staps committed
108 109 110

	split :: Int String -> [String]
	split n s
Camil Staps's avatar
Camil Staps committed
111
		| size s > n  = [s % (0,n-1) : split n (s % (n, size s - 1))]
Camil Staps's avatar
Camil Staps committed
112
		| size s == n = [s]
Camil Staps's avatar
Camil Staps committed
113
		| size s == 0 = []
114 115 116 117 118 119

	splitOn :: Char String -> [String]
	splitOn c s = map toString (split` c [c \\ c <-: s])
	where
		split` :: Char [Char] -> [[Char]]
		split` c [] = []
Camil Staps's avatar
Camil Staps committed
120
		split` c cs=:[x:xs] = [l:split` c r] where (l,[_:r]) = span ((<>)c) cs
Camil Staps's avatar
Camil Staps committed
121
	
122
	c_check :: !Int -> (!Bool, !String, !String, !String, !Int)
Camil Staps's avatar
Camil Staps committed
123
	c_check fd = code {
124
		ccall clean_inotify_check "I:VISSSI"
Camil Staps's avatar
Camil Staps committed
125 126
	}

127 128 129
inotify_is_event :: INMask INEvent -> Bool
inotify_is_event mask ev = ev bitand mask <> 0

Camil Staps's avatar
Camil Staps committed
130 131
inotify_loop_with_timeout :: !(Maybe Int) !*(Inotify st) !*World
                          -> *(!*Inotify st, !*World)
132 133 134
inotify_loop_with_timeout to inot w
	# (n,inot) = inotify_poll to inot
	| n == 0   = (inot,w)
135
	# (inot,w) = inotify_check inot w
136 137 138 139
	= inotify_loop_with_timeout to inot w

inotify_loop_forever :: !*(Inotify st) !*World -> *(!*Inotify st, !*World)
inotify_loop_forever inot w = inotify_loop_with_timeout Nothing inot w