1 /*
2    Copyright (C) 2001 Kai Sterker <kai.sterker@gmail.com>
3    Part of the Adonthell Project <http://adonthell.nongnu.org>
4 
5    Adonthell is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 2 of the License, or
8    (at your option) any later version.
9 
10    Adonthell is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14 
15    You should have received a copy of the GNU General Public License
16    along with Adonthell.  If not, see <http://www.gnu.org/licenses/>.
17 */
18 
19 
20 /**
21  * @file   python_class.cc
22  * @author Kai Sterker <kai.sterker@gmail.com>
23  *
24  * @brief  Declares the python class.
25  *
26  *
27  */
28 
29 #include "python_class.h"
30 #include "game.h"
31 #include <iostream>
32 
33 PyObject *data::globals;
34 PyObject *python::module;
35 
36 // defined in py_adonthell_wrap.cc
37 PyObject *get_py_obj (void *instance, const char* class_name);
38 
39 using namespace std;
40 
41 /*
42  * Start Python
43  */
init()44 void python::init ()
45 {
46     Py_Initialize ();
47 }
48 
49 /**
50  * Stop Python
51  */
cleanup()52 void python::cleanup ()
53 {
54     // Cleanup the global namespace of python interpreter
55     // Note that we don't have to DECREF data::globals, because they're a
56     // borrowed reference of py_module.
57     Py_XDECREF (module);
58     Py_Finalize ();
59 }
60 
61 /*
62  * Insert a string into the module search path.
63  */
insert_path(char * name)64 void python::insert_path( char *name )
65 {
66     char buf[256];
67 
68     sprintf ( buf, "import sys ; sys.path.insert(0, \"%s\")", name );
69     PyRun_SimpleString ( buf );
70 }
71 
72 /*
73  * Some convenience functions
74  */
75 
76 /*
77  * Executes the Python statements in the string
78  */
exec_string(const char * s)79 void python::exec_string(const char * s)
80 {
81     PyRun_SimpleString(s);
82 }
83 
84 /*
85  * Execute the file given by 'filename'
86  */
exec_file(string filename)87 bool python::exec_file (string filename)
88 {
89     PyObject *mod = python::import_module (filename);
90 
91     if (!mod)
92     {
93         cerr << "exec_file: " << filename << " load failed: " << endl;
94         show_traceback ();
95 
96         return false;
97     }
98 
99     Py_DECREF (mod);
100 
101     return true;
102 }
103 
104 /*
105  * Dump any error information to stderr
106  */
show_traceback(void)107 void python::show_traceback(void)
108 {
109     if ( PyErr_Occurred() )
110     {
111         PyErr_Print();
112         fflush (stderr);
113     }
114 }
115 
116 /* Import a module, return module ptr */
import_module(string filename)117 PyObject *python::import_module (string filename)
118 {
119     PyObject *result = PyImport_ImportModule ((char *) filename.c_str ());
120 
121 #ifdef PY_DEBUG
122     show_traceback ();
123 #endif
124     return result;
125 }
126 
127 // Make a C++ instance available to Python
pass_instance(void * instance,const char * class_name)128 PyObject *python::pass_instance (void *instance, const char *class_name)
129 {
130     string class_ptr = string(class_name) + "*";
131     return get_py_obj (instance, class_ptr.c_str());
132 }
133 
get_tuple(igzstream & file)134 PyObject * python::get_tuple (igzstream & file)
135 {
136     PyObject * tuple;
137     u_int32 l;
138     l << file;
139 
140     tuple = PyTuple_New (l);
141 
142     for (u_int32 i = 0; i < l; i++)
143     {
144         string ms;
145         u_int32 j;
146         char c;
147 
148         c << file;
149         switch (c)
150         {
151             case 's':
152                 ms << file;
153                 // Stolen reference
154                 PyTuple_SetItem (tuple, i, PyString_FromString (ms.c_str ()));
155                 break;
156 
157             case 'i':
158                 j << file;
159                 // Stolen reference
160                 PyTuple_SetItem (tuple, i, PyInt_FromLong (j));
161                 break;
162         }
163     }
164     return tuple;
165 }
166 
put_tuple(PyObject * tuple,ogzstream & file)167 void python::put_tuple (PyObject * tuple, ogzstream & file)
168 {
169     u_int32 l = PyTuple_Size (tuple);
170     l >> file;
171     for (u_int32 i = 0; i < l; i++)
172     {
173         // Borrowed reference
174         PyObject * item = PyTuple_GetItem (tuple, i);
175 
176         // Check for the type of this object
177         // String?
178         if (PyString_Check (item))
179         {
180             's' >> file;
181             string s = python::as_string (item);
182             s >> file;
183         }
184 
185         // Integer?
186         else if (PyInt_Check (item))
187         {
188             'i' >> file;
189             u_int32 li = PyInt_AsLong (item);
190             li >> file;
191         }
192     }
193 }
194 
as_string(PyObject * s)195 string python::as_string(PyObject *s)
196 {
197 #if PY_MAJOR_VERSION >= 3
198 	PyObject *byteArr = PyUnicode_AsUTF8String(s);
199 	char* str = PyBytes_AsString(byteArr);
200 #else
201 	char* str = PyString_AsString(s);
202 #endif
203 	if (str)
204 	{
205 		string result(str);
206 #if PY_MAJOR_VERSION >= 3
207 		Py_DECREF(byteArr);
208 #endif
209 		return result;
210 	}
211 #if PY_MAJOR_VERSION >= 3
212 	Py_DECREF(byteArr);
213 #endif
214         return string("");
215 }
216