diff options
Diffstat (limited to 'plugins/python')
-rw-r--r-- | plugins/python/python.c | 145 |
1 files changed, 121 insertions, 24 deletions
diff --git a/plugins/python/python.c b/plugins/python/python.c index 90dbb22d..7bedcad9 100644 --- a/plugins/python/python.c +++ b/plugins/python/python.c @@ -72,15 +72,32 @@ #include <structmember.h> #include <pythread.h> +/* Macros to convert version macros into string literals. + * The indirect macro is a well-known preprocessor trick to force X to be evaluated before the # operator acts to make it a string literal. + * If STRINGIZE were to be directly defined as #X instead, VERSION would be "VERSION_MAJOR" instead of "1". + */ +#define STRINGIZE2(X) #X +#define STRINGIZE(X) STRINGIZE2(X) + +/* Version number macros */ #define VERSION_MAJOR 1 #define VERSION_MINOR 0 -#if PY_MAJOR_VERSION == 2 +/* Version string macro */ #ifdef WIN32 -#undef WITH_THREAD -#define VERSION "1.0/2.7" /* Linked to python27.dll */ +#if PY_MAJOR_VERSION == 2 +#define VERSION STRINGIZE(VERSION_MAJOR) "." STRINGIZE(VERSION_MINOR) "/2.7" /* Linked to python27.dll */ +#elif PY_MAJOR_VERSION == 3 +#define VERSION STRINGIZE(VERSION_MAJOR) "." STRINGIZE(VERSION_MINOR) "/3.3" /* Linked to python33.dll */ +#endif #endif +#ifndef VERSION +#define VERSION STRINGIZE(VERSION_MAJOR) "." STRINGIZE(VERSION_MINOR) +#endif + +/* #define's for Python 2 */ +#if PY_MAJOR_VERSION == 2 #undef PyLong_Check #define PyLong_Check PyInt_Check #define PyLong_AsLong PyInt_AsLong @@ -95,15 +112,14 @@ #define PyUnicode_FromString PyString_FromString #define PyUnicode_AsUTF8 PyString_AsString -#else -#define IS_PY3K #ifdef WIN32 -#define VERSION "1.0/3.3" /* Linked to python33.dll */ +#undef WITH_THREAD #endif #endif -#ifndef VERSION -#define VERSION "1.0" +/* #define for Python 3 */ +#if PY_MAJOR_VERSION == 3 +#define IS_PY3K #endif #define NONE 0 @@ -269,7 +285,8 @@ static char *Util_Expand(char *filename); static int Callback_Server(char *word[], char *word_eol[], hexchat_event_attrs *attrs, void *userdata); static int Callback_Command(char *word[], char *word_eol[], void *userdata); -static int Callback_Print(char *word[], hexchat_event_attrs *attrs, void *userdata); +static int Callback_Print_Attrs(char *word[], hexchat_event_attrs *attrs, void *userdata); +static int Callback_Print(char *word[], void *userdata); static int Callback_Timer(void *userdata); static int Callback_ThreadTimer(void *userdata); @@ -365,9 +382,6 @@ Usage: /PY LOAD <filename>\n\ ABOUT\n\ \n"; -/* Remove if/when HexChat supports this command for plugins */ -static const char reload[] = "Usage: RELOAD <name>, reloads a python script"; - static const char about[] = "HexChat Python " PY_VERSION " Interface Version " VERSION "\n"; /* ===================================================================== */ @@ -593,10 +607,8 @@ Callback_Command(char *word[], char *word_eol[], void *userdata) return ret; } -/* No Callback_Server() here. We use Callback_Command() as well. */ - static int -Callback_Print(char *word[], hexchat_event_attrs *attrs, void *userdata) +Callback_Print_Attrs(char *word[], hexchat_event_attrs *attrs, void *userdata) { Hook *hook = (Hook *) userdata; PyObject *retobj; @@ -662,12 +674,8 @@ Callback_Print(char *word[], hexchat_event_attrs *attrs, void *userdata) attributes = Attribute_New(attrs); - if (hook->type == HOOK_XCHAT_ATTR) - retobj = PyObject_CallFunction(hook->callback, "(OOOO)", word_list, - word_eol_list, hook->userdata, attributes); - else - retobj = PyObject_CallFunction(hook->callback, "(OOO)", word_list, - word_eol_list, hook->userdata); + retobj = PyObject_CallFunction(hook->callback, "(OOOO)", word_list, + word_eol_list, hook->userdata, attributes); Py_DECREF(word_list); Py_DECREF(word_eol_list); @@ -691,6 +699,94 @@ Callback_Print(char *word[], hexchat_event_attrs *attrs, void *userdata) } static int +Callback_Print(char *word[], void *userdata) +{ + Hook *hook = (Hook *) userdata; + PyObject *retobj; + PyObject *word_list; + PyObject *word_eol_list; + char **word_eol; + char *word_eol_raw; + int listsize = 0; + int next = 0; + int i; + int ret = 0; + PyObject *plugin; + + /* Cut off the message identifier. */ + word += 1; + + /* HexChat doesn't provide a word_eol for print events, so we + * build our own here. */ + while (word[listsize] && word[listsize][0]) + listsize++; + word_eol = (char **) g_malloc(sizeof(char*)*(listsize+1)); + if (word_eol == NULL) { + hexchat_print(ph, "Not enough memory to alloc word_eol " + "for python plugin callback."); + return 0; + } + /* First build a word clone, but NULL terminated. */ + memcpy(word_eol, word, listsize*sizeof(char*)); + word_eol[listsize] = NULL; + /* Then join it. */ + word_eol_raw = g_strjoinv(" ", word_eol); + if (word_eol_raw == NULL) { + hexchat_print(ph, "Not enough memory to alloc word_eol_raw " + "for python plugin callback."); + return 0; + } + /* And rebuild the real word_eol. */ + for (i = 0; i != listsize; i++) { + word_eol[i] = word_eol_raw+next; + next += strlen(word[i])+1; + } + word_eol[i] = ""; + + plugin = hook->plugin; + BEGIN_PLUGIN(plugin); + + word_list = Util_BuildList(word); + if (word_list == NULL) { + g_free(word_eol_raw); + g_free(word_eol); + END_PLUGIN(plugin); + return 0; + } + word_eol_list = Util_BuildList(word_eol); + if (word_eol_list == NULL) { + g_free(word_eol_raw); + g_free(word_eol); + Py_DECREF(word_list); + END_PLUGIN(plugin); + return 0; + } + + + retobj = PyObject_CallFunction(hook->callback, "(OOO)", word_list, + word_eol_list, hook->userdata); + + Py_DECREF(word_list); + Py_DECREF(word_eol_list); + + g_free(word_eol_raw); + g_free(word_eol); + if (retobj == Py_None) { + ret = HEXCHAT_EAT_NONE; + Py_DECREF(retobj); + } else if (retobj) { + ret = PyLong_AsLong(retobj); + Py_DECREF(retobj); + } else { + PyErr_Print(); + } + + END_PLUGIN(plugin); + + return ret; +} + +static int Callback_Timer(void *userdata) { Hook *hook = (Hook *) userdata; @@ -896,6 +992,7 @@ static PyTypeObject XChatOut_Type = { /* ===================================================================== */ /* Attribute object */ +#undef OFF #define OFF(x) offsetof(AttributeObject, x) static PyMemberDef Attribute_members[] = { @@ -2028,7 +2125,7 @@ Module_hexchat_hook_print(PyObject *self, PyObject *args, PyObject *kwargs) return NULL; BEGIN_XCHAT_CALLS(NONE); - hook->data = (void*)hexchat_hook_print_attrs(ph, name, priority, + hook->data = (void*)hexchat_hook_print(ph, name, priority, Callback_Print, hook); END_XCHAT_CALLS(); @@ -2065,7 +2162,7 @@ Module_hexchat_hook_print_attrs(PyObject *self, PyObject *args, PyObject *kwargs BEGIN_XCHAT_CALLS(NONE); hook->data = (void*)hexchat_hook_print_attrs(ph, name, priority, - Callback_Print, hook); + Callback_Print_Attrs, hook); END_XCHAT_CALLS(); return PyLong_FromVoidPtr(hook); @@ -2755,7 +2852,7 @@ hexchat_plugin_init(hexchat_plugin *plugin_handle, hexchat_hook_command(ph, "PY", HEXCHAT_PRI_NORM, Command_Py, usage, 0); hexchat_hook_command(ph, "LOAD", HEXCHAT_PRI_NORM, Command_Load, 0, 0); hexchat_hook_command(ph, "UNLOAD", HEXCHAT_PRI_NORM, Command_Unload, 0, 0); - hexchat_hook_command(ph, "RELOAD", HEXCHAT_PRI_NORM, Command_Reload, reload, 0); + hexchat_hook_command(ph, "RELOAD", HEXCHAT_PRI_NORM, Command_Reload, 0, 0); #ifdef WITH_THREAD thread_timer = hexchat_hook_timer(ph, 300, Callback_ThreadTimer, NULL); #endif |