| --- a/tclpython.c 2006-03-07 16:28:03.000000000 +0300 |
| +++ b/tclpython.c 2014-05-06 23:33:41.713623943 +0400 |
| @@ -19,13 +19,83 @@ |
| $ cc -fpic -I/usr/local/include/tcltk/tcl8.3 -c tclthread.c |
| $ ld -o tclpython.so -Bshareable -L/usr/X11R6/lib -L/usr/local/lib -L/usr/local/share/python/config tclpython.o tclthread.o -lpython -lutil -lreadline -ltermcap -lcrypt -lgmp -lgdbm -lpq -lz -ltcl83 -ltk83 -lX11 |
| |
| +Patched for Python 3 with respect to https://github.com/facebook/fbthrift/blob/master/thrift/lib/py/protocol/fastbinary.c |
| + |
| */ |
| |
| #include <Python.h> |
| #include <tcl.h> |
| -#include <cStringIO.h> |
| + |
| +#if PY_MAJOR_VERSION >= 3 |
| + #define PyInt_FromLong PyLong_FromLong |
| + #define PyInt_AsLong PyLong_AsLong |
| + #define PyString_FromStringAndSize PyBytes_FromStringAndSize |
| +#else |
| + #include <cStringIO.h> |
| +#endif |
| + |
| #include "tclpython.h" |
| |
| +// Mostly copied from cStringIO.c |
| +#if PY_MAJOR_VERSION >= 3 |
| + |
| +/** io module in python3. */ |
| +static PyObject* Python3IO; |
| + |
| +typedef struct { |
| + PyObject_HEAD |
| + char *buf; |
| + Py_ssize_t pos, string_size; |
| +} IOobject; |
| + |
| +#define IOOOBJECT(O) ((IOobject*)(O)) |
| + |
| +static int |
| +IO__opencheck(IOobject *self) { |
| + if (!self->buf) { |
| + PyErr_SetString(PyExc_ValueError, |
| + "I/O operation on closed file"); |
| + return 0; |
| + } |
| + return 1; |
| +} |
| + |
| +static PyObject * |
| +IO_cgetval(PyObject *self) { |
| + if (!IO__opencheck(IOOOBJECT(self))) return NULL; |
| + assert(IOOOBJECT(self)->pos >= 0); |
| + return PyBytes_FromStringAndSize(((IOobject*)self)->buf, |
| + ((IOobject*)self)->pos); |
| +} |
| +#endif |
| + |
| +/* -- PYTHON MODULE SETUP STUFF --- */ |
| + |
| +static PyObject *pythonTclEvaluate(PyObject *self, PyObject *args); |
| + |
| +static PyMethodDef tclMethods[] = { |
| + {"eval", pythonTclEvaluate, METH_VARARGS, "Evaluate a Tcl script."}, |
| + {0, 0, 0, 0} /* sentinel */ |
| +}; |
| + |
| +#if PY_MAJOR_VERSION >= 3 |
| +struct module_state { |
| + PyObject *error; |
| +}; |
| + |
| +static struct PyModuleDef TclModuleDef = { |
| + PyModuleDef_HEAD_INIT, |
| + "tcl", |
| + NULL, |
| + sizeof(struct module_state), |
| + tclMethods, |
| + NULL, |
| + NULL, |
| + NULL, |
| + NULL |
| +}; |
| +#endif |
| + |
| #ifndef WIN32 |
| /* George Petasis, 21 Feb 2006: |
| * The following check cannot be handled correctly |
| @@ -66,13 +136,13 @@ |
| |
| static int pythonInterpreter(ClientData clientData, Tcl_Interp *interpreter, int numberOfArguments, Tcl_Obj * CONST arguments[]) |
| { |
| - int identifier; |
| + intptr_t identifier; |
| PyObject *output; |
| PyObject *message; |
| PyObject *result; |
| PyObject *globals; |
| char *string = 0; |
| - int length; |
| + Py_ssize_t length; |
| Tcl_Obj *object; |
| struct Tcl_HashEntry *entry; |
| unsigned evaluate; |
| @@ -111,12 +181,22 @@ |
| /* choose start token depending on whether this is an evaluation or an execution: */ |
| result = PyRun_String(Tcl_GetString(arguments[2]), (evaluate? Py_eval_input: Py_file_input), globals, globals); |
| if (result == 0) { /* an error occured */ |
| +#if PY_MAJOR_VERSION >= 3 |
| + output = PyObject_CallMethod(Python3IO, "BytesIO", "()"); |
| +#else |
| output = PycStringIO->NewOutput(1024); /* use a reasonable initial size but big enough to handle most cases */ |
| - PySys_SetObject("stderr", output); /* capture all interpreter error output */ |
| +#endif |
| + PySys_SetObject("sys.stderr", output); /* capture all interpreter error output */ |
| PyErr_Print(); /* so that error is printed on standard error, redirected above */ |
| +#if PY_MAJOR_VERSION >= 3 |
| + message = IO_cgetval(output); |
| + string = PyBytes_AsString(message); |
| + length = (string == NULL) ? 0 : strlen(string); |
| +#else |
| message = PycStringIO->cgetvalue(output); |
| string = PyString_AsString(message); |
| length = PyString_Size(message); |
| +#endif |
| if ((length > 0) && (string[length - 1] == '\n')) length--; /* eventually remove trailing new line character */ |
| object = Tcl_NewObj(); |
| Tcl_AppendStringsToObj(object, Tcl_GetString(arguments[0]), ": ", 0); /* identify interpreter in error */ |
| @@ -124,7 +204,11 @@ |
| Py_DECREF(output); |
| } else { |
| if (evaluate) { |
| +#if PY_MAJOR_VERSION >= 3 |
| + string = PyUnicode_AsUTF8(PyObject_Str(result)); |
| +#else |
| string = PyString_AsString(PyObject_Str(result)); |
| +#endif |
| object = Tcl_NewStringObj(string, -1); /* return evaluation result */ |
| } else /* execute */ |
| object = Tcl_NewObj(); /* always return an empty result or an error */ |
| @@ -139,9 +223,9 @@ |
| |
| Tcl_Interp *tclInterpreter(CONST char *name) /* public function for use in extensions to this extension */ |
| { |
| - int identifier; |
| + intptr_t identifier; |
| |
| - if ((sscanf(name, "tcl%u", &identifier) == 0) || (identifier != 0)) { |
| + if ((sscanf(name, "tcl%lu", &identifier) == 0) || (identifier != 0)) { |
| return 0; /* invalid name */ |
| } else { |
| return mainInterpreter; /* sole available interpreter */ |
| @@ -188,14 +272,9 @@ |
| return Py_BuildValue("s", result); |
| } |
| |
| -static PyMethodDef tclMethods[] = { |
| - {"eval", pythonTclEvaluate, METH_VARARGS, "Evaluate a Tcl script."}, |
| - {0, 0, 0, 0} /* sentinel */ |
| -}; |
| - |
| static int newInterpreter(Tcl_Interp *interpreter) |
| { |
| - int identifier; |
| + intptr_t identifier; |
| Tcl_Obj *object; |
| int created; |
| #ifdef WITH_THREAD |
| @@ -214,19 +293,31 @@ |
| return TCL_ERROR; |
| } else { |
| Py_Initialize(); /* initialize main interpreter */ |
| +#if PY_MAJOR_VERSION >= 3 |
| + Python3IO = PyImport_ImportModule("io"); |
| +#else |
| PycString_IMPORT; |
| +#endif |
| } |
| Tcl_SetHashValue(Tcl_CreateHashEntry(&threadStates, (ClientData)identifier, &created), 0); |
| #else |
| if (existingInterpreters == 0) { |
| Py_Initialize(); /* initialize main interpreter */ |
| PyEval_InitThreads(); /* initialize and acquire the global interpreter lock */ |
| +#if PY_MAJOR_VERSION >= 3 |
| + Python3IO = PyImport_ImportModule("io"); |
| +#else |
| PycString_IMPORT; |
| +#endif |
| globalState = PyThreadState_Swap(0); /* save the global thread */ |
| } else { |
| PyEval_AcquireLock(); /* needed in order to be able to create a new interpreter */ |
| } |
| +#if PY_MAJOR_VERSION >= 3 |
| + if (Python3IO == 0) { /* make sure string input/output is properly initialized */ |
| +#else |
| if (PycStringIO == 0) { /* make sure string input/output is properly initialized */ |
| +#endif |
| Tcl_SetResult(interpreter, "fatal error: could not initialize Python string input/output module", TCL_STATIC); |
| return TCL_ERROR; |
| } |
| @@ -250,7 +341,11 @@ |
| newIdentifier++; |
| #endif |
| existingInterpreters++; |
| +#if PY_MAJOR_VERSION >= 3 |
| + tcl = PyModule_Create(&TclModuleDef); |
| +#else |
| tcl = Py_InitModule("tcl", tclMethods); /* add a new 'tcl' module to the python interpreter */ |
| +#endif |
| Py_INCREF(tcl); |
| PyModule_AddObject(PyImport_AddModule("__builtin__"), "tcl", tcl); |
| return TCL_OK; |
| @@ -260,7 +355,7 @@ |
| { |
| int index; |
| char *name; |
| - int identifier; |
| + intptr_t identifier; |
| struct Tcl_HashEntry *entry; |
| Tcl_Obj *object; |
| #ifdef WITH_THREAD |
| @@ -270,7 +365,7 @@ |
| for (index = 0; index < numberOfArguments; index++) { |
| name = Tcl_GetString(arguments[index]); /* interpreter name is "pythonN" */ |
| entry = 0; |
| - if (sscanf(name, "python%u", &identifier) == 1) { |
| + if (sscanf(name, "python%lu", &identifier) == 1) { |
| identifier = atoi(name + 6); |
| entry = Tcl_FindHashEntry(&threadStates, (ClientData)identifier); |
| } |