aboutsummaryrefslogtreecommitdiff
path: root/Inotify.icl
blob: 20ce3e957351a8245a9d78ad3b9248c7af3b13ce (plain) (blame)
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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
implementation module Inotify

import Data.Either
import Data.Maybe

import StdArray
import StdBool
import StdFunc
import StdInt
import StdList
import StdString

from StdOverloaded import class zero(zero)

import code from "inotify_c.o"

:: *Inotify st = { fd      :: *Int
                 , watches :: [(INWatch, INCallback st)]
                 , state   :: st
                 }

:: INWatch :== Int

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

inotify_init :: st -> Maybe *(Inotify st)
inotify_init st
	= let fd=c_init 0 in if (fd<0) Nothing (Just {fd=fd, watches=[], state=st})
where
	c_init :: !Int -> *Int
	c_init i = code {
		ccall clean_inotify_init "I:I"
	}

inotify_close :: *(Inotify st) -> st
inotify_close {fd,state} = c_close fd state
where
	c_close :: !*Int !st -> st
	c_close fd st = code {
		ccall close "I:V:A"
	}

inotify_add_watch :: (INCallback st) !Int !String !*(Inotify st)
                  -> *(Either Int INWatch, *Inotify st)
inotify_add_watch f mask fname inot=:{fd,watches}
	= let (w, fd`) = c_add_watch fd fname mask in
		( if (w == -1) (Left errno) (Right w)
		, {inot & fd=fd`, watches=[(w,f):watches]}
		)
where
	c_add_watch :: !*Int !String !Int -> *(!Int, !*Int)
	c_add_watch inot fname mask = code {
		ccall clean_inotify_add_watch "ISI:VII"
	}

inotify_rm_watch :: !INWatch !*(Inotify st) -> *(Bool, *Inotify st)
inotify_rm_watch w inot=:{fd}
	= case c_inotify_rm_watch fd w of (0, fd`) = (True,  {inot & fd=fd`})
	                                  (_, fd`) = (False, {inot & fd=fd`})
where
	c_inotify_rm_watch :: !*Int !Int -> *(!Int, !*Int)
	c_inotify_rm_watch w i = code {
		ccall clean_inotify_rm_watch "II:VII"
	}

inotify_poll :: *(Inotify st) -> *Inotify st
inotify_poll inot=:{fd} = let (_,fd`) = c_poll fd in { inot & fd=fd` }
where
	c_poll :: !*Int -> *(!Int, !*Int)
	c_poll fd = code {
		ccall clean_poll "I:VII"
	}

inotify_check :: *(Inotify st) *World -> *(*Inotify st, *World)
inotify_check inot=:{fd,watches,state} w
	# (ok, wds, masks, fd) = c_check fd
	  inot = { inot & fd=fd }
	| not ok = (inot, w)
	| (size wds) rem 4 <> 0 || (size masks) rem 4 <> 0 = (inot,w)
	# (wds,masks) = (split 4 wds, split 4 masks)
	| length wds <> length masks = (inot, w)
	# wdsmasks = zip2 (map bytesToInt wds) (map bytesToInt masks)
	# (fd,st,w`) = seq (map (check wdsmasks) watches) (inot.fd, state, w)
	= ({ inot & fd=fd, state=st }, w`)
where
	check :: [(Int,Int)] (INWatch, INCallback st) *(*Int, st, *World)
	      -> *(*Int, st, *World)
	check wdsmasks (watch,f) (fd,st,w)
		# (st,w) = seq [\(st,w) -> f mask st w
		                \\ (wd,mask) <- wdsmasks | wd == watch] (st,w)
		= (fd,st,w)

	bytesToInt :: {#Char} -> Int
	bytesToInt cs = sum [toInt c * (8 ^ p) \\ c <-: cs & p <- [0..]]

	split :: Int String -> [String]
	split n s
		| size s > n = [s % (0,n-1) : split n (s % (n, size s - 1))]
		| size s == n = [s]
		| s == "" = []
	
	c_check :: !*Int -> *(!Bool, !String, !String, !*Int)
	c_check fd = code {
		ccall clean_inotify_check "I:VISSI"
	}

errno :: Int
errno = err 0
where
	err :: !Int -> Int
	err i = code {
		ccall clean_errno "I:I"
	}