Salome HOME
Merge branch 'master' of https://git.salome-platform.org/git/modules/yacs
[modules/yacs.git] / src / runtime / PyStdout.cxx
1 // Copyright (C) 2006-2015  CEA/DEN, EDF R&D
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 #include "PyStdout.hxx"
21 #include "Exception.hxx"
22 #include "AutoGIL.hxx"
23
24 #include <structmember.h>
25
26 #include <string>
27 #include <sstream>
28
29 #ifdef WIN32
30 #include <process.h>
31 #define getpid _getpid
32 #endif
33
34 namespace YACS
35 {
36   namespace ENGINE
37     {
38
39     typedef struct {
40       PyObject_HEAD
41       int softspace;
42       std::string *out;
43     } PyStdOut;
44
45 static void
46 PyStdOut_dealloc(PyStdOut *self)
47 {
48   PyObject_Del(self);
49 }
50
51 static PyObject *
52 PyStdOut_write(PyStdOut *self, PyObject *args)
53 {
54   char *c;
55   int l;
56   if (!PyArg_ParseTuple(args, "t#:write",&c, &l))
57     return NULL;
58
59   //std::cerr << c ;
60   *(self->out)=*(self->out)+std::string(c);
61
62   Py_INCREF(Py_None);
63   return Py_None;
64 }
65
66 static PyMethodDef PyStdOut_methods[] = {
67   {"write",  (PyCFunction)PyStdOut_write,  METH_VARARGS,
68     PyDoc_STR("write(string) -> None")},
69   {NULL,    NULL}   /* sentinel */
70 };
71
72 static PyMemberDef PyStdOut_memberlist[] = {
73   {(char*)"softspace", T_INT,  offsetof(PyStdOut, softspace), 0,
74    (char*)"flag indicating that a space needs to be printed; used by print"},
75   {NULL} /* Sentinel */
76 };
77
78 static PyTypeObject PyStdOut_Type = {
79   /* The ob_type field must be initialized in the module init function
80    * to be portable to Windows without using C++. */
81   PyObject_HEAD_INIT(NULL)
82   0,      /*ob_size*/
83   "PyOut",   /*tp_name*/
84   sizeof(PyStdOut),  /*tp_basicsize*/
85   0,      /*tp_itemsize*/
86   /* methods */
87   (destructor)PyStdOut_dealloc, /*tp_dealloc*/
88   0,      /*tp_print*/
89   0, /*tp_getattr*/
90   0, /*tp_setattr*/
91   0,      /*tp_compare*/
92   0,      /*tp_repr*/
93   0,      /*tp_as_number*/
94   0,      /*tp_as_sequence*/
95   0,      /*tp_as_mapping*/
96   0,      /*tp_hash*/
97         0,                      /*tp_call*/
98         0,                      /*tp_str*/
99         PyObject_GenericGetAttr,                      /*tp_getattro*/
100         /* softspace is writable:  we must supply tp_setattro */
101         PyObject_GenericSetAttr,    /* tp_setattro */
102         0,                      /*tp_as_buffer*/
103         Py_TPFLAGS_DEFAULT,     /*tp_flags*/
104         0,                      /*tp_doc*/
105         0,                      /*tp_traverse*/
106         0,                      /*tp_clear*/
107         0,                      /*tp_richcompare*/
108         0,                      /*tp_weaklistoffset*/
109         0,                      /*tp_iter*/
110         0,                      /*tp_iternext*/
111         PyStdOut_methods,                      /*tp_methods*/
112         PyStdOut_memberlist,                      /*tp_members*/
113         0,                      /*tp_getset*/
114         0,                      /*tp_base*/
115         0,                      /*tp_dict*/
116         0,                      /*tp_descr_get*/
117         0,                      /*tp_descr_set*/
118         0,                      /*tp_dictoffset*/
119         0,                      /*tp_init*/
120         0,                      /*tp_alloc*/
121         0,                      /*tp_new*/
122         0,                      /*tp_free*/
123         0,                      /*tp_is_gc*/
124 };
125
126
127 #define PyStdOut_Check(v)  ((v)->ob_type == &PyStdOut_Type)
128
129 PyObject * newPyStdOut( std::string& out )
130 {
131   PyStdOut *self;
132   self = PyObject_New(PyStdOut, &PyStdOut_Type);
133   if (self == NULL)
134     return NULL;
135   self->softspace = 0;
136   self->out=&out;
137   return (PyObject*)self;
138 }
139
140 PyObject *evalPy(const std::string& funcName, const std::string& strToEval)
141 {
142   std::ostringstream oss0; oss0 << "def " << funcName << "():\n";
143   std::string::size_type i0(0);
144   while(i0<strToEval.length() && i0!=std::string::npos)
145     {
146       std::string::size_type i2(strToEval.find('\n',i0));
147       std::string::size_type lgth(i2!=std::string::npos?i2-i0:std::string::npos);
148       std::string part(strToEval.substr(i0,lgth));
149       if(!part.empty())
150         oss0 << "  " << part << "\n";
151       i0=i2!=std::string::npos?i2+1:std::string::npos;
152     }
153   std::string zeCodeStr(oss0.str());
154   std::ostringstream stream;
155   stream << "/tmp/PythonNode_";
156   stream << getpid();
157   AutoPyRef context(PyDict_New());
158   PyDict_SetItemString( context, "__builtins__", PyEval_GetBuiltins() );
159   AutoPyRef code(Py_CompileString(zeCodeStr.c_str(), "kkkk", Py_file_input));
160   if(code.isNull())
161     {
162       std::string errorDetails;
163       PyObject *new_stderr(newPyStdOut(errorDetails));
164       PySys_SetObject((char*)"stderr", new_stderr);
165       PyErr_Print();
166       PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
167       Py_DECREF(new_stderr);
168       std::ostringstream oss; oss << "evalPy failed : " << errorDetails;
169       throw Exception(oss.str());
170     }
171   AutoPyRef res(PyEval_EvalCode(reinterpret_cast<PyCodeObject *>((PyObject *)code),context,context));
172   PyObject *ret(PyDict_GetItemString(context,funcName.c_str())); //borrowed ref
173   if(!ret)
174     throw YACS::Exception("evalPy : Error on returned func !");
175   Py_XINCREF(ret);
176   return ret;
177 }
178
179 PyObject *evalFuncPyWithNoParams(PyObject *func)
180 {
181   if(!func)
182     throw YACS::Exception("evalFuncPyWithNoParams : input func is NULL !");
183   AutoPyRef args(PyTuple_New(0));
184   AutoPyRef ret(PyObject_CallObject(func,args));
185   if(ret.isNull())
186     throw YACS::Exception("evalFuncPyWithNoParams : ret is null !");
187   return ret.retn();
188 }
189
190 }
191 }
192