Embedding to C++: hooking up GNU readline
Alex Farber
farber at cpan.org
Wed Mar 1 17:52:05 EST 2000
Hi,
Alex Farber wrote:
> I have a C++ application which embeds Python. To use the GNU readline
> library for input I run a separate thread, which calls readline(">>> "),
> then processes the input and passes the received char array to another
> function. And that function is hooked up to PyOS_ReadlineFunctionPointer.
I am attaching my solution for the case that someone else is interested.
I am not sure if there are any stupid bugs or if it will work with future
Python releases. It tries to emulate the Python command line.
The background: I am writing a 3D-viewer in C++ which uses Qt (not thread
safe) and some FE library (written by my university; not thread safe).
Since both Qt and the Python (via FE objects and via OpenGL) access Xlib
(which is not thread safe on many computers), I have to run Qt and Python
in the same thread.
This means that I can not set PyOS_ReadlineFunctionPointer and run the
PyRun_InteractiveLoop() because then the Qt would freeze. So I have to
run Readline in a different thread and write to a pipe. Qt will select()
on that pipe (via QSocketNotifier) and run PyRun_SimpleString().
Now the problem is to know whether there is enough data to be run by
Python (consider "for i in [1,2]:\n"). I was hoping to Py_CompileString()
and then, if more data is needed - save the string for later, otherwise -
run PyEval_EvalCode().
Now the bad thing is, that I can not say if Py_CompileString() failed
because of "not enough data" or because of "syntax error". That's why
I had to write the attached code. I hope that Mr. van Rossum will
consider adding some easier interface in the later versions of Python -
because other people embedding Python can get the same difficulties.
Regards
Alex
/* Emulate readline behaviour for the cases where
PyRun_InteractiveOne() or PyRun_InteractiveLoop()
can not be run (like Qt + Python in one thread). */
/* COMPILE: gcc -I/usr/include/python -I/usr/include/readline
-lpython1.5 -lreadline -o rdl rdl.c */
#include <stdio.h>
#include <readline.h>
#include <Python.h>
#include <node.h>
#include <errcode.h>
#include <grammar.h>
#include <parsetok.h>
#include <compile.h>
extern grammar _PyParser_Grammar; /* from graminit.c */
int main (int argc, char* argv[])
{
node* n; /* will these work */
perrdetail e; /* in future releases? */
int done = 0;
char *line; /* temporary buffer */
char *code = NULL; /* source code */
int i, j; /* lengths of line, code */
char ps1[] = ">>> ";
char ps2[] = "... ";
char *prompt = ps1;
Py_Initialize ();
while (!done) {
line = readline (prompt);
if (NULL == line || /* CTRL-D pressed */
0 == strcmp (line, "quit") ||
0 == strcmp (line, "exit")) {
done = 1;
}
else {
i = strlen (line);
if (i > 0)
add_history (line); /* save non-empty lines */
if (NULL == code) /* nothing in code yet */
j = 0;
else
j = strlen (code);
code = realloc (code, i + j + 2);
if (NULL == code) /* out of memory */
exit (1);
if (0 == j) /* code was empty, so */
code[0] = '\0'; /* keep strncat happy */
strncat (code, line, i); /* append line to code */
code[i + j] = '\n';
code[i + j + 1] = '\0'; /* append '\n' to code */
n = PyParser_ParseString (code, &_PyParser_Grammar, Py_file_input, &e);
if (NULL == n && E_EOF == e.error) { /* more input needed */
prompt = ps2;
}
else { /* try to run the code */
PyNode_Free (n);
if (ps1 == prompt || /* ">>> " or */
'\n' == code[i + j - 1]) { /* "... " and 2 '\n' */
PyRun_SimpleString (code); /* returns -1 on failure */
free (code);
code = NULL;
prompt = ps1;
}
}
}
free (line);
}
Py_Finalize();
exit(0);
}
More information about the Python-list
mailing list