Initial snarf.
[shack.git] / libmojave / cutil / lm_notify.c
blob5411b903392116802966c1d834c8e2462a4c2cc9
1 /*
2 * File-change notification.
4 * ----------------------------------------------------------------
6 * @begin[license]
7 * Copyright (C) 2004 Mojave Group, Caltech
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation,
12 * version 2.1 of the License.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 * Additional permission is given to link this library with the
24 * OpenSSL project's "OpenSSL" library, and with the OCaml runtime,
25 * and you may distribute the linked executables. See the file
26 * LICENSE.libmojave for more details.
28 * Author: Jason Hickey
29 * @email{jyh@cs.caltech.edu}
30 * @end[license]
32 #include <stdio.h>
33 #include <caml/mlvalues.h>
34 #include <caml/alloc.h>
35 #include <caml/memory.h>
36 #include <caml/fail.h>
37 #include <caml/custom.h>
38 #include <caml/signals.h>
40 #ifdef FAM_ENABLED
42 #ifdef WIN32
43 #include <windows.h>
44 /* Disable some of the warnings */
45 #pragma warning( disable : 4100 4189 4127 4702 4996 )
46 #endif /* WIN32 */
48 #ifdef FAM_PSEUDO
49 #include "fam_pseudo.h"
50 #else /* FAM_PSEUDO */
51 #include <fam.h>
52 #include <stdlib.h>
53 #include <unistd.h>
54 #include <sys/stat.h>
55 #include <sys/select.h>
56 #endif /* FAM_PSEUDO */
59 * Custom blocks.
61 typedef struct {
62 FAMConnection *fc;
63 int is_open;
64 } FAMInfo;
66 #define FAMInfo_val(v) ((FAMInfo *) Data_custom_val(v))
67 #define FAMConnection_val(v) ((FAMInfo_val(v)->fc))
69 #ifdef HAVE_SNPRINTF
70 #define ErrFmt(buffer, fmt) snprintf(buffer, sizeof(buffer), fmt, FamErrlist[FAMErrno])
71 #else
72 #define ErrFmt(buffer, fmt) sprintf(buffer, fmt, FamErrlist[FAMErrno])
73 #endif
75 #define CheckCode(fmt, expr) \
76 enter_blocking_section(); \
77 code = expr; \
78 leave_blocking_section(); \
79 if(code < 0) { \
80 char buffer[256]; \
81 ErrFmt(buffer, fmt); \
82 failwith(buffer); \
85 static int fam_connection_compare(value v1, value v2)
87 FAMConnection *info1 = FAMConnection_val(v1);
88 FAMConnection *info2 = FAMConnection_val(v2);
90 #ifdef FAM_PSEUDO
91 return info1->id == info2->id ? 0 : info1->id < info2->id ? -1 : 1;
92 #else /* FAM_PSEUDO */
93 return info1->fd == info2->fd ? 0 : info1->fd < info2->fd ? -1 : 1;
94 #endif /* !FAM_PSEUDO */
97 static long fam_connection_hash(value v)
99 return (long) FAMConnection_val(v);
102 static void fam_connection_finalize(value v_info)
104 FAMInfo *info;
106 info = FAMInfo_val(v_info);
107 if(info->is_open) {
108 FAMClose(info->fc);
109 free(info->fc);
110 info->is_open = 0;
115 * Pass info in a custom block.
117 static struct custom_operations fam_connection_ops = {
118 "fam_connection",
119 fam_connection_finalize,
120 fam_connection_compare,
121 fam_connection_hash,
122 custom_serialize_default,
123 custom_deserialize_default
127 * Is this module enabled?
129 value om_notify_enabled(value v_unit)
131 return Val_true;
135 * Open the FAM connection.
137 value om_notify_open(value v_unit)
139 CAMLparam1(v_unit);
140 CAMLlocal1(v);
141 FAMConnection *fc;
142 FAMInfo *info;
143 int code;
145 v = alloc_custom(&fam_connection_ops, sizeof(FAMInfo), 0, 1);
146 info = FAMInfo_val(v);
147 fc = malloc(sizeof(FAMConnection));
148 if(fc == 0)
149 invalid_argument("om_notify_open: out of memory");
150 info->fc = fc;
151 CheckCode("om_notify_open: %s", FAMOpen(fc));
152 #ifdef HAVE_FAMNOEXISTS
153 CheckCode("om_notify_open: FAMNoExists: %s", FAMNoExists(fc));
154 #endif /* HAVE_FAMNOEXISTS */
155 info->is_open = 1;
156 CAMLreturn(v);
160 * Close the FAM connection.
162 value om_notify_close(value v_fc)
164 fam_connection_finalize(v_fc);
165 return Val_unit;
169 * Get the file descriptor.
171 value om_notify_fd(value v_fc)
173 #ifdef FAM_PSEUDO
174 #ifdef FAM_INOTIFY
175 FAMConnection *fc;
177 fc = FAMConnection_val(v_fc);
178 return Val_int(fc->id);
179 #else /* FAM_PSEUDO && !FAM_INOTIFY */
180 failwith("No file descriptors in pseudo-FAM");
181 return Val_unit;
182 #endif /* FAM_INOTIFY */
183 #else /* FAM_PSEUDO */
184 FAMConnection *fc;
186 fc = FAMConnection_val(v_fc);
187 return Val_int(FAMCONNECTION_GETFD(fc));
188 #endif /* FAM_PSEUDO */
192 * Monitor a directory.
194 value om_notify_monitor_directory(value v_fc, value v_name, value v_recursive)
196 CAMLparam3(v_fc, v_name, v_recursive);
197 const char *name;
198 FAMConnection *fc;
199 FAMRequest request;
200 int code, recursive;
202 fc = FAMConnection_val(v_fc);
203 name = String_val(v_name);
204 recursive = Int_val(v_recursive);
205 if(recursive) {
206 #ifdef WIN32
207 code = FAMMonitorDirectoryTree(fc, name, &request, 0);
208 #else /* WIN32 */
209 failwith("om_notify_monitor_directory: recursive monitoring is not allowed");
210 #endif /* !WIN32 */
212 else
213 code = FAMMonitorDirectory(fc, name, &request, 0);
214 CheckCode("om_notify_monitor_directory: %s", code);
215 CAMLreturn(Val_int(request.reqnum));
219 * Suspend the monitor.
221 value om_notify_suspend(value v_fc, value v_request)
223 CAMLparam2(v_fc, v_request);
224 FAMConnection *fc;
225 FAMRequest request;
226 int code;
228 fc = FAMConnection_val(v_fc);
229 request.reqnum = Int_val(v_request);
230 CheckCode("om_notify_suspend: %s", FAMSuspendMonitor(fc, &request));
231 CAMLreturn(Val_unit);
235 * Resume the monitor.
237 value om_notify_resume(value v_fc, value v_request)
239 CAMLparam2(v_fc, v_request);
240 FAMConnection *fc;
241 FAMRequest request;
242 int code;
244 fc = FAMConnection_val(v_fc);
245 request.reqnum = Int_val(v_request);
246 CheckCode("om_notify_resume: %s", FAMResumeMonitor(fc, &request));
247 CAMLreturn(Val_unit);
251 * Cancel the monitor.
253 value om_notify_cancel(value v_fc, value v_request)
255 CAMLparam2(v_fc, v_request);
256 FAMConnection *fc;
257 FAMRequest request;
258 int code;
260 fc = FAMConnection_val(v_fc);
261 request.reqnum = Int_val(v_request);
262 CheckCode("om_notify_cancel: %s", FAMCancelMonitor(fc, &request));
263 CAMLreturn(Val_unit);
267 * Check for a pending event.
269 value om_notify_pending(value v_fc)
271 CAMLparam1(v_fc);
272 FAMConnection *fc;
273 int code;
275 fc = FAMConnection_val(v_fc);
276 CheckCode("om_notify_pending: %s", FAMPending(fc));
277 CAMLreturn(code ? Val_true : Val_false);
281 * Get the next event.
283 value om_notify_next_event(value v_fc)
285 CAMLparam1(v_fc);
286 CAMLlocal2(v_name, v_tuple);
287 FAMConnection *fc;
288 FAMEvent event;
289 int code;
291 fc = FAMConnection_val(v_fc);
292 CheckCode("om_notify_next_event: %s", FAMNextEvent(fc, &event));
293 code = event.code;
294 if(code < 1 || code > 10)
295 failwith("om_notify_next_event: code out of bounds");
297 /* Allocate the string name */
298 v_name = copy_string(event.filename);
300 /* Allocate the tuple */
301 v_tuple = alloc_tuple(3);
302 Field(v_tuple, 0) = Val_int(event.fr.reqnum);
303 Field(v_tuple, 1) = v_name;
304 Field(v_tuple, 2) = Val_int(code - 1);
305 CAMLreturn(v_tuple);
308 #else /* FAM_ENABLED */
311 * Is this module enabled?
313 value om_notify_enabled(value v_unit)
315 return Val_false;
319 * Open the FAM connection.
321 value om_notify_open(value v_unit)
323 return Val_unit;
327 * Get the file descriptor.
329 value om_notify_fd(value v_fc)
331 invalid_argument("FAM not enabled");
332 return Val_unit;
336 * Close the FAM connection.
338 value om_notify_close(value v_fc)
340 return Val_unit;
344 * Monitor a directory.
346 value om_notify_monitor_directory(value v_fc, value v_name, value v_recursive)
348 return Val_int(0);
352 * Suspend the monitor.
354 value om_notify_suspend(value v_fc, value v_request)
356 return Val_unit;
361 * Suspend the monitor.
363 value om_notify_resume(value v_fc, value v_request)
365 return Val_unit;
370 * Suspend the monitor.
372 value om_notify_cancel(value v_fc, value v_request)
374 return Val_unit;
378 * Check for a pending event.
380 value om_notify_pending(value v_fc)
382 return Val_false;
386 * Get the next event.
388 value om_notify_next_event(value v_fc)
390 invalid_argument("FAM not enabled");
391 return Val_unit;
394 #endif /* !FAM_ENABLED */