ca02712015-05-19Martin Nilsson /* -*- c -*- || This file is part of Pike. For copyright information see COPYRIGHT. || Pike is distributed under GPL, LGPL and MPL. See the file COPYING || for more information. */
f51d422012-07-25Bill Welliver /*! @module System */ /*! @module Wnotify *!
13670c2015-05-25Martin Nilsson  *! An interface to Windows filesystem change information.
f51d422012-07-25Bill Welliver  *! */ #include "global.h" #include "interpret.h" #include "module.h" #include "program.h" #include "stralloc.h" #include "svalue.h" #include "threads.h" #include "object.h" #include "pike_types.h" #include "builtin_functions.h" #include "wnotify_config.h" #define ADD_ICONST(name) do { \ add_integer_constant(#name, name, 0); \ } while(0); #ifdef HAVE_FILEAPI_H #include <FileAPI.h> #endif /* HAVE_FILEAPI_H */ #ifdef HAVE_WINBASE_H
a87c632014-10-10Henrik Grubbström (Grubba) #include <WinBase.h>
f51d422012-07-25Bill Welliver #endif /* HAVE_WINBASE_H */ #ifndef MAX_LEN #define MAX_LEN 255 #endif /* !MAX_LEN */ DECLARATIONS #ifdef HAVE_FINDFIRSTCHANGENOTIFICATION /*! @class NotificationHandle */ PIKECLASS NotificationHandle { CVAR HANDLE handle; PIKEVAR string path; PIKEVAR int watch_subtree; PIKEVAR int filter; PIKEVAR int triggered;
126fa42013-04-03Henrik Grubbström (Grubba) /*! @decl void create(string path, int watch_subtree, int filter)
f51d422012-07-25Bill Welliver  */ PIKEFUN void create(string path, int watch_subtree, int filter) { HANDLE h; THIS->path = path; add_ref(path); THIS->watch_subtree = watch_subtree; THIS->filter = filter;
c745692015-11-08Martin Nilsson 
f51d422012-07-25Bill Welliver  if(string_has_null(path)) Pike_error("NotificationHandle: path cannot contain null.\n");
c745692015-11-08Martin Nilsson  if(path->size_shift)
f51d422012-07-25Bill Welliver  Pike_error("NotificationHandle: path cannot be a wide string.\n"); if(THIS->path->len > MAX_LEN) Pike_error("NotificationHandle: length of path is too long.\n");
c745692015-11-08Martin Nilsson 
f51d422012-07-25Bill Welliver  h = FindFirstChangeNotification(path->str, (BOOL)THIS->watch_subtree, (DWORD)THIS->filter); if(h == INVALID_HANDLE_VALUE) Pike_error("NotificationHandle: failed to create handle.\n"); else THIS->handle = h; } /*! @decl int get_error() */ PIKEFUN int get_error() {
c745692015-11-08Martin Nilsson  RETURN GetLastError();
f51d422012-07-25Bill Welliver  } PIKEFUN void read_change() {
71f9cf2012-07-25Bill Welliver /*
f51d422012-07-25Bill Welliver  BOOL res;
13670c2015-05-25Martin Nilsson */
f51d422012-07-25Bill Welliver  if(!THIS->triggered) { Pike_error("NotificationHandle.read_change(): no change event triggered.\n"); } /* res = ReadDirectoryChangesW(THIS->handle, ); */ } INIT { } EXIT { if(THIS->path) free_string(THIS->path); if(THIS->handle) FindCloseChangeNotification(THIS->handle); } }
126fa42013-04-03Henrik Grubbström (Grubba) /*! @endclass */
f51d422012-07-25Bill Welliver /*! @class EventPoller */ PIKECLASS EventPoller { /* Do not meddle with this array; it must be kept in sync with the handles array. */ PIKEVAR array phandles flags ID_PRIVATE; CVAR HANDLE * handles; CVAR int handles_size; CVAR int handles_used;
13670c2015-05-25Martin Nilsson  /*! @decl void add_handle(NotificationHandle handle)
f51d422012-07-25Bill Welliver  */ PIKEFUN void add_handle(object handle) { void * h; HANDLE nh;
ca02712015-05-19Martin Nilsson 
cdac262014-12-06Bill Welliver  h = get_storage(handle, Wnotify_NotificationHandle_program);
f51d422012-07-25Bill Welliver  if(!h) Pike_error("add_handle: invalid object type.\n");
8d63182015-05-19Martin Nilsson  THIS->phandles = append_array(THIS->phandles, &Pike_sp[-args]);
cdac262014-12-06Bill Welliver  nh = OBJ2_WNOTIFY_NOTIFICATIONHANDLE(handle)->handle;
f51d422012-07-25Bill Welliver  if(THIS->handles_size <= THIS->handles_used) {
8d63182015-05-19Martin Nilsson  int s = THIS->handles_size || 1; THIS->handles = xrealloc(THIS->handles, sizeof(HANDLE) * s * 2);
f51d422012-07-25Bill Welliver  } THIS->handles[THIS->handles_used++] = nh; }
f87cb92012-07-27Tobias S. Josefowitz  /*! @decl NotificationHandle|int poll(void|float timeout) */
f51d422012-07-25Bill Welliver  PIKEFUN int poll(void|float timeout) { DWORD res; DWORD to; if(THIS->handles_used < 1) Pike_error("poll: no paths to monitor.\n");
cdac262014-12-06Bill Welliver  if(!timeout || SAFE_IS_ZERO(timeout))
f51d422012-07-25Bill Welliver  { to = INFINITE; }
cdac262014-12-06Bill Welliver  else if(TYPEOF(*timeout) == PIKE_T_FLOAT)
f51d422012-07-25Bill Welliver  { to = (DWORD)timeout->u.float_number * 1000; } else { Pike_error("poll: invalid timeout.\n"); } pop_n_elems(args); res = WaitForMultipleObjects(THIS->handles_used, THIS->handles, FALSE, to); if(res >= WAIT_OBJECT_0 && res <= (WAIT_OBJECT_0 + THIS->handles_used - 1)) { /* we have a hit. */ struct svalue * sv; sv = THIS->phandles->item+res; /* TODO: proper value checking of the items in the array! */
cdac262014-12-06Bill Welliver  OBJ2_WNOTIFY_NOTIFICATIONHANDLE(sv->u.object)->triggered = 1;
f51d422012-07-25Bill Welliver  push_svalue(&ITEM(THIS->phandles)[res]); FindNextChangeNotification(THIS->handles+res); } else if(res >= WAIT_ABANDONED_0 && res <= (WAIT_ABANDONED_0 + THIS->handles_used - 1)) { /* don't think this applies to us, so let's flag an exception. */ Pike_error("poll: unexpected result (WAIT_ABANDONED)\n"); } else if(res == WAIT_TIMEOUT) { push_int(0); } } INIT {
c745692015-11-08Martin Nilsson  THIS->phandles = allocate_array(0);
f51d422012-07-25Bill Welliver  } EXIT { if(THIS->handles) free(THIS->handles); if(THIS->phandles) free_array(THIS->phandles); } }
126fa42013-04-03Henrik Grubbström (Grubba) /*! @endclass */
f51d422012-07-25Bill Welliver #endif /* HAVE_FINDFIRSTCHANGENOTIFICATION */ PIKE_MODULE_INIT { INIT; /*! @decl constant FILE_NOTIFY_CHANGE_FILE_NAME */ /*! @decl constant FILE_NOTIFY_CHANGE_DIR_NAME */ /*! @decl constant FILE_NOTIFY_CHANGE_ATTRIBUTES */ /*! @decl constant FILE_NOTIFY_CHANGE_SIZE */ /*! @decl constant FILE_NOTIFY_CHANGE_LAST_WRITE */ /*! @decl constant FILE_NOTIFY_CHANGE_SECURITY */ #ifdef HAVE_FINDFIRSTCHANGENOTIFICATION ADD_ICONST(FILE_NOTIFY_CHANGE_FILE_NAME); ADD_ICONST(FILE_NOTIFY_CHANGE_DIR_NAME); ADD_ICONST(FILE_NOTIFY_CHANGE_ATTRIBUTES); ADD_ICONST(FILE_NOTIFY_CHANGE_SIZE); ADD_ICONST(FILE_NOTIFY_CHANGE_LAST_WRITE); ADD_ICONST(FILE_NOTIFY_CHANGE_SECURITY); #endif /* HAVE_FINDFIRSTCHANGENOTIFICATION */ } PIKE_MODULE_EXIT { EXIT; } /*! @endmodule */ /*! @endmodule */