2018-03-02 21:18:24 +00:00
|
|
|
|
|
|
|
|
|
|
|
#include "py4yap.h"
|
|
|
|
#include <VFS.h>
|
|
|
|
|
|
|
|
#include "YapStreams.h"
|
2018-06-01 13:22:13 +01:00
|
|
|
#include "YapUTF8.h"
|
2018-03-02 21:18:24 +00:00
|
|
|
|
2018-03-12 15:11:59 +00:00
|
|
|
YAP_Term TermErrStream, TermOutStream;
|
2018-03-02 21:18:24 +00:00
|
|
|
|
2018-06-01 13:22:13 +01:00
|
|
|
|
2018-06-05 11:20:39 +01:00
|
|
|
static void pyflush(StreamDesc *st) {
|
|
|
|
#if 0
|
2018-06-01 13:22:13 +01:00
|
|
|
st->u.w_irl.ptr[0] = '\0';
|
|
|
|
fprintf(stderr,"%s\n", st->u.w_irl.buf);
|
|
|
|
term_t tg = python_acquire_GIL();
|
|
|
|
if (st->user_name == TermOutStream){
|
|
|
|
PySys_WriteStdout("%s", st->u.w_irl.buf);
|
|
|
|
} else {
|
|
|
|
PySys_WriteStderr("%s", st->u.w_irl.buf);
|
2018-06-05 11:20:39 +01:00
|
|
|
|
2018-06-01 13:22:13 +01:00
|
|
|
}
|
|
|
|
python_release_GIL(tg);
|
|
|
|
st->u.w_irl.ptr = st->u.w_irl.buf;
|
2018-06-05 11:20:39 +01:00
|
|
|
#endif
|
2018-06-01 13:22:13 +01:00
|
|
|
}
|
|
|
|
|
2018-05-24 21:45:38 +01:00
|
|
|
static int py_putc(int sno, int ch) {
|
2018-03-02 21:18:24 +00:00
|
|
|
// PyObject *pyw; // buffer
|
|
|
|
// int pyw_kind;
|
|
|
|
// PyObject *pyw_data;
|
|
|
|
StreamDesc *st = YAP_GetStreamFromId(sno);
|
2018-06-01 13:22:13 +01:00
|
|
|
#if 0
|
|
|
|
if (false && (st->user_name == TermOutStream || st->user_name == TermErrStream)) {
|
|
|
|
size_t sz = put_utf8(st->u.w_irl.ptr, ch);
|
|
|
|
if (sz > 0) {
|
|
|
|
st->u.w_irl.ptr += sz;
|
|
|
|
if (ch == '\n' || st->u.w_irl.ptr - st->u.w_irl.buf > 256)
|
|
|
|
{pyflush(st); }
|
|
|
|
}
|
|
|
|
return ch;
|
2018-03-12 15:11:59 +00:00
|
|
|
}
|
2018-06-05 11:20:39 +01:00
|
|
|
#endif
|
2018-03-12 15:11:59 +00:00
|
|
|
char s[2];
|
|
|
|
PyObject *err;
|
2018-03-02 21:18:24 +00:00
|
|
|
s[0] = ch;
|
|
|
|
s[1] = '\0';
|
2018-03-19 11:43:14 +00:00
|
|
|
term_t g0 = python_acquire_GIL();
|
2018-03-02 21:18:24 +00:00
|
|
|
PyObject_CallMethodObjArgs(st->u.private_data, PyUnicode_FromString("write"),
|
|
|
|
PyUnicode_FromString(s), NULL);
|
2018-03-12 15:11:59 +00:00
|
|
|
python_release_GIL(g0);
|
2018-05-21 14:45:24 +01:00
|
|
|
if ((err = PyErr_Occurred())) {
|
2018-03-02 21:18:24 +00:00
|
|
|
PyErr_SetString(
|
|
|
|
err,
|
|
|
|
"Error in put\n"); // %s:%s:%d!\n", __FILE__, __FUNCTION__, __LINE__);
|
|
|
|
}
|
|
|
|
return ch;
|
|
|
|
}
|
|
|
|
|
2018-03-12 15:11:59 +00:00
|
|
|
VFS_t pystream;
|
2018-05-21 14:45:24 +01:00
|
|
|
static void *py_open(VFS_t *me, const char *name, const char *io_mode,
|
|
|
|
int sno) {
|
2018-03-12 15:11:59 +00:00
|
|
|
#if HAVE_STRCASESTR
|
|
|
|
if (strcasestr(name, "/python/") == name)
|
|
|
|
name += strlen("/python/");
|
|
|
|
#else
|
|
|
|
if (strstr(name, "/python/") == name)
|
|
|
|
name += strlen("/python/");
|
|
|
|
#endif
|
2018-03-18 00:44:08 +00:00
|
|
|
term_t ctk = python_acquire_GIL();
|
2018-05-21 14:45:24 +01:00
|
|
|
PyObject *pystream = string_to_python(name, true, NULL);
|
|
|
|
if (pystream == NULL || pystream == Py_None) {
|
|
|
|
python_release_GIL(ctk);
|
|
|
|
return NULL;
|
|
|
|
}
|
2018-03-12 15:11:59 +00:00
|
|
|
StreamDesc *st = YAP_RepStreamFromId(sno);
|
2018-03-17 10:38:56 +00:00
|
|
|
st->name = YAP_LookupAtom(name);
|
2018-06-14 11:27:43 +01:00
|
|
|
if (strcmp(name, "sys.stdout") == 0 ||
|
|
|
|
strcmp(name, "sys.stderr") == 0 ||
|
|
|
|
strcmp(name, "input") == 0) {
|
|
|
|
st->status |= Tty_Stream_f;
|
|
|
|
}
|
|
|
|
/*
|
2018-06-01 13:22:13 +01:00
|
|
|
if (!outbuf)
|
|
|
|
outbuf = ( unsigned char *)malloc(1024);
|
|
|
|
st->u.w_irl.ptr = st->u.w_irl.buf = outbuf;
|
2018-06-02 10:36:04 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
]\]
|
2018-03-12 15:11:59 +00:00
|
|
|
st->user_name = TermOutStream;
|
2018-05-21 14:45:24 +01:00
|
|
|
} else if (strcmp(name, "sys.stderr") == 0) {
|
2018-03-12 15:11:59 +00:00
|
|
|
st->user_name = TermErrStream;
|
2018-06-01 13:22:13 +01:00
|
|
|
if (!errbuf)
|
|
|
|
errbuf = ( unsigned char *)malloc(1024);
|
|
|
|
st->u.w_irl.ptr = st->u.w_irl.buf = errbuf;
|
2018-06-01 08:37:25 +01:00
|
|
|
// } else if (strcmp(name, "input") == 0) {
|
|
|
|
//pystream = PyObject_Call(pystream, PyTuple_New(0), NULL);
|
2018-06-01 13:22:13 +01:00
|
|
|
} else */
|
2018-06-05 11:20:39 +01:00
|
|
|
{ st->user_name = YAP_MkAtomTerm(st->name); }
|
|
|
|
st->u.private_data = pystream;
|
2018-03-17 10:38:56 +00:00
|
|
|
st->vfs = me;
|
2018-05-26 00:22:27 +01:00
|
|
|
st->file = NULL;
|
2018-05-21 14:45:24 +01:00
|
|
|
python_release_GIL(ctk);
|
2018-03-12 15:11:59 +00:00
|
|
|
return st;
|
|
|
|
}
|
|
|
|
|
2018-06-01 13:22:13 +01:00
|
|
|
static void py_flush(int sno) {
|
|
|
|
StreamDesc *s = YAP_GetStreamFromId(sno);
|
|
|
|
term_t tg = python_acquire_GIL();
|
|
|
|
PyObject *flush = PyObject_GetAttrString(s->u.private_data, "flush");
|
2018-06-05 11:20:39 +01:00
|
|
|
pyflush(s);
|
2018-06-01 13:22:13 +01:00
|
|
|
PyObject_CallFunction(flush, NULL);
|
|
|
|
python_release_GIL(tg);
|
|
|
|
}
|
|
|
|
|
2018-03-12 15:11:59 +00:00
|
|
|
static bool py_close(int sno) {
|
2018-03-17 10:38:56 +00:00
|
|
|
StreamDesc *st = YAP_RepStreamFromId(sno);
|
2018-06-05 11:20:39 +01:00
|
|
|
if (st->status & (Output_Stream_f | Append_Stream_f))
|
|
|
|
py_flush(sno);
|
2018-05-21 14:45:24 +01:00
|
|
|
if (strcmp(st->name, "sys.stdout") && strcmp(st->name, "sys.stderr")) {
|
|
|
|
Py_XDECREF(st->u.private_data);
|
2018-06-01 13:22:13 +01:00
|
|
|
st->u.w_irl.buf = st->u.w_irl.ptr = NULL;
|
2018-03-18 00:44:08 +00:00
|
|
|
}
|
2018-05-21 14:45:24 +01:00
|
|
|
st->u.private_data = NULL;
|
2018-03-18 00:44:08 +00:00
|
|
|
st->vfs = NULL;
|
|
|
|
|
2018-03-12 15:11:59 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-06-14 11:27:43 +01:00
|
|
|
static bool getLine(StreamDesc *rl_iostream, int sno) {
|
2018-03-12 15:11:59 +00:00
|
|
|
char *myrl_line = NULL;
|
2018-05-21 14:45:24 +01:00
|
|
|
term_t ctk = python_acquire_GIL();
|
2018-06-18 10:51:01 +01:00
|
|
|
|
2018-03-12 15:11:59 +00:00
|
|
|
/* window of vulnerability opened */
|
2018-06-18 10:51:01 +01:00
|
|
|
myrl_line = PyUnicode_AsUTF8(PyObject_CallFunctionObjArgs(rl_iostream->u.private_data, NULL));
|
2018-03-19 11:43:14 +00:00
|
|
|
python_release_GIL(ctk);
|
2018-06-14 11:27:43 +01:00
|
|
|
PyObject *err;
|
|
|
|
if ((err = PyErr_Occurred())) {
|
|
|
|
PyErr_SetString(
|
|
|
|
err,
|
|
|
|
"Error in getLine\n");
|
|
|
|
Yap_ThrowError(SYSTEM_ERROR_GET_FAILED, YAP_MkIntTerm(sno), err);
|
|
|
|
}
|
2018-06-18 10:51:01 +01:00
|
|
|
size_t size = strlen (myrl_line)+1;
|
2018-06-14 11:27:43 +01:00
|
|
|
rl_iostream->u.irl.ptr = rl_iostream->u.irl.buf =
|
2018-06-05 11:20:39 +01:00
|
|
|
(const unsigned char *)malloc(size);
|
2018-06-14 11:27:43 +01:00
|
|
|
memcpy((void *)rl_iostream->u.irl.buf, myrl_line, size);
|
2018-03-12 15:11:59 +00:00
|
|
|
return true;
|
2018-03-02 21:18:24 +00:00
|
|
|
}
|
2018-03-12 15:11:59 +00:00
|
|
|
|
|
|
|
static int py_getc(int sno) {
|
|
|
|
StreamDesc *s = YAP_RepStreamFromId(sno);
|
|
|
|
int ch;
|
|
|
|
bool fetch = (s->u.irl.buf == NULL);
|
2018-03-02 21:18:24 +00:00
|
|
|
|
2018-06-14 11:27:43 +01:00
|
|
|
if (fetch) {
|
|
|
|
if (!getLine(s, sno)) {
|
|
|
|
return EOF;
|
2018-03-12 15:11:59 +00:00
|
|
|
}
|
2018-06-14 11:27:43 +01:00
|
|
|
}
|
|
|
|
const unsigned char *ttyptr = s->u.irl.ptr++, *myrl_line = s->u.irl.buf;
|
|
|
|
ch = *ttyptr;
|
|
|
|
if (ch == '\0') {
|
|
|
|
ch = '\n';
|
|
|
|
free((void *)myrl_line);
|
|
|
|
s->u.irl.ptr = s->u.irl.buf = NULL;
|
2018-03-12 15:11:59 +00:00
|
|
|
}
|
2018-05-21 14:45:24 +01:00
|
|
|
return ch;
|
2018-03-12 15:11:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
@brief Yap_ReadlinePeekChar peeks the next char from the
|
|
|
|
readline buffer, but does not actually grab it.
|
|
|
|
|
|
|
|
The idea is to take advantage of the buffering. Special care must be taken
|
|
|
|
with EOF, though.
|
|
|
|
|
|
|
|
*/
|
2018-03-02 21:18:24 +00:00
|
|
|
static int py_peek(int sno) {
|
2018-03-12 15:11:59 +00:00
|
|
|
StreamDesc *s = YAP_RepStreamFromId(sno);
|
|
|
|
int ch;
|
|
|
|
|
|
|
|
if (s->u.irl.buf) {
|
|
|
|
const unsigned char *ttyptr = s->u.irl.ptr;
|
|
|
|
ch = *ttyptr;
|
|
|
|
if (ch == '\0') {
|
|
|
|
ch = '\n';
|
|
|
|
}
|
|
|
|
return ch;
|
|
|
|
}
|
2018-06-14 11:27:43 +01:00
|
|
|
if (getLine(s, sno)) {
|
2018-03-12 15:11:59 +00:00
|
|
|
ch = s->u.irl.ptr[0];
|
|
|
|
if (ch == '\0') {
|
|
|
|
ch = '\n';
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return EOF;
|
|
|
|
}
|
|
|
|
return ch;
|
2018-03-02 21:18:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int64_t py_seek(int sno, int64_t where, int how) {
|
2018-03-12 15:11:59 +00:00
|
|
|
StreamDesc *g0 = YAP_RepStreamFromId(sno);
|
2018-05-21 14:45:24 +01:00
|
|
|
term_t s0 = python_acquire_GIL();
|
2018-03-12 15:11:59 +00:00
|
|
|
PyObject *fseek = PyObject_GetAttrString(g0->u.private_data, "seek");
|
2018-03-02 21:18:24 +00:00
|
|
|
PyObject *pyr = PyObject_CallFunctionObjArgs(fseek, PyLong_FromLong(where),
|
|
|
|
PyLong_FromLong(how), NULL);
|
2018-05-21 14:45:24 +01:00
|
|
|
python_release_GIL(s0);
|
|
|
|
return PyLong_AsLong(pyr);
|
2018-03-02 21:18:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
static void python_output(void) {
|
|
|
|
PyObject *stream = string_to_python("sys.stdout", true, NULL);
|
|
|
|
StreamDesc *st = YAP_GetStreamFromId(1);
|
|
|
|
st->u.private_data = stream;
|
|
|
|
st->vfs = &pystream;
|
|
|
|
stream = string_to_python("sys.stderr", true, NULL);
|
|
|
|
st = YAP_GetStreamFromIds(2);
|
|
|
|
st->u.private_data = stream;
|
|
|
|
st->vfs = &pystream;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static bool initialized = false;
|
|
|
|
|
|
|
|
bool init_python_vfs(void) {
|
|
|
|
// pyw = PyUnicode_FromString("x");
|
|
|
|
// pyw_kind = PyUnicode_KIND(pyw);
|
|
|
|
// pyw_data = PyUnicode_DATA(pyw);
|
|
|
|
if (initialized)
|
|
|
|
return false;
|
|
|
|
initialized = true;
|
|
|
|
pystream.name = "python stream";
|
|
|
|
pystream.vflags =
|
|
|
|
VFS_CAN_WRITE | VFS_CAN_EXEC | VFS_CAN_READ | VFS_HAS_PREFIX;
|
|
|
|
pystream.prefix = "/python/";
|
|
|
|
pystream.suffix = NULL;
|
|
|
|
pystream.open = py_open;
|
|
|
|
pystream.close = py_close;
|
2018-03-12 15:11:59 +00:00
|
|
|
pystream.get_char = py_getc;
|
2018-03-02 21:18:24 +00:00
|
|
|
pystream.peek_char = py_peek;
|
2018-05-24 21:45:38 +01:00
|
|
|
pystream.put_char = py_putc;
|
2018-03-02 21:18:24 +00:00
|
|
|
pystream.flush = py_flush;
|
|
|
|
pystream.seek = py_seek;
|
|
|
|
pystream.next = GLOBAL_VFS;
|
|
|
|
GLOBAL_VFS = &pystream;
|
2018-03-12 15:11:59 +00:00
|
|
|
TermOutStream = YAP_MkAtomTerm(YAP_LookupAtom("std.output"));
|
|
|
|
TermErrStream = YAP_MkAtomTerm(YAP_LookupAtom("std.error"));
|
2018-03-02 21:18:24 +00:00
|
|
|
// NULL;
|
|
|
|
return true;
|
|
|
|
}
|