1/* 2 * Implements a function to fetch the list of objective-C classes known 3 * in the runtime. 4 */ 5#include "pyobjc.h" 6 7 8 /* Implementation for MacOS X */ 9 10Py_ssize_t 11PyObjC_ClassCount(void) 12{ 13 int neededLen = objc_getClassList(NULL, 0); 14 return neededLen; 15} 16 17 18PyObject* 19PyObjC_GetClassList(void) 20{ 21 PyObject* result = NULL; 22 Class* buffer = NULL; 23 int bufferLen = 0; 24 int neededLen = 0; 25 int i; 26 27 /* 28 * objc_getClassList returns the number of classes known in the runtime, 29 * the documented way to fetch the list is: 30 * 1. call ret = objc_getClassList(NULL, 0); 31 * 2. allocate a buffer of 'ret' class-pointers 32 * 3. call objc_getClassList again with this buffer. 33 * 34 * Step 3 might return more classes because another thread may have 35 * loaded a new framework/bundle. This means we need a loop to be sure 36 * we'll get all classes. 37 */ 38 neededLen = objc_getClassList(NULL, 0); 39 bufferLen = 0; 40 buffer = NULL; 41 42 while (bufferLen < neededLen) { 43 Class* newBuffer; 44 bufferLen = neededLen; 45 46 /* Realloc(NULL, ...) might not work, call Malloc when 47 * the buffer is NULL. 48 */ 49 if (buffer == NULL) { 50 newBuffer = PyMem_Malloc( 51 sizeof(Class) * bufferLen); 52 } else { 53 newBuffer = PyMem_Realloc(buffer, 54 sizeof(Class) * bufferLen); 55 } 56 if (newBuffer == NULL) { 57 PyErr_NoMemory(); 58 goto error; 59 } 60 buffer = newBuffer; newBuffer = NULL; 61 neededLen = objc_getClassList(buffer, bufferLen); 62 } 63 bufferLen = neededLen; 64 65 result = PyTuple_New(bufferLen); 66 if (result == NULL) { 67 goto error; 68 } 69 70 for (i = 0; i < bufferLen; i++) { 71 PyObject* pyclass; 72 73 pyclass = PyObjCClass_New(buffer[i]); 74 if (pyclass == NULL) { 75 goto error; 76 } 77 PyTuple_SET_ITEM(result, i, pyclass); 78 } 79 80 PyMem_Free(buffer); buffer = NULL; 81 82 return result; 83 84error: 85 if (buffer != NULL) { 86 PyMem_Free(buffer); 87 buffer = NULL; 88 } 89 Py_XDECREF(result); 90 return NULL; 91} 92