Build fixes
[tclinotify.git] / generic / main.c
blobf777204fd7885562223217fa5cb23adf5f949433
1 #include <tclstuff.h>
2 #include <sys/inotify.h>
3 #include <sys/ioctl.h>
4 #include <unistd.h>
5 #include <malloc.h>
8 static int list2mask(interp, list, mask) //<<<
9 Tcl_Interp *interp;
10 Tcl_Obj *list;
11 uint32_t *mask;
13 int objc, i, index;
14 Tcl_Obj **objv;
15 uint32_t build = 0;
16 static CONST char *mask_bits[] = {
17 "IN_ACCESS",
18 "IN_MODIFY",
19 "IN_ATTRIB",
20 "IN_CLOSE_WRITE",
21 "IN_CLOSE_NOWRITE",
22 "IN_OPEN",
23 "IN_MOVED_FROM",
24 "IN_MOVED_TO",
25 "IN_CREATE",
26 "IN_DELETE",
27 "IN_DELETE_SELF",
28 "IN_MOVE_SELF",
29 "IN_CLOSE", // IN_CLOSE_WRITE | IN_CLOSE_NOWRITE
30 "IN_MOVE", // IN_MOVED_FROM | IN_MOVED_TO
31 "IN_ONLYDIR",
32 "IN_DONT_FOLLOW",
33 "IN_MASK_ADD",
34 "IN_ISDIR",
35 "IN_ONESHOT",
36 "IN_ALL_EVENTS",
37 (char *)NULL
39 uint32_t map[] = {
40 IN_ACCESS,
41 IN_MODIFY,
42 IN_ATTRIB,
43 IN_CLOSE_WRITE,
44 IN_CLOSE_NOWRITE,
45 IN_OPEN,
46 IN_MOVED_FROM,
47 IN_MOVED_TO,
48 IN_CREATE,
49 IN_DELETE,
50 IN_DELETE_SELF,
51 IN_MOVE_SELF,
52 IN_CLOSE,
53 IN_MOVE,
54 IN_ONLYDIR,
55 IN_DONT_FOLLOW,
56 IN_MASK_ADD,
57 IN_ISDIR,
58 IN_ONESHOT,
59 IN_ALL_EVENTS
62 TEST_OK(Tcl_ListObjGetElements(interp, list, &objc, &objv));
64 for (i=0; i<objc; i++) {
65 TEST_OK(Tcl_GetIndexFromObj(interp, objv[i], mask_bits, "mask bit",
66 TCL_EXACT, &index));
67 build |= map[index];
70 *mask = build;
72 return TCL_OK;
75 //>>>
76 static Tcl_Obj *mask2list(uint32_t mask) //<<<
78 Tcl_Obj *result = Tcl_NewListObj(0, NULL);
80 #define CHECK_BIT(bit, str) \
81 if ((mask & bit) == bit) \
82 Tcl_ListObjAppendElement(NULL, result, Tcl_NewStringObj(str, -1));
84 CHECK_BIT(IN_ACCESS, "IN_ACCESS");
85 CHECK_BIT(IN_ATTRIB, "IN_ATTRIB");
86 CHECK_BIT(IN_CLOSE_WRITE, "IN_CLOSE_WRITE");
87 CHECK_BIT(IN_CLOSE_NOWRITE, "IN_CLOSE_NOWRITE");
88 CHECK_BIT(IN_CREATE, "IN_CREATE");
89 CHECK_BIT(IN_DELETE, "IN_DELETE");
90 CHECK_BIT(IN_DELETE_SELF, "IN_DELETE_SELF");
91 CHECK_BIT(IN_MODIFY, "IN_MODIFY");
92 CHECK_BIT(IN_MOVE_SELF, "IN_MOVE_SELF");
93 CHECK_BIT(IN_MOVED_FROM, "IN_MOVED_FROM");
94 CHECK_BIT(IN_MOVED_TO, "IN_MOVED_TO");
95 CHECK_BIT(IN_OPEN, "IN_OPEN");
96 CHECK_BIT(IN_IGNORED, "IN_IGNORED");
97 CHECK_BIT(IN_ISDIR, "IN_ISDIR");
98 CHECK_BIT(IN_Q_OVERFLOW, "IN_Q_OVERFLOW");
99 CHECK_BIT(IN_UNMOUNT, "IN_UNMOUNT");
101 return result;
104 //>>>
105 static int glue_create_queue(cdata, interp, objc, objv) //<<<
106 ClientData cdata;
107 Tcl_Interp *interp;
108 int objc;
109 Tcl_Obj *CONST objv[];
111 const char *channel_name;
112 Tcl_Channel channel;
113 int queue_fd;
115 CHECK_ARGS(0, "");
117 queue_fd = inotify_init();
118 channel = Tcl_MakeFileChannel((ClientData)queue_fd, TCL_READABLE);
119 Tcl_RegisterChannel(interp, channel);
120 channel_name = Tcl_GetChannelName(channel);
122 Tcl_SetObjResult(interp, Tcl_NewStringObj(channel_name, -1));
124 return TCL_OK;
127 //>>>
128 static int get_queue_fd_from_chan(interp, handle, queue_fd) //<<<
129 Tcl_Interp *interp;
130 Tcl_Obj *handle;
131 int *queue_fd;
133 Tcl_Channel channel;
134 int chan_mode;
136 channel = Tcl_GetChannel(interp, Tcl_GetString(handle), &chan_mode);
137 if (channel == NULL)
138 THROW_ERROR("Invalid queue handle: ", Tcl_GetString(handle));
140 if ((chan_mode & TCL_READABLE) != TCL_READABLE)
141 THROW_ERROR("Queue exists, but is not readable. Wierd, man");
143 if (Tcl_GetChannelHandle(channel, TCL_READABLE, (ClientData *)queue_fd) != TCL_OK) {
144 THROW_ERROR("Couldn't retrieve queue fd from channel");
147 return TCL_OK;
150 //>>>
151 static int glue_add_watch(cdata, interp, objc, objv) //<<<
152 ClientData cdata;
153 Tcl_Interp *interp;
154 int objc;
155 Tcl_Obj *CONST objv[];
157 int queue_fd, wd, is_new;
158 uint32_t mask;
159 const char *path;
161 CHECK_ARGS(3, "queue path mask");
163 TEST_OK(get_queue_fd_from_chan(interp, objv[1], &queue_fd));
164 path = Tcl_GetString(objv[2]);
165 TEST_OK(list2mask(interp, objv[3], &mask));
167 wd = inotify_add_watch(queue_fd, path, mask);
168 if (wd == -1)
169 THROW_ERROR("Problem creating watch on ", path);
171 Tcl_SetObjResult(interp, Tcl_NewIntObj(wd));
173 return TCL_OK;
176 //>>>
177 static int glue_rm_watch(cdata, interp, objc, objv) //<<<
178 ClientData cdata;
179 Tcl_Interp *interp;
180 int objc;
181 Tcl_Obj *CONST objv[];
183 int queue_fd, wd, ret;
185 CHECK_ARGS(2, "queue wd");
187 TEST_OK(get_queue_fd_from_chan(interp, objv[1], &queue_fd));
188 TEST_OK(Tcl_GetIntFromObj(interp, objv[2], &wd));
190 ret = inotify_rm_watch(queue_fd, wd);
192 Tcl_SetObjResult(interp, Tcl_NewIntObj(ret));
194 return TCL_OK;
197 //>>>
198 static int glue_decode_events(cdata, interp, objc, objv) //<<<
199 ClientData cdata;
200 Tcl_Interp *interp;
201 int objc;
202 Tcl_Obj *CONST objv[];
204 unsigned char *raw;
205 int raw_len, remaining, eventsize, offset;
206 struct inotify_event *event;
207 Tcl_Obj *result;
209 CHECK_ARGS(1, "raw_event_data");
211 raw = Tcl_GetByteArrayFromObj(objv[1], &raw_len);
213 offset = 0;
214 remaining = raw_len;
215 event = (struct inotify_event *)(raw + offset);
217 result = Tcl_NewListObj(0, NULL);
219 while (remaining > 0) {
220 Tcl_Obj *evdata = Tcl_NewListObj(0, NULL);
222 eventsize = sizeof(struct inotify_event) + event->len;
223 remaining -= eventsize;
224 offset += eventsize;
226 #define ADD_ELEM(elem) \
227 TEST_OK(Tcl_ListObjAppendElement(interp, evdata, elem));
229 ADD_ELEM(Tcl_NewIntObj(event->wd));
230 ADD_ELEM(mask2list(event->mask));
231 ADD_ELEM(Tcl_NewIntObj(event->cookie));
232 //ADD_ELEM(Tcl_NewIntObj(event->len));
233 if (event->len > 0) {
234 // Why not give event->len as the length? len includes null padding
235 ADD_ELEM(Tcl_NewStringObj(event->name, -1));
236 } else {
237 ADD_ELEM(Tcl_NewStringObj("", 0));
240 TEST_OK(Tcl_ListObjAppendElement(interp, result, evdata));
242 event = (struct inotify_event *)(raw + offset);
245 Tcl_SetObjResult(interp, result);
247 return TCL_OK;
250 //>>>
251 int Inotify_Init(Tcl_Interp *interp) //<<<
253 if (Tcl_InitStubs(interp, "8.1", 0) == NULL)
254 return TCL_ERROR;
256 if (sizeof(ClientData) < sizeof(int))
257 THROW_ERROR("On this platform ints are bigger than pointers. That freaks us out, sorry");
259 NEW_CMD("inotify::create_queue", glue_create_queue);
260 NEW_CMD("inotify::add_watch", glue_add_watch);
261 NEW_CMD("inotify::rm_watch", glue_rm_watch);
262 NEW_CMD("inotify::decode_events", glue_decode_events);
264 return TCL_OK;
267 //>>>
268 // vim: foldmethod=marker foldmarker=<<<,>>>