You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

230 lines
8.7 KiB

--- 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);
}