/*! @module System |
*/ |
|
/*! @module Wnotify |
*! |
*! An interface to Windows filesystem change information. |
*! |
*/ |
|
#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_WINDOWS_H |
#include <windows.h> |
#endif /* HAVE_WINDOWS_H */ |
|
#ifdef HAVE_WINBASE_H |
#include <winbase.h> |
#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; |
|
/*! @decl void create(string path, int watch_subtree, int filter) |
*/ |
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; |
if(string_has_null(path)) |
{ |
pop_n_elems(args); |
Pike_error("NotificationHandle: path cannot contain null.\n"); |
} |
if((1 << path->size_shift)>1) |
{ |
pop_n_elems(args); |
Pike_error("NotificationHandle: path cannot be a wide string.\n"); |
} |
if(THIS->path->len > MAX_LEN) |
{ |
pop_n_elems(args); |
Pike_error("NotificationHandle: length of path is too long.\n"); |
} |
h = FindFirstChangeNotification(path->str, (BOOL)THIS->watch_subtree, (DWORD)THIS->filter); |
if(h == INVALID_HANDLE_VALUE) |
{ |
pop_n_elems(args); |
Pike_error("NotificationHandle: failed to create handle.\n"); |
} |
else |
THIS->handle = h; |
pop_n_elems(args); |
return; |
} |
|
/*! @decl int get_error() |
*/ |
PIKEFUN int get_error() |
{ |
DWORD e; |
|
e = GetLastError(); |
|
push_int(e); |
} |
|
PIKEFUN void read_change() |
{ |
/* |
BOOL res; |
*/ |
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); |
} |
} |
|
/*! @endclass */ |
|
/*! @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; |
|
/*! @decl void add_handle(NotificationHandle handle) |
*/ |
PIKEFUN void add_handle(object handle) |
{ |
void * h; |
int s, n; |
struct array * ph; |
HANDLE nh; |
HANDLE * handles; |
h = get_storage(handle, NotificationHandle_program); |
if(!h) |
{ |
pop_stack(); |
Pike_error("add_handle: invalid object type.\n"); |
} |
|
ph = append_array(THIS->phandles, &Pike_sp[-args]); |
THIS->phandles = ph; |
nh = OBJ2_NOTIFICATIONHANDLE(handle)->handle; |
|
if(THIS->handles_size <= THIS->handles_used) |
{ |
s = n = THIS->handles_size || 1; |
s*=2; |
handles = realloc(THIS->handles, sizeof(HANDLE) * s); |
if(!handles) |
{ |
pop_stack(); |
Pike_error("add_handle: failed to allocate memory.\n"); |
} |
|
THIS->handles = handles; |
} |
|
THIS->handles[THIS->handles_used++] = nh; |
|
pop_stack(); |
} |
|
/*! @decl NotificationHandle|int poll(void|float timeout) |
*/ |
PIKEFUN int poll(void|float timeout) |
{ |
DWORD res; |
DWORD to; |
|
if(THIS->handles_used < 1) |
{ |
pop_stack(); |
Pike_error("poll: no paths to monitor.\n"); |
} |
|
if(!timeout || (timeout->type == PIKE_T_INT && timeout->u.integer == 0)) |
{ |
to = INFINITE; |
} |
else if(timeout->type == PIKE_T_FLOAT) |
{ |
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! */ |
OBJ2_NOTIFICATIONHANDLE(sv->u.object)->triggered = 1; |
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 |
{ |
struct array * a; |
a = allocate_array(0); |
THIS->phandles = a; |
} |
|
EXIT |
{ |
if(THIS->handles) |
free(THIS->handles); |
if(THIS->phandles) |
free_array(THIS->phandles); |
} |
} |
|
/*! @endclass */ |
|
#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 |
*/ |
|