1 /***************************************************************************
2 pythongdl.cpp - GDL embedded in python
3 too be included by gdlpython
4 -------------------
5 begin : July 22 2002
6 copyright : (C) 2002 by Marc Schellens
7 email : m_schellens@users.sourceforge.net
8 ***************************************************************************/
9
10 /***************************************************************************
11 * *
12 * This program is free software; you can redistribute it and/or modify *
13 * it under the terms of the GNU General Public License as published by *
14 * the Free Software Foundation; either version 2 of the License, or *
15 * (at your option) any later version. *
16 * *
17 ***************************************************************************/
18
19 // this has to be included from gdlpython because python
20 // (here numarray) duplicates the C API for each compilation unit module
21 // which includes it and hence numarray does not feel initialized in
22 // gdlpython.cpp
23 // and as topython.cpp has to be included from datatypes,
24 // they all have to be included from datatypes
25 #ifdef INCLUDE_PYTHONGDL_CPP
26
27 #include "includefirst.hpp"
28
29 #include <memory> // auto_ptr
30 #include <vector>
31
32 #include "datatypes.hpp"
33 #include "envt.hpp"
34 #include "sigfpehandler.hpp"
35 #include "terminfo.hpp"
36 #include "dinterpreter.hpp"
37
38 #include "gdleventhandler.hpp"
39
40 // SA fix based on:
41 // http://synopsis.fresco.org/viewsvn/Synopsis/branches/Synopsis_0_8/src/Synopsis/Python/Object.hh?r2=1792&rev=1792&r1=1657&sortdir=down
42 #if PY_VERSION_HEX < 0x02050000
43 typedef int Py_ssize_t;
44 #endif
45
46 void LibInit(); // defined in libinit.cpp
47
48 using namespace std;
49
50 // everything is executed within this interpreter
51 // initialized in the initGDL function
52 DInterpreter* interpreter;
53 PyObject* gdlError;
54
GetScript(PyObject * argTuple,DString & name)55 bool GetScript( PyObject *argTuple, DString& name)
56 {
57 if( argTuple == NULL)
58 {
59 PyErr_SetString( gdlError, "No input.");
60 return false;
61 }
62
63 int nArg = PyTuple_Size( argTuple);
64 if( nArg == 0)
65 {
66 PyErr_SetString( gdlError, "No input.");
67 return false;
68 }
69
70 PyObject* proPy = PyTuple_GetItem(argTuple, 0);
71 BaseGDL* proGDL = FromPython( proPy); // throws
72 if( proGDL->Type() != GDL_STRING)
73 {
74 PyErr_SetString( gdlError, "Script must be a tuple of strings.");
75 GDLDelete(proGDL);
76 return false;
77 }
78
79 name = StrUpCase((*(static_cast< DStringGDL*>( proGDL)))[ 0]);
80 GDLDelete(proGDL);
81
82 return true;
83 }
84
GetFirstString(PyObject * argTuple,DString & name)85 bool GetFirstString( PyObject *argTuple, DString& name)
86 {
87 if( argTuple == NULL)
88 {
89 PyErr_SetString( gdlError, "No argument.");
90 return false;
91 }
92
93 int nArg = PyTuple_Size( argTuple);
94 if( nArg == 0)
95 {
96 PyErr_SetString( gdlError, "No argument.");
97 return false;
98 }
99
100 PyObject* proPy = PyTuple_GetItem(argTuple, 0);
101 BaseGDL* proGDL = FromPython( proPy); // throws
102 if( proGDL->Type() != GDL_STRING || proGDL->N_Elements() != 1)
103 {
104 PyErr_SetString( gdlError, "First argument must be a scalar string");
105 GDLDelete(proGDL);
106 return false;
107 }
108
109 name = (*(static_cast< DStringGDL*>( proGDL)))[ 0];
110 GDLDelete(proGDL);
111
112 return true;
113 }
114
115
CheckSub(DSub * sub,PyObject * argTuple,PyObject * kwDict)116 bool CheckSub( DSub* sub, PyObject *argTuple, PyObject *kwDict)
117 {
118 int nKey = sub->NKey();
119 int nPar = sub->NPar();
120
121 int nArg = PyTuple_Size( argTuple);
122
123 // check args and keywords
124 if( nPar != -1 && (nArg-1) > nPar)
125 {
126 string errString = "Only " + i2s(nPar) +
127 " arguments are allowed in call to: " + sub->ObjectName();
128 PyErr_SetString( gdlError, errString.c_str());
129 return false;
130 }
131
132 if( kwDict == NULL) return true; // finish
133
134 int nKW = PyDict_Size( kwDict);
135
136 if( nKW > nKey)
137 {
138 string errString = "Only " + i2s(nKey) +
139 " keywords are allowed in call to: " + sub->ObjectName();
140 PyErr_SetString( gdlError, errString.c_str());
141 return false;
142 }
143 return true;
144 }
145
CopyArgFromPython(vector<BaseGDL * > & parRef,vector<BaseGDL * > & kwRef,EnvBaseT & e,PyObject * argTuple,PyObject * kwDict)146 bool CopyArgFromPython( vector<BaseGDL*>& parRef,
147 vector<BaseGDL*>& kwRef,
148 EnvBaseT& e,
149 PyObject *argTuple, PyObject *kwDict)
150 {
151 int nArg = PyTuple_Size( argTuple);
152
153 if( nArg > 1)
154 parRef.reserve( nArg-1);
155
156 // copy arguments
157 for( SizeT p=1; p<nArg; ++p)
158 {
159 PyObject *pyArg = PyTuple_GetItem(argTuple, p);
160 if( PyTuple_Check( pyArg)) // local variable (no cpy back)
161 {
162 BaseGDL* pP = FromPython( PyTuple_GetItem( pyArg, 0)); // throws
163 parRef.push_back( NULL);
164 e.SetNextPar( pP);
165 }
166 else
167 {
168 BaseGDL* pP = FromPython( pyArg); // throws
169 parRef.push_back( pP);
170 e.SetNextPar( &(parRef.back()));
171
172 // cout << "Set arg " << p << ": "; pP->ToStream( cout); cout << endl;
173 // cout << pP << " " << parRef.back() << " &" << &parRef.back() << endl;
174 }
175 }
176 if( kwDict != NULL)
177 {
178 PyObject *key, *value;
179 Py_ssize_t dictPos = 0;
180
181 int nKW = PyDict_Size( kwDict);
182
183 parRef.reserve( nKW);
184
185 for( SizeT k=0; k<nKW; ++k)
186 {
187 PyDict_Next( kwDict, &dictPos, &key, &value);
188 #if PY_MAJOR_VERSION >= 3
189 int keyIsString = PyUnicode_Check( key);
190 #else
191 int keyIsString = PyString_Check( key);
192 #endif
193 if( !keyIsString)
194 {
195 PyErr_SetString( gdlError,
196 "Keywords must be of type string");
197 return false;
198 }
199 #if PY_MAJOR_VERSION >= 3
200 const char* keyChar = PyUnicode_AsUTF8( key);
201 #else
202 const char* keyChar = PyString_AsString( key);
203 #endif
204 string keyString = StrUpCase( keyChar);
205 int kwIx = e.GetPro()->FindKey( keyString);
206 if( kwIx == -1)
207 {
208 string errString = "Keyword " + string(keyChar) +
209 " not allowed in call to: " + e.GetPro()->ObjectName();
210 PyErr_SetString( gdlError, errString.c_str());
211 return false;
212 }
213
214 if( PyTuple_Check( value)) // local keyword (no cpy back)
215 {
216 BaseGDL* pP = FromPython( PyTuple_GetItem( value, 0)); // throws
217 kwRef.push_back( NULL);
218 e.SetKeyword( keyString, pP);
219 }
220 else
221 {
222 BaseGDL* pP = FromPython( value); // throws
223 kwRef.push_back( pP);
224 e.SetKeyword( keyString, &kwRef.back());
225 }
226 }
227 }
228
229 e.ResolveExtra(); // expand _EXTRA
230
231 return true;
232 }
233
CopyArgToPython(vector<BaseGDL * > & parRef,vector<BaseGDL * > & kwRef,EnvBaseT & e,PyObject * argTuple,PyObject * kwDict)234 bool CopyArgToPython( vector<BaseGDL*>& parRef,
235 vector<BaseGDL*>& kwRef,
236 EnvBaseT& e,
237 PyObject *argTuple, PyObject *kwDict)
238 {
239 int nArg = PyTuple_Size( argTuple);
240 for( SizeT p=1; p<nArg; ++p)
241 {
242 BaseGDL* gdlPar = parRef[ p-1];
243 if( gdlPar != NULL)
244 {
245 PyObject* pyObj = gdlPar->ToPython(); // throws
246 int success0 = PyTuple_SetItem( argTuple, p, pyObj);
247 // Py_DECREF(pyObj); not needed: PyTuple_SetItem steals
248 }
249 }
250 if( kwDict != NULL)
251 {
252 PyObject *key, *value;
253 Py_ssize_t dictPos = 0;
254
255 int nKW = PyDict_Size( kwDict);
256 for( SizeT k=0; k<nKW; ++k)
257 {
258 BaseGDL* gdlKW = kwRef[ k];
259 PyDict_Next( kwDict, &dictPos, &key, &value);
260 if( gdlKW != NULL)
261 {
262 PyObject* pyObj = gdlKW->ToPython(); // throws
263 int success0 = PyDict_SetItem( kwDict, key, pyObj);
264 Py_DECREF( pyObj);
265 }
266 }
267 }
268 return true;
269 }
270
271 int (*oldInputHook)();
GDLEventHandlerPy()272 int GDLEventHandlerPy()
273 {
274 GDLEventHandler();
275 if( oldInputHook != NULL)
276 return (*oldInputHook)();
277 else
278 return 0;
279 }
280
281 // Execute a GDL subroutine
GDLSub(PyObject * self,PyObject * argTuple,PyObject * kwDict,bool functionCall)282 PyObject *GDLSub( PyObject *self, PyObject *argTuple, PyObject *kwDict,
283 bool functionCall)
284 {
285 feclearexcept(FE_ALL_EXCEPT);
286
287 PyOS_sighandler_t oldControlCHandler = PyOS_setsig(SIGINT,ControlCHandler);
288 PyOS_sighandler_t oldSigFPEHandler = PyOS_setsig(SIGFPE,SigFPEHandler);
289
290 PyObject *retVal = NULL; // init to error indicator
291
292 vector<BaseGDL*> parRef;
293 vector<BaseGDL*> kwRef;
294 bool success;
295 DString pro;
296
297 // handle GDL exceptions
298 try {
299
300 success = GetFirstString( argTuple, pro);
301 if( !success) goto ret;
302
303 pro = StrUpCase( pro);
304
305 DSub* sub;
306 bool libCall = false;
307
308 if( functionCall)
309 {
310 // search for function pro
311 // first search library functions
312 int proIx = LibFunIx( pro);
313 if( proIx != -1)
314 {
315 // PCALL_LIB
316 sub = libFunList[ proIx];
317 libCall = true;
318 }
319 else
320 {
321 // FCALL - user defined procedures
322 proIx = FunIx( pro);
323 if( proIx == -1)
324 {
325 /*bool found=*/ interpreter->SearchCompilePro( pro, false);
326
327 proIx = FunIx( pro);
328 if( proIx == -1)
329 {
330 string errString = "Function " + pro + " not found.";
331 PyErr_SetString( gdlError, errString.c_str());
332 goto ret;
333 }
334 }
335
336 sub = funList[ proIx];
337 }
338 }
339 else
340 {
341 // search for procedure pro
342 // first search library procedures
343 int proIx = LibProIx( pro);
344 if( proIx != -1)
345 {
346 // PCALL_LIB
347 sub = libProList[ proIx];
348 libCall = true;
349 }
350 else
351 {
352 // PCALL - user defined procedures
353 proIx = ProIx( pro);
354 if( proIx == -1)
355 {
356 /*bool found=*/ interpreter->SearchCompilePro( pro, true);
357
358 proIx = ProIx( pro);
359 if( proIx == -1)
360 {
361 string errString = "Procedure " + pro + " not found.";
362 PyErr_SetString( gdlError, errString.c_str());
363 goto ret;
364 }
365 }
366
367 sub = proList[ proIx];
368 }
369 }
370
371 success = CheckSub( sub, argTuple, kwDict);
372 if( !success) goto ret;
373
374 // build the environment
375 EnvBaseT* e;
376
377 if( libCall)
378 e = new EnvT( NULL, sub);
379 else
380 e = new EnvUDT( NULL, static_cast<DSubUD*>(sub));
381
382 Guard< EnvBaseT> e_guard( e);
383
384 // copy arguments
385 success = CopyArgFromPython( parRef, kwRef, *e, argTuple, kwDict);
386 if( !success) goto ret;
387
388 // make the call
389 StackSizeGuard<EnvStackT> guard( GDLInterpreter::CallStack());
390
391 if( !libCall)
392 {
393 GDLInterpreter::CallStack().push_back( static_cast<EnvUDT*>(e));
394 e_guard.release();
395 }
396
397 BaseGDL* retValGDL = NULL;
398 Guard<BaseGDL> retValGDL_guard;
399
400 if (functionCall) {
401 DLibFun* sub_fun_chk = dynamic_cast<DLibFun *>(static_cast<EnvT *>(e)->GetPro());
402 if (sub_fun_chk) {
403 //handle direct call function first
404 if (sub_fun_chk->DirectCall()) {
405 BaseGDL* directCallParameter = e->GetParDefined(0);
406 retValGDL = static_cast<DLibFunDirect*>(sub_fun_chk)->FunDirect()(directCallParameter, true /*isReference*/);
407 }
408 } else if (libCall)
409 retValGDL = static_cast<DLibFun *>(static_cast<EnvT *>(e)->GetPro())
410 ->Fun()(static_cast<EnvT *>(e));
411 else
412 retValGDL = interpreter->call_fun(
413 static_cast<DSubUD *>(static_cast<EnvUDT *>(e)->GetPro())
414 ->GetTree());
415 retValGDL_guard.Reset(retValGDL);
416 } else {
417 if (libCall)
418 static_cast<DLibPro *>(e->GetPro())
419 ->Pro()(static_cast<EnvT *>(e)); // throws
420 else
421 interpreter->call_pro(
422 static_cast<DSubUD *>(e->GetPro())->GetTree()); // throws
423 }
424
425 // copy back args and keywords
426 success = CopyArgToPython( parRef, kwRef, *e, argTuple, kwDict);
427 if( !success) goto ret;
428
429 if( retValGDL != NULL)
430 {
431 retVal = retValGDL->ToPython();
432 }
433 }
434 catch ( GDLException ex)
435 {
436 // ERROR GDL exception
437 string errString = "Calling " + pro + ": " + ex.toString();
438 PyErr_SetString( gdlError, errString.c_str());
439 goto ret;
440 }
441
442 if( retVal == NULL)
443 {
444 // no error: return Py_None from procedure
445 Py_INCREF(Py_None);
446 retVal = Py_None;
447 }
448
449 ret:
450 // free GDL parameters and keywords
451 PurgeContainer( parRef);
452 PurgeContainer( kwRef);
453
454 // restore old signal handlers
455 PyOS_setsig(SIGINT,oldControlCHandler);
456 PyOS_setsig(SIGFPE,oldSigFPEHandler);
457
458 return retVal;
459 }
460
461 // GDL is a C++ program
462 extern "C" {
463
464 // Execute a GDL procedure
GDL_script(PyObject * self,PyObject * argTuple,PyObject * kwDict)465 PyObject *GDL_script(PyObject *self, PyObject *argTuple, PyObject *kwDict)
466 {
467 PyOS_sighandler_t oldControlCHandler = PyOS_setsig(SIGINT,ControlCHandler);
468 PyOS_sighandler_t oldSigFPEHandler = PyOS_setsig(SIGFPE,SigFPEHandler);
469
470 PyObject *retVal = NULL; // init to error indicator
471
472 bool success;
473 DString file;
474
475 success = GetFirstString( argTuple, file);
476 if( !success) goto ret;
477
478 {
479 ifstream in(file.c_str());
480 if( !in.good())
481 {
482 string errString = "Error opening file: "+file;
483 PyErr_SetString( gdlError, errString.c_str());
484 goto ret;
485 }
486
487 success = interpreter->RunBatch( &in);
488 if( !success)
489 {
490 string errString = "Error in batch file: "+file;
491 PyErr_SetString( gdlError, errString.c_str());
492 goto ret;
493 }
494 }
495
496 Py_INCREF(Py_None);
497 retVal = Py_None;
498
499 ret:
500 // restore old signal handlers
501 PyOS_setsig(SIGINT,oldControlCHandler);
502 PyOS_setsig(SIGFPE,oldSigFPEHandler);
503
504 return retVal;
505 }
506
507 // Execute a GDL procedure
GDL_function(PyObject * self,PyObject * argTuple,PyObject * kwDict)508 PyObject *GDL_function(PyObject *self, PyObject *argTuple, PyObject *kwDict)
509 {
510 return GDLSub( self, argTuple, kwDict, true);
511 }
512
513 // Execute a GDL procedure
GDL_pro(PyObject * self,PyObject * argTuple,PyObject * kwDict)514 PyObject *GDL_pro(PyObject *self, PyObject *argTuple, PyObject *kwDict)
515 {
516 return GDLSub( self, argTuple, kwDict, false);
517 }
518
519 // python GDL module method table
520 PyMethodDef GDLMethods[] = {
521 {"pro", (PyCFunction) GDL_pro, METH_VARARGS | METH_KEYWORDS,
522 "Execute a GDL procedure."},
523 {"function", (PyCFunction) GDL_function, METH_VARARGS | METH_KEYWORDS,
524 "Execute a GDL function."},
525 {"script", (PyCFunction) GDL_script, METH_VARARGS | METH_KEYWORDS,
526 "Run a GDL script (sequence of commands)."},
527 {NULL, NULL, 0, NULL} // Sentinel
528 };
529
530 #if PY_MAJOR_VERSION >= 3
531 struct module_state {
532 PyObject *error;
533 };
534
535 #define GETSTATE(m) ((struct module_state*)PyModule_GetState(m))
536
GDL_traverse(PyObject * m,visitproc visit,void * arg)537 static int GDL_traverse(PyObject *m, visitproc visit, void *arg) {
538 Py_VISIT(GETSTATE(m)->error);
539 return 0;
540 }
541
GDL_clear(PyObject * m)542 static int GDL_clear(PyObject *m) {
543 Py_CLEAR(GETSTATE(m)->error);
544 return 0;
545 }
546
547 static struct PyModuleDef moduledef = {
548 PyModuleDef_HEAD_INIT,
549 "GDL",
550 NULL,
551 sizeof(struct module_state),
552 GDLMethods,
553 NULL,
554 GDL_traverse,
555 GDL_clear,
556 NULL
557 };
558 #endif
559
560 // python GDL module init function
561 #if PY_MAJOR_VERSION >= 3
PyInit_GDL(void)562 PyMODINIT_FUNC PyInit_GDL(void)
563 #else
564 PyMODINIT_FUNC initGDL(void)
565 #endif
566 {
567 // http://docs.scipy.org/doc/numpy/reference/c-api.array.html#miscellaneous
568 import_array();
569
570 // note: we don't use atexit here
571 // ncurses blurs the output, initialize TermWidth here
572 TermWidth();
573
574 // initializations
575 InitObjects();
576
577 // init library functions
578 LibInit();
579
580 // instantiate the interpreter (creates $MAIN$ environment)
581 interpreter = new DInterpreter();
582
583 // Ole: enable GDL PATH!
584 string gdlPath=GetEnvString("GDL_PATH");
585 if( gdlPath == "") gdlPath=GetEnvString("IDL_PATH");
586 if( gdlPath == "")
587 {
588 gdlPath = "+" GDLDATADIR "/lib";
589 }
590 SysVar::SetGDLPath( gdlPath);
591
592 #if PY_MAJOR_VERSION >= 3
593 PyObject* m = PyModule_Create(&moduledef);
594 #else
595 PyObject* m = Py_InitModule("GDL", GDLMethods);
596 #endif
597
598 gdlError = PyErr_NewException((char*)"GDL.error", NULL, NULL);
599 Py_INCREF(gdlError);
600 PyModule_AddObject(m, "error", gdlError);
601
602 // GDL event handling
603 oldInputHook = PyOS_InputHook;
604 PyOS_InputHook = GDLEventHandlerPy;
605 #if PY_MAJOR_VERSION >= 3
606 return m;
607 #endif
608 }
609
610 } // extern "C"
611
612 //#endif
613 #endif // INCLUDE_PYTHONGDL_CPP
614