Fix INT_MAX definition on some newer systems.
[Tsunagari.git] / src / python-importer.cpp
blobf759b2e875ae172212dbe42198aa42806a59ad4b
1 /***************************************
2 ** Tsunagari Tile Engine **
3 ** python-importer.cpp **
4 ** Copyright 2011-2013 PariahSoft LLC **
5 ***************************************/
7 // **********
8 // Permission is hereby granted, free of charge, to any person obtaining a copy
9 // of this software and associated documentation files (the "Software"), to
10 // deal in the Software without restriction, including without limitation the
11 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
12 // sell copies of the Software, and to permit persons to whom the Software is
13 // furnished to do so, subject to the following conditions:
15 // The above copyright notice and this permission notice shall be included in
16 // all copies or substantial portions of the Software.
18 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
24 // IN THE SOFTWARE.
25 // **********
28 #include <Python.h>
30 #include "formatter.h"
31 #include "log.h"
32 #include "reader.h"
33 #include "python-importer.h"
36 //! List of known safe Python modules allowed for importing.
37 static const char* module_whitelist[] = {
38 "__builtin__",
39 "__main__",
40 "math",
41 "traceback",
42 NULL
45 static bool wi_in_whitelist(const char* name)
47 for (int i = 0; module_whitelist[i]; i++)
48 if (!strcmp(name, module_whitelist[i]))
49 return true;
50 return false;
53 static PyObject* wi_find_module(PyObject* /*self*/, PyObject* args)
55 PyObject* fullname = NULL;
56 PyObject* path = NULL; // dummy
58 if (!PyArg_UnpackTuple(args, "find_module", 1, 2, &fullname, &path)) {
59 // exc already set
60 return NULL;
62 if (!PyString_Check(fullname)) {
63 PyErr_Format(PyExc_TypeError, "expected string, got %.200s",
64 fullname->ob_type->tp_name);
65 return NULL;
68 const char* dotname = PyString_AsString(fullname); // "foo.bar"
69 std::string slashname(dotname); // "foo/bar.py"
70 std::replace(slashname.begin(), slashname.end(), '.', '/');
72 Log::info("PyWorldImporter", Formatter("%: requested") % dotname);
74 // Returning Py_None allows the import to continue. NULL stops it.
75 if (wi_in_whitelist(dotname)) {
76 Py_INCREF(Py_None);
77 return Py_None;
79 else if (Reader::directoryExists(slashname) && Reader::fileExists(slashname + "/__init__.py")) {
80 Py_INCREF(Py_None);
81 return Py_None;
83 else if (Reader::resourceExists(slashname + ".py")) {
84 Py_INCREF(Py_None);
85 return Py_None;
87 else {
88 PyErr_Format(PyExc_ImportError, "No module name %.200s", dotname);
89 return NULL;
93 typedef struct {
94 PyObject_HEAD
95 } worldimporterobject;
97 static PyMethodDef pyworldimporter_methods[] = {
98 {"find_module", (PyCFunction)wi_find_module, METH_VARARGS, NULL},
99 {NULL, NULL, 0, NULL},
102 static bool initted = false;
103 static PyTypeObject worldimporter_type = {
104 PyObject_HEAD_INIT(&PyType_Type)
107 static bool wi_init_type()
109 if (!initted) {
110 initted = false;
112 worldimporter_type.tp_name = "worldimporter";
113 worldimporter_type.tp_basicsize = sizeof(worldimporterobject);
114 worldimporter_type.tp_getattro = PyObject_GenericGetAttr;
115 worldimporter_type.tp_flags = Py_TPFLAGS_DEFAULT;
116 worldimporter_type.tp_methods = pyworldimporter_methods;
118 if (PyType_Ready(&worldimporter_type) < 0) {
119 Py_FatalError("Can't initialize worldimporter type");
120 return false;
123 return true;
126 static PyObject* wi_worldimporter_new()
128 wi_init_type();
129 return (PyObject*)PyObject_New(worldimporterobject, &worldimporter_type);
133 /** Public functions **/
135 bool pythonImporterInstall()
137 PyObject* meta_path = NULL;
138 PyObject* importer = NULL;
139 int idx = -1;
141 /* meta_path is a borrowed reference; no decref */
142 meta_path = PySys_GetObject((char*)"meta_path");
143 if (meta_path == NULL || !PyList_Check(meta_path)) {
144 Log::fatal("Python Importer",
145 "sys.meta_path must be a list of import hooks");
146 goto err;
149 importer = wi_worldimporter_new();
150 if (importer == NULL) {
151 Log::fatal("Python Importer",
152 "failed to create PyWorldImporter object");
153 goto err;
156 idx = PyList_Append(meta_path, importer);
157 if (idx == -1) {
158 Log::fatal("Python Importer", "failed to append to sys.meta_path");
159 goto err;
162 Py_DECREF(importer);
163 return true;
165 err:
166 Py_XDECREF(importer);
167 return false;