/*
* This file is part of Python FAM.
* Copyright (C) 2002 Robert Sander <robert.sander@epigenomics.com>
* Copyright (C) 2005 Martin v. Loewis
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* $Id: _fam.c,v 1.14 2005/04/10 07:48:45 loewis Exp $
*
*/
#include <Python.h>
#include <structmember.h>
#include <fam.h>
#include "_fam.h"
#define PY22 0x020200F0
// #define _DEBUG 1
#define add_int(d, name) \
{ \
PyObject *i = PyInt_FromLong(FAM##name); \
PyDict_SetItemString( d, #name, i ); \
Py_DECREF(i); \
}
char* code2str(int code) {
char* rv;
switch (code) {
case FAMExists:
rv = "exists";
break;
case FAMEndExist:
rv = "endExist";
break;
case FAMChanged:
rv = "changed";
break;
case FAMDeleted:
rv = "deleted";
break;
case FAMStartExecuting:
rv = "started executing";
break;
case FAMStopExecuting:
rv = "stopped executing";
break;
case FAMCreated:
rv = "created";
break;
case FAMMoved:
rv = "moved";
break;
case FAMAcknowledge:
rv = "acknowleged";
break;
default:
rv = NULL;
}
return rv;
}
/*
* FAMConnection object definitions
*
* The Connection object is returned by the open() method of the module.
* It implements FAMClose(), FAMMonitorDirectory(), FAMMonitorFile(),
* FAMNextEvent() and FAMPending().
*
*/
typedef struct {
PyObject_HEAD
FAMConnection *fc;
} _fam_connection_object;
static PyMethodDef _fam_connection_methods[] = {
{ "close", _fam_close, 1, _fam_close__doc__},
{ "monitorDirectory", _fam_monitor_directory, 1, _fam_monitor_directory__doc__},
{ "monitorFile", _fam_monitor_file, 1, _fam_monitor_file__doc__},
{ "nextEvent", _fam_next_event, 1, _fam_next_event__doc__},
{ "pending", _fam_pending, 1, _fam_pending__doc__},
{ "fileno", _fam_fileno, 1, _fam_fileno__doc__},
{ NULL, NULL, 0, NULL}
};
#if PY_VERSION_HEX < PY22
static PyObject* _fam_connection_getattr(PyObject* self, char* name) {
#ifdef _DEBUG
fprintf(stderr, "_fam: getting attribute %s from connection object.\n", name);
#endif
return Py_FindMethod(_fam_connection_methods, self, name);
}
#endif
void _fam_connection_del(PyObject* self) {
#ifdef _DEBUG
fprintf(stderr, "_fam: deleting connection object.\n");
#endif
_fam_close(self, NULL);
PyMem_DEL(self);
}
static PyTypeObject _fam_connection_type = {
#if defined(WIN32) || defined(__CYGWIN__)
PyObject_HEAD_INIT(NULL)
#else
PyObject_HEAD_INIT(&PyType_Type)
#endif
0, /* ob_size */
"_fam.FAMConnection", /* tp_name */
sizeof(_fam_connection_object), /* tp_basicsize */
0, /* tp_itemsize */
_fam_connection_del, /* tp_dealloc */
0, /* tp_print */
#if PY_VERSION_HEX < PY22
_fam_connection_getattr, /* tp_getattr */
#else
0, /* tp_getattr */
#endif
0, /* tp_setattr */
0, /* tp_compare */
0, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* call */
0, /* str */
#if PY_VERSION_HEX >= PY22
PyObject_GenericGetAttr, /* tp_getattro */
#else
0, /* tp_getattro */
#endif
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT, /* tp_flags */
_fam_connection_type__doc__, /* doc string */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
#if PY_VERSION_HEX >= PY22
0, /* tp_iter */
0, /* tp_iternext */
_fam_connection_methods, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
0, /* tp_init */
0, /* tp_alloc */
0, /* tp_new */
0, /* tp_free */
0, /* tp_is_gc */
0, /* tp_bases */
0, /* tp_mro */
0, /* tp_cache */
0, /* tp_subclasses */
0, /* tp_weaklist */
#endif
};
/*
* FAMRequest object definitions
*
* A Request object is returned by one of the two monitor methods.
* It implements FAMSuspendMonitor(), FAMResumeMonitor() and
* FAMCancelMonitor()
*
*/
typedef struct {
PyObject_HEAD
_fam_connection_object *fc_obj;
FAMRequest *fr;
} _fam_request_object;
static PyMethodDef _fam_request_methods[] = {
{ "suspendMonitor", _fam_suspend_monitor, 1, _fam_suspend_monitor__doc__},
{ "resumeMonitor", _fam_resume_monitor, 1, _fam_resume_monitor__doc__},
{ "cancelMonitor", _fam_cancel_monitor, 1, _fam_cancel_monitor__doc__},
{ "requestID", _fam_request_id, 1, _fam_request_id__doc__},
{ NULL, NULL, 0, NULL}
};
#if PY_VERSION_HEX < PY22
static PyObject* _fam_request_getattr(PyObject* self, char* name) {
#ifdef _DEBUG
fprintf(stderr, "_fam: getting attribute %s from request object.\n", name);
#endif
return Py_FindMethod(_fam_request_methods, self, name);
}
#endif
void _fam_request_del(PyObject* self) {
#ifdef _DEBUG
fprintf(stderr, "_fam: deleting request object.\n");
#endif
_fam_cancel_monitor(self, NULL);
PyMem_DEL(self);
}
static PyTypeObject _fam_request_type = {
#if defined(WIN32) || defined(__CYGWIN__)
PyObject_HEAD_INIT(NULL)
#else
PyObject_HEAD_INIT(&PyType_Type)
#endif
0, /* ob_size */
"_fam.FAMRequest", /* tp_name */
sizeof(_fam_request_object), /* tp_basicsize */
0, /* tp_itemsize */
_fam_request_del, /* tp_dealloc */
0, /* tp_print */
#if PY_VERSION_HEX < PY22
_fam_request_getattr, /* tp_getattr */
#else
0, /* tp_getattr */
#endif
0, /* tp_setattr */
0, /* tp_compare */
0, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* call */
0, /* str */
#if PY_VERSION_HEX >= PY22
PyObject_GenericGetAttr, /* tp_getattro */
#else
0, /* tp_getattro */
#endif
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT, /* tp_flags */
_fam_request_type__doc__, /* doc string */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
#if PY_VERSION_HEX >= PY22
0, /* tp_iter */
0, /* tp_iternext */
_fam_request_methods, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
0, /* tp_init */
0, /* tp_alloc */
0, /* tp_new */
0, /* tp_free */
0, /* tp_is_gc */
0, /* tp_bases */
0, /* tp_mro */
0, /* tp_cache */
0, /* tp_subclasses */
0, /* tp_weaklist */
#endif
};
/*
* FAMEvent object definitions
*
* An Event object is returned by the nextEvent method.
* It implements the code2str() method and has
* the attributes connection, requestID, hostname,
* filename, userData and code.
*
*/
typedef struct {
PyObject_HEAD
PyObject *attr;
_fam_connection_object *fc_obj;
enum FAMCodes code;
} _fam_event_object;
static PyMethodDef _fam_event_methods[] = {
{ "code2str", _fam_code2str, 1, _fam_code2str__doc__},
{ NULL, NULL, 0, NULL}
};
#if PY_VERSION_HEX >= PY22
static PyMemberDef _fam_event_members[] = {
{ "__dict__", T_OBJECT, offsetof(_fam_event_object, attr), READONLY, 0},
{ NULL, 0, 0, 0, NULL}
};
#endif
#if PY_VERSION_HEX < PY22
static PyObject* _fam_event_getattr(PyObject* self, char* name) {
_fam_event_object *fe_obj;
PyObject *v;
fe_obj = (_fam_event_object *)self;
if (fe_obj->attr) {
v = PyDict_GetItemString(fe_obj->attr, name);
if (v) {
Py_INCREF(v);
return v;
}
}
return Py_FindMethod(_fam_event_methods, self, name);
}
static int _fam_event_setattr(PyObject* self, char* name, PyObject* v) {
_fam_event_object *fe_obj = (_fam_event_object *)self;
if (! fe_obj->attr) {
fe_obj->attr = PyDict_New();
if (! fe_obj->attr)
return -1;
}
if (! v) {
int rv = PyDict_DelItemString(fe_obj->attr, name);
if (rv < 0)
PyErr_SetString(PyExc_AttributeError, "delete non-existing FAMEvent attribute");
return rv;
} else
return PyDict_SetItemString(fe_obj->attr, name, v);
}
#endif
void _fam_event_del(PyObject* self) {
_fam_event_object *fe_obj = (_fam_event_object *)self;
#ifdef _DEBUG
fprintf(stderr, "_fam: deleting event object.\n");
#endif
if (fe_obj) {
if (fe_obj->fc_obj) {
Py_DECREF(fe_obj->fc_obj);
fe_obj->fc_obj = NULL;
}
Py_XDECREF(fe_obj->attr);
PyMem_DEL(fe_obj);
}
}
static PyTypeObject _fam_event_type = {
#if defined(WIN32) || defined(__CYGWIN__)
PyObject_HEAD_INIT(NULL)
#else
PyObject_HEAD_INIT(&PyType_Type)
#endif
0, /* ob_size */
"_fam.FAMEvent", /* tp_name */
sizeof(_fam_event_object), /* tp_basicsize */
0, /* tp_itemsize */
_fam_event_del, /* tp_dealloc */
0, /* tp_print */
#if PY_VERSION_HEX < PY22
_fam_event_getattr, /* tp_getattr */
_fam_event_setattr, /* tp_setattr */
#else
0, /* tp_getattr */
0, /* tp_setattr */
#endif
0, /* tp_compare */
0, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* call */
0, /* str */
#if PY_VERSION_HEX >= PY22
PyObject_GenericGetAttr, /* tp_getattro */
PyObject_GenericSetAttr, /* tp_setattro */
#else
0, /* tp_getattro */
0, /* tp_setattro */
#endif
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT, /* tp_flags */
_fam_event_type__doc__, /* doc string */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
#if PY_VERSION_HEX >= PY22
0, /* tp_iter */
0, /* tp_iternext */
_fam_event_methods, /* tp_methods */
_fam_event_members, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
offsetof(_fam_event_object, attr), /* tp_dictoffset */
0, /* tp_init */
0, /* tp_alloc */
0, /* tp_new */
0, /* tp_free */
0, /* tp_is_gc */
0, /* tp_bases */
0, /* tp_mro */
0, /* tp_cache */
0, /* tp_subclasses */
0, /* tp_weaklist */
#endif
};
/*
* The method definitions.
*
*/
static PyObject* _fam_open(PyObject* self, PyObject* args) {
int rc;
_fam_connection_object *fc_obj = PyObject_NEW(_fam_connection_object, &_fam_connection_type);
if (!fc_obj)
return NULL;
fc_obj->fc = (FAMConnection *)malloc(sizeof(FAMConnection));
if (!fc_obj->fc) {
PyErr_SetString(PyExc_MemoryError, "_fam: unable to malloc for connection");
return NULL;
}
rc = FAMOpen(fc_obj->fc);
if (!rc) {
return (PyObject*)fc_obj;
} else {
PyErr_SetString(PyExc_IOError, "_fam: unable to open connection");
return NULL;
}
};
static PyObject* _fam_close(PyObject* self, PyObject* args) {
int rc;
_fam_connection_object *fc_obj = (_fam_connection_object *)self;
if (fc_obj->fc) {
rc = FAMClose(fc_obj->fc);
free(fc_obj->fc);
fc_obj->fc = NULL;
if (!rc) {
#ifdef _DEBUG
fprintf(stderr, "_fam: closed connection.\n");
#endif
} else {
PyErr_SetString(PyExc_IOError, "_fam: unable to close connection");
return NULL;
}
} else {
#ifdef _DEBUG
fprintf(stderr, "_fam: no connection to close.\n");
#endif
}
Py_INCREF(Py_None);
return Py_None;
};
static PyObject* _fam_monitor_directory(PyObject* self, PyObject* args) {
int rc;
char *filename;
PyObject *userData;
_fam_connection_object *fc_obj;
_fam_request_object *fr_obj;
fc_obj = (_fam_connection_object *)self;
if (fc_obj->fc) {
if (!PyArg_ParseTuple(args, "sO", &filename, &userData))
return NULL;
fr_obj = PyObject_NEW(_fam_request_object, &_fam_request_type);
if (!fr_obj)
return NULL;
fr_obj->fc_obj = fc_obj;
Py_INCREF(fc_obj);
fr_obj->fr = (FAMRequest *)malloc(sizeof(FAMRequest));
if (!fr_obj->fr) {
PyErr_SetString(PyExc_MemoryError, "_fam: unable to malloc for request");
return NULL;
}
rc = FAMMonitorDirectory(fc_obj->fc,
filename,
fr_obj->fr,
(void *)userData);
if (!rc) {
Py_INCREF(userData);
return (PyObject*)fr_obj;
} else {
PyErr_SetString(PyExc_IOError, "_fam: unable to monitor directory");
return NULL;
}
} else {
PyErr_SetString(PyExc_RuntimeError, "_fam: no connection to monitor");
return NULL;
}
};
static PyObject* _fam_monitor_file(PyObject* self, PyObject* args) {
int rc;
char *filename;
PyObject *userData;
_fam_connection_object *fc_obj;
_fam_request_object *fr_obj;
fc_obj = (_fam_connection_object *)self;
if (fc_obj->fc) {
if (!PyArg_ParseTuple(args, "sO", &filename, &userData))
return NULL;
fr_obj = PyObject_NEW(_fam_request_object, &_fam_request_type);
if (!fr_obj)
return NULL;
fr_obj->fc_obj = fc_obj;
Py_INCREF(fc_obj);
fr_obj->fr = (FAMRequest *)malloc(sizeof(FAMRequest));
if (!fr_obj->fr) {
PyErr_SetString(PyExc_MemoryError, "_fam: unable to malloc for request");
return NULL;
}
rc = FAMMonitorFile(fc_obj->fc, filename, fr_obj->fr, (void *)userData);
if (!rc) {
Py_INCREF(userData);
return (PyObject*)fr_obj;
} else {
PyErr_SetString(PyExc_IOError, "_fam: unable to monitor file");
return NULL;
}
} else {
PyErr_SetString(PyExc_RuntimeError, "_fam: no connection to monitor");
return NULL;
}
};
static PyObject* _fam_suspend_monitor(PyObject* self, PyObject* args) {
int rc;
_fam_request_object *fr_obj;
fr_obj = (_fam_request_object *)self;
if (fr_obj->fc_obj && fr_obj->fc_obj->fc && fr_obj->fr) {
rc = FAMSuspendMonitor(fr_obj->fc_obj->fc, fr_obj->fr);
if (rc) {
PyErr_SetString(PyExc_RuntimeError, "_fam: unable to suspend monitor");
return NULL;
}
}
Py_INCREF(Py_None);
return Py_None;
};
static PyObject* _fam_resume_monitor(PyObject* self, PyObject* args) {
int rc;
_fam_request_object *fr_obj;
fr_obj = (_fam_request_object *)self;
if (fr_obj->fc_obj && fr_obj->fc_obj->fc && fr_obj->fr) {
rc = FAMResumeMonitor(fr_obj->fc_obj->fc, fr_obj->fr);
if (rc) {
PyErr_SetString(PyExc_RuntimeError, "_fam: unable to resume monitor");
return NULL;
}
}
Py_INCREF(Py_None);
return Py_None;
};
static PyObject* _fam_cancel_monitor(PyObject* self, PyObject* args) {
int rc;
_fam_request_object *fr_obj;
fr_obj = (_fam_request_object *)self;
if (fr_obj->fc_obj && fr_obj->fc_obj->fc && fr_obj->fr) {
rc = FAMCancelMonitor(fr_obj->fc_obj->fc, fr_obj->fr);
free(fr_obj->fr);
fr_obj->fr = NULL;
Py_DECREF(fr_obj->fc_obj);
fr_obj->fc_obj = NULL;
} else {
#ifdef _DEBUG
fprintf(stderr, "_fam: no monitor to cancel.\n");
#endif
}
Py_INCREF(Py_None);
return Py_None;
};
static PyObject* _fam_next_event(PyObject* self, PyObject* args) {
int rc;
_fam_connection_object *fc_obj;
_fam_event_object *fe_obj;
FAMEvent fe;
PyObject *reqid, *hostname, *filename, *userData, *code;
fe.fc = NULL;
fe.hostname = NULL;
fe.userdata = NULL;
fc_obj = (_fam_connection_object *)self;
if (fc_obj->fc) {
fe_obj = PyObject_NEW(_fam_event_object, &_fam_event_type);
if (!fe_obj)
return NULL;
#ifdef _DEBUG
fprintf(stderr, "_fam: got fe_obj.\n");
#endif
fe_obj->attr = NULL;
fe_obj->fc_obj = fc_obj;
Py_INCREF(fc_obj);
rc = FAMNextEvent(fc_obj->fc, &fe);
if (rc == 1) {
if (PyObject_SetAttrString((PyObject*)fe_obj,
"connection",
(PyObject*)fc_obj) < 0)
return NULL;
#ifdef _DEBUG
fprintf(stderr, "_fam: got next event from queue.\n");
#endif
reqid = PyInt_FromLong((long)fe.fr.reqnum);
if (PyObject_SetAttrString((PyObject*)fe_obj, "requestID", reqid) < 0)
return NULL;
#ifdef _DEBUG
fprintf(stderr, "_fam: got request ID.\n");
#endif
filename = PyString_FromString(fe.filename);
if (PyObject_SetAttrString((PyObject*)fe_obj, "filename", filename) < 0)
return NULL;
#ifdef _DEBUG
fprintf(stderr, "_fam: got filename %s.\n", fe.filename);
#endif
userData = (PyObject*)fe.userdata;
if (PyObject_SetAttrString((PyObject*)fe_obj, "userData", userData) < 0)
return NULL;
#ifdef _DEBUG
fprintf(stderr, "_fam: got userdata.\n");
#endif
code = PyInt_FromLong(fe.code);
if (PyObject_SetAttrString((PyObject*)fe_obj, "code", code) < 0)
return NULL;
fe_obj->code = fe.code;
#ifdef _DEBUG
fprintf(stderr, "_fam: got code %d: '%s'.\n", fe.code, code2str(fe.code));
#endif
if (! fe.hostname) {
#ifdef _DEBUG
fprintf(stderr, "_fam: null pointer to hostname.\n");
#endif
fe.hostname = (char*)malloc(255*sizeof(char));
bzero(fe.hostname,255);
#ifdef _DEBUG
} else {
fprintf(stderr, "_fam: valid pointer to hostname %s.\n", fe.hostname);
#endif
}
#ifdef _DEBUG
fprintf(stderr, "_fam: casting hostname to PyString.\n");
#endif
hostname = PyString_FromString(fe.hostname);
#ifdef _DEBUG
fprintf(stderr, "_fam: casted hostname to PyString.\n");
#endif
if (PyObject_SetAttrString((PyObject*)fe_obj, "hostname", hostname) < 0)
return NULL;
#ifdef _DEBUG
fprintf(stderr, "_fam: got hostname.\n");
#endif
return (PyObject*)fe_obj;
} else {
PyErr_SetString(PyExc_IOError, "_fam: unable to get next event");
return NULL;
}
} else {
PyErr_SetString(PyExc_RuntimeError, "_fam: no connection for next event");
return NULL;
}
};
static PyObject* _fam_pending(PyObject* self, PyObject* args) {
PyObject *pyval = Py_False;
_fam_connection_object *fc_obj;
fc_obj = (_fam_connection_object *)self;
if (fc_obj->fc)
pyval = FAMPending(fc_obj->fc) ? Py_True : Py_False;
Py_INCREF(pyval);
return pyval;
};
static PyObject* _fam_code2str(PyObject* self, PyObject* args) {
_fam_event_object *fe_obj;
PyObject *rv;
char *str;
fe_obj = (_fam_event_object *)self;
str = code2str(fe_obj->code);
if (str) {
rv = PyString_FromString(str);
} else {
PyErr_SetString(PyExc_RuntimeError, "_fam: unknown event code");
rv = NULL;
}
return rv;
}
static PyObject* _fam_fileno(PyObject* self, PyObject* args) {
_fam_connection_object *fc_obj;
PyObject *rv;
fc_obj = (_fam_connection_object *)self;
rv = PyInt_FromLong(FAMCONNECTION_GETFD(fc_obj->fc));
if (!rv) {
PyErr_SetString(PyExc_RuntimeError,
"_fam: unable to get file descriptor from connection");
}
return rv;
}
static PyObject* _fam_request_id(PyObject* self, PyObject* args) {
_fam_request_object *fr_obj;
PyObject *rv;
fr_obj = (_fam_request_object *)self;
rv = PyInt_FromLong(FAMREQUEST_GETREQNUM(fr_obj->fr));
if (!rv) {
PyErr_SetString(PyExc_RuntimeError, "_fam: unable to get ID from request");
}
return rv;
}
void _fam_cleanup(void) {
#ifdef _DEBUG
fprintf(stderr, "cleaning up _fam.\n");
#endif
}
static PyMethodDef moduleMethods[] = {
{ "open", _fam_open, 1, _fam_open__doc__},
{ NULL, NULL, 0, NULL}
};
static char _fam__doc__[] = "File Alteration Monitor library routines";
void init_fam(void) {
PyObject *m, *d;
m = Py_InitModule3("_fam",
moduleMethods,
_fam__doc__);
d = PyModule_GetDict(m);
add_int(d, Changed);
add_int(d, Deleted);
add_int(d, StartExecuting);
add_int(d, StopExecuting);
add_int(d, Created);
add_int(d, Moved);
add_int(d, Acknowledge);
add_int(d, Exists);
add_int(d, EndExist);
Py_INCREF(&_fam_connection_type);
PyModule_AddObject(m, "FAMConnection", (PyObject*)&_fam_connection_type);
Py_INCREF(&_fam_request_type);
PyModule_AddObject(m, "FAMRequest", (PyObject*)&_fam_request_type);
Py_INCREF(&_fam_event_type);
PyModule_AddObject(m, "FAMEvent", (PyObject*)&_fam_event_type);
#if defined(WIN32) || defined(__CYGWIN__)
_fam_connection_type.ob_type = &PyType_Type;
_fam_request_type.ob_type = &PyType_Type;
#endif
if (Py_AtExit(_fam_cleanup)) {
fprintf(stderr, "_fam: warining: cleanup procedure not registered.\n");
}
};
syntax highlighted by Code2HTML, v. 0.9.1