Panda3D
|
00001 #include <Python.h> 00002 00003 #ifdef _WIN32 00004 #define DLLEXPORT __declspec(dllexport) 00005 #else 00006 #define DLLEXPORT 00007 #endif 00008 00009 /* 00010 * This pointer is kept internally to this module. It represents the 00011 * locally-allocated FrozenModules array. If the 00012 * PyImport_FrozenModules is any other value, then it wasn't allocated 00013 * via this module. 00014 */ 00015 static struct _frozen *frozen_modules = NULL; 00016 static int num_frozen_modules = 0; 00017 00018 /* 00019 * Call this function to extend the frozen modules array with a new 00020 * array of frozen modules, provided in a C-style array, at runtime. 00021 * Returns the total number of frozen modules. 00022 */ 00023 static int 00024 extend_frozen_modules(const struct _frozen *new_modules, int new_count) { 00025 int orig_count; 00026 struct _frozen *realloc_FrozenModules; 00027 00028 if (PyImport_FrozenModules == frozen_modules) { 00029 /* If the previous array was allocated through this module, we 00030 already know the count. */ 00031 orig_count = num_frozen_modules; 00032 00033 } else { 00034 /* If the previous array came from anywhere else, we have to count 00035 up its length. */ 00036 orig_count = 0; 00037 while (PyImport_FrozenModules[orig_count].name != NULL) { 00038 ++orig_count; 00039 } 00040 } 00041 00042 if (new_count == 0) { 00043 /* Trivial no-op. */ 00044 return orig_count; 00045 } 00046 00047 /* Reallocate the PyImport_FrozenModules array bigger to make room 00048 for the additional frozen modules. */ 00049 realloc_FrozenModules = (struct _frozen *)malloc((orig_count + new_count + 1) * sizeof(struct _frozen)); 00050 00051 /* If the previous array was allocated through this module, we can 00052 free it; otherwise, we have to leak it. */ 00053 if (frozen_modules != NULL) { 00054 free(frozen_modules); 00055 frozen_modules = NULL; 00056 } 00057 00058 /* The new frozen modules go at the front of the list. */ 00059 memcpy(realloc_FrozenModules, new_modules, new_count * sizeof(struct _frozen)); 00060 00061 /* Then the original set of frozen modules. */ 00062 memcpy(realloc_FrozenModules + new_count, PyImport_FrozenModules, orig_count * sizeof(struct _frozen)); 00063 00064 /* Finally, a single 0-valued entry marks the end of the array. */ 00065 memset(realloc_FrozenModules + orig_count + new_count, 0, sizeof(struct _frozen)); 00066 00067 /* Assign the new pointer. */ 00068 PyImport_FrozenModules = realloc_FrozenModules; 00069 frozen_modules = realloc_FrozenModules; 00070 num_frozen_modules = orig_count + new_count; 00071 00072 return num_frozen_modules; 00073 } 00074 00075 /* 00076 * Call this function to extend the frozen modules array with a new 00077 * list of frozen modules, provided in a Python-style list of (name, 00078 * code) tuples, at runtime. This function is designed to be called 00079 * from Python. 00080 * 00081 * Returns the total number of frozen modules. 00082 */ 00083 static PyObject * 00084 py_extend_frozen_modules(PyObject *self, PyObject *args) { 00085 PyObject *list; 00086 int num_elements; 00087 int i; 00088 struct _frozen *new_modules; 00089 int total_count; 00090 00091 if (!PyArg_ParseTuple(args, "O", &list)) { 00092 return NULL; 00093 } 00094 00095 if (!PySequence_Check(list)) { 00096 Py_DECREF(list); 00097 PyErr_SetString(PyExc_TypeError, "List required"); 00098 return NULL; 00099 } 00100 00101 num_elements = PySequence_Size(list); 00102 new_modules = (struct _frozen *)malloc(sizeof(struct _frozen) * num_elements); 00103 00104 for (i = 0; i < num_elements; ++i) { 00105 PyObject *tuple; 00106 const char *name; 00107 const char *code; 00108 int size; 00109 00110 tuple = PySequence_GetItem(list, i); 00111 if (!PyArg_ParseTuple(tuple, "ss#", &name, &code, &size)) { 00112 return NULL; 00113 } 00114 00115 /* We have to malloc new pointers for the name and code arrays. 00116 These pointers will never be freed. */ 00117 new_modules[i].name = strdup(name); 00118 new_modules[i].code = (unsigned char *)malloc(size); 00119 new_modules[i].size = size; 00120 memcpy(new_modules[i].code, code, size); 00121 00122 Py_DECREF(tuple); 00123 } 00124 00125 Py_DECREF(list); 00126 00127 total_count = extend_frozen_modules(new_modules, num_elements); 00128 free(new_modules); 00129 00130 return Py_BuildValue("i", total_count); 00131 } 00132 00133 /* 00134 * Call this function to query whether the named module is already a 00135 * frozen module or not. 00136 */ 00137 static PyObject * 00138 py_is_frozen_module(PyObject *self, PyObject *args) { 00139 const char *name; 00140 int i; 00141 00142 if (!PyArg_ParseTuple(args, "s", &name)) { 00143 return NULL; 00144 } 00145 00146 i = 0; 00147 while (PyImport_FrozenModules[i].name != NULL) { 00148 if (strcmp(PyImport_FrozenModules[i].name, name) == 0) { 00149 Py_INCREF(Py_True); 00150 return Py_True; 00151 } 00152 ++i; 00153 } 00154 00155 Py_INCREF(Py_False); 00156 return Py_False; 00157 } 00158 00159 /* 00160 * This returns the tuple (code, isPackage), where code is the code 00161 * string associated with the named frozen module, and isPackage is 00162 * true if the module is a package, or false if it is a normal 00163 * module). The return value is None if there is no such frozen 00164 * module. You must use the marshal module to convert the code string 00165 * to a code object. 00166 */ 00167 static PyObject * 00168 py_get_frozen_module_code(PyObject *self, PyObject *args) { 00169 const char *name; 00170 int i; 00171 00172 if (!PyArg_ParseTuple(args, "s", &name)) { 00173 return NULL; 00174 } 00175 00176 i = 0; 00177 while (PyImport_FrozenModules[i].name != NULL) { 00178 if (strcmp(PyImport_FrozenModules[i].name, name) == 0) { 00179 int is_package = (PyImport_FrozenModules[i].size < 0); 00180 return Py_BuildValue("(s#i)", PyImport_FrozenModules[i].code, 00181 abs(PyImport_FrozenModules[i].size), 00182 is_package); 00183 } 00184 ++i; 00185 } 00186 00187 return Py_BuildValue(""); 00188 } 00189 00190 /* 00191 * Call this function to return a list of the existing frozen module 00192 * names. 00193 */ 00194 static PyObject * 00195 py_get_frozen_module_names(PyObject *self, PyObject *args) { 00196 int i; 00197 PyObject *list; 00198 00199 if (!PyArg_ParseTuple(args, "")) { 00200 return NULL; 00201 } 00202 00203 list = PyList_New(0); 00204 i = 0; 00205 while (PyImport_FrozenModules[i].name != NULL) { 00206 PyObject *name = PyString_FromString(PyImport_FrozenModules[i].name); 00207 PyList_Append(list, name); 00208 Py_DECREF(name); 00209 ++i; 00210 } 00211 00212 return list; 00213 } 00214 00215 /* Initializes the Python module with our functions. */ 00216 DLLEXPORT void initextend_frozen() { 00217 static PyMethodDef extend_frozen_methods[] = { 00218 { "extend", py_extend_frozen_modules, METH_VARARGS, 00219 "Adds new frozen modules at runtime." }, 00220 { "is_frozen_module", py_is_frozen_module, METH_VARARGS, 00221 "Returns true if the named module is a frozen module." }, 00222 { "get_frozen_module_code", py_get_frozen_module_code, METH_VARARGS, 00223 "Returns the code string associated with the named module." }, 00224 { "get_frozen_module_names", py_get_frozen_module_names, METH_VARARGS, 00225 "Returns a list of frozen module names." }, 00226 { NULL, NULL, 0, NULL } /* Sentinel */ 00227 }; 00228 00229 Py_InitModule("extend_frozen", extend_frozen_methods); 00230 }