Panda3D

extend_frozen.c

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 }
 All Classes Functions Variables Enumerations