Merge branch 'beta-NPL'
[pyTivo.git] / Cheetah / _namemapper.c
blob02f243726a7bb5b5135563a49fcfda2af5a6d5ed
1 /* ***************************************************************************
2 This is the C language version of NameMapper.py. See the comments and
3 DocStrings in NameMapper for details on the purpose and interface of this
4 module.
6 ===============================================================================
7 $Id: _namemapper.c,v 1.31 2005/01/06 15:13:16 tavis_rudd Exp $
8 Authors: Tavis Rudd <tavis@damnsimple.com>
9 Version: $Revision: 1.31 $
10 Start Date: 2001/08/07
11 Last Revision Date: $Date: 2005/01/06 15:13:16 $
14 /* *************************************************************************** */
15 #include "Python.h" /* Python header files */
16 #include <string.h>
17 #include <stdlib.h>
19 #ifdef __cplusplus
20 extern "C" {
21 #endif
24 static PyObject *NotFound; /* locally-raised exception */
25 static PyObject *TooManyPeriods; /* locally-raised exception */
26 static PyObject* pprintMod_pformat; /* used for exception formatting */
27 #define MAXCHUNKS 15 /* max num of nameChunks for the arrays */
28 #define TRUE 1
29 #define FALSE 0
31 #define ALLOW_WRAPPING_OF_NOTFOUND_EXCEPTIONS 1
32 #define INCLUDE_NAMESPACE_REPR_IN_NOTFOUND_EXCEPTIONS 0
34 # define createNameCopyAndChunks() {\
35 nameCopy = malloc(strlen(name) + 1);\
36 tmpPntr1 = name; \
37 tmpPntr2 = nameCopy;\
38 while ((*tmpPntr2++ = *tmpPntr1++)); \
39 numChunks = getNameChunks(nameChunks, name, nameCopy); \
40 if (PyErr_Occurred()) { /* there might have been TooManyPeriods */\
41 free(nameCopy);\
42 return NULL;\
46 #define OLD_checkForNameInNameSpaceAndReturnIfFound() { \
47 if ( PyNamemapper_hasKey(nameSpace, nameChunks[0]) ) {\
48 theValue = PyNamemapper_valueForName(nameSpace, nameChunks, numChunks, executeCallables);\
49 free(nameCopy);\
50 if (wrapInternalNotFoundException(name, nameSpace)) {\
51 theValue = NULL;\
53 return theValue;\
57 #define checkForNameInNameSpaceAndReturnIfFound(namespace_decref) { \
58 if ( PyNamemapper_hasKey(nameSpace, nameChunks[0]) ) {\
59 theValue = PyNamemapper_valueForName(nameSpace, nameChunks, numChunks, executeCallables);\
60 if (namespace_decref) {\
61 Py_DECREF(nameSpace);\
63 if (wrapInternalNotFoundException(name, nameSpace)) {\
64 theValue = NULL;\
66 goto done;\
70 /* *************************************************************************** */
71 /* First the c versions of the functions */
72 /* *************************************************************************** */
74 static void
75 setNotFoundException(char *key, PyObject *namespace)
79 PyObject *exceptionStr = NULL;
80 exceptionStr = Py_BuildValue("s","cannot find '");
81 PyString_ConcatAndDel(&exceptionStr, Py_BuildValue("s", key));
82 PyString_ConcatAndDel(&exceptionStr, Py_BuildValue("s", "'"));
83 if (INCLUDE_NAMESPACE_REPR_IN_NOTFOUND_EXCEPTIONS) {
84 PyString_ConcatAndDel(&exceptionStr, Py_BuildValue("s", " in the namespace "));
85 PyString_ConcatAndDel(&exceptionStr,
86 PyObject_CallFunctionObjArgs(pprintMod_pformat, namespace, NULL));
88 PyErr_SetObject(NotFound, exceptionStr);
89 Py_DECREF(exceptionStr);
92 static int
93 wrapInternalNotFoundException(char *fullName, PyObject *namespace)
95 PyObject *excType, *excValue, *excTraceback, *isAlreadyWrapped = NULL;
96 if (!ALLOW_WRAPPING_OF_NOTFOUND_EXCEPTIONS) {
97 return 0;
99 if (PyErr_Occurred() && PyErr_GivenExceptionMatches(PyErr_Occurred(), NotFound)) {
100 PyErr_Fetch(&excType, &excValue, &excTraceback);
101 isAlreadyWrapped = PyObject_CallMethod(excValue, "find", "s", "while searching");
102 if (PyInt_AsLong(isAlreadyWrapped)==-1) { /* only wrap once */
103 PyString_ConcatAndDel(&excValue, Py_BuildValue("s", " while searching for '"));
104 PyString_ConcatAndDel(&excValue, Py_BuildValue("s", fullName));
105 PyString_ConcatAndDel(&excValue, Py_BuildValue("s", "'"));
106 if (INCLUDE_NAMESPACE_REPR_IN_NOTFOUND_EXCEPTIONS) {
107 PyString_ConcatAndDel(&excValue, Py_BuildValue("s", " in "));
108 PyString_ConcatAndDel(&excValue, Py_BuildValue("s", "the top-level namespace "));
109 PyString_ConcatAndDel(&excValue,
110 PyObject_CallFunctionObjArgs(pprintMod_pformat, namespace, NULL));
113 Py_DECREF(isAlreadyWrapped);
114 PyErr_Restore(excType, excValue, excTraceback);
115 return -1;
116 } else {
117 return 0;
121 static int getNameChunks(char *nameChunks[], char *name, char *nameCopy)
123 char c;
124 char *currChunk;
125 int currChunkNum = 0;
127 currChunk = nameCopy;
128 while ('\0' != (c = *nameCopy)){
129 if ('.' == c) {
130 if (currChunkNum >= (MAXCHUNKS-2)) { /* avoid overflowing nameChunks[] */
131 PyErr_SetString(TooManyPeriods, name);
132 return 0;
135 *nameCopy ='\0';
136 nameChunks[currChunkNum++] = currChunk;
137 nameCopy++;
138 currChunk = nameCopy;
139 } else
140 nameCopy++;
142 if (nameCopy > currChunk) {
143 nameChunks[currChunkNum++] = currChunk;
145 return currChunkNum;
149 static int
150 PyNamemapper_hasKey(PyObject *obj, char *key)
152 if (PyMapping_Check(obj) && PyMapping_HasKeyString(obj, key)) {
153 return TRUE;
154 } else if (PyObject_HasAttrString(obj, key)) {
155 return TRUE;
156 } else {
157 return FALSE;
162 static PyObject *
163 PyNamemapper_valueForKey(PyObject *obj, char *key)
165 PyObject *theValue = NULL;
167 if (PyMapping_Check(obj) && PyMapping_HasKeyString(obj, key)) {
168 theValue = PyMapping_GetItemString(obj, key);
169 } else if (PyObject_HasAttrString(obj, key)) {
170 theValue = PyObject_GetAttrString(obj, key);
172 } else {
173 setNotFoundException(key, obj);
176 return theValue;
179 static PyObject *
180 PyNamemapper_valueForName(PyObject *obj, char *nameChunks[],
181 int numChunks,
182 int executeCallables)
184 int i;
185 char *currentKey;
186 PyObject *currentVal = NULL;
187 PyObject *nextVal = NULL;
189 currentVal = obj;
190 for (i=0; i < numChunks;i++) {
191 currentKey = nameChunks[i];
192 if (PyErr_CheckSignals()) { /* not sure if I really need to do this here, but what the hell */
193 if (i>0) {
194 Py_DECREF(currentVal);
196 return NULL;
199 if (PyMapping_Check(currentVal) && PyMapping_HasKeyString(currentVal, currentKey)) {
200 nextVal = PyMapping_GetItemString(currentVal, currentKey);
201 } else if (PyObject_HasAttrString(currentVal, currentKey)) {
202 nextVal = PyObject_GetAttrString(currentVal, currentKey);
203 } else {
204 setNotFoundException(currentKey, currentVal);
205 if (i>0) {
206 Py_DECREF(currentVal);
208 return NULL;
210 if (i>0) {
211 Py_DECREF(currentVal);
213 if (executeCallables && PyCallable_Check(nextVal) && (!PyInstance_Check(nextVal))
214 && (!PyClass_Check(nextVal)) && (!PyType_Check(nextVal)) ) {
215 if (!(currentVal = PyObject_CallObject(nextVal, NULL))){
216 Py_DECREF(nextVal);
217 return NULL;
219 Py_DECREF(nextVal);
220 } else {
221 currentVal = nextVal;
225 return currentVal;
229 /* *************************************************************************** */
230 /* Now the wrapper functions to export into the Python module */
231 /* *************************************************************************** */
234 static PyObject *
235 namemapper_valueForKey(PyObject *self, PyObject *args)
237 PyObject *obj;
238 char *key;
240 if (!PyArg_ParseTuple(args, "Os", &obj, &key)) {
241 return NULL;
244 return PyNamemapper_valueForKey(obj, key);
248 static PyObject *
249 namemapper_valueForName(PyObject *self, PyObject *args, PyObject *keywds)
253 PyObject *obj;
254 char *name;
255 int executeCallables = 0;
257 char *nameCopy = NULL;
258 char *tmpPntr1 = NULL;
259 char *tmpPntr2 = NULL;
260 char *nameChunks[MAXCHUNKS];
261 int numChunks;
263 PyObject *theValue;
265 static char *kwlist[] = {"obj", "name", "executeCallables", NULL};
267 if (!PyArg_ParseTupleAndKeywords(args, keywds, "Os|i", kwlist, &obj, &name, &executeCallables)) {
268 return NULL;
271 createNameCopyAndChunks();
273 theValue = PyNamemapper_valueForName(obj, nameChunks, numChunks, executeCallables);
274 free(nameCopy);
275 if (wrapInternalNotFoundException(name, obj)) {
276 theValue = NULL;
278 return theValue;
282 static PyObject *
283 namemapper_valueFromSearchList(PyObject *self, PyObject *args, PyObject *keywds)
286 PyObject *searchList;
287 char *name;
288 int executeCallables = 0;
290 char *nameCopy = NULL;
291 char *tmpPntr1 = NULL;
292 char *tmpPntr2 = NULL;
293 char *nameChunks[MAXCHUNKS];
294 int numChunks;
296 PyObject *nameSpace = NULL;
297 PyObject *theValue = NULL;
298 PyObject *iterator = NULL;
300 static char *kwlist[] = {"searchList", "name", "executeCallables", NULL};
302 if (!PyArg_ParseTupleAndKeywords(args, keywds, "Os|i", kwlist, &searchList, &name,
303 &executeCallables)) {
304 return NULL;
307 createNameCopyAndChunks();
309 iterator = PyObject_GetIter(searchList);
310 if (iterator == NULL) {
311 PyErr_SetString(PyExc_TypeError,"This searchList is not iterable!");
312 goto done;
315 while ( (nameSpace = PyIter_Next(iterator)) ) {
316 checkForNameInNameSpaceAndReturnIfFound(TRUE);
317 Py_DECREF(nameSpace);
318 if(PyErr_CheckSignals()) {
319 theValue = NULL;
320 goto done;
323 if (PyErr_Occurred()) {
324 theValue = NULL;
325 goto done;
328 setNotFoundException(nameChunks[0], searchList);
329 done:
330 Py_XDECREF(iterator);
331 free(nameCopy);
332 return theValue;
335 static PyObject *
336 namemapper_valueFromFrameOrSearchList(PyObject *self, PyObject *args, PyObject *keywds)
339 /* python function args */
340 char *name;
341 int executeCallables = 0;
342 PyObject *searchList = NULL;
344 /* locals */
345 char *nameCopy = NULL;
346 char *tmpPntr1 = NULL;
347 char *tmpPntr2 = NULL;
348 char *nameChunks[MAXCHUNKS];
349 int numChunks;
351 PyObject *nameSpace = NULL;
352 PyObject *theValue = NULL;
353 PyObject *excString = NULL;
354 PyObject *iterator = NULL;
356 static char *kwlist[] = {"searchList", "name", "executeCallables", NULL};
358 if (!PyArg_ParseTupleAndKeywords(args, keywds, "Os|i", kwlist, &searchList, &name,
359 &executeCallables)) {
360 return NULL;
363 createNameCopyAndChunks();
365 nameSpace = PyEval_GetLocals();
366 checkForNameInNameSpaceAndReturnIfFound(FALSE);
368 iterator = PyObject_GetIter(searchList);
369 if (iterator == NULL) {
370 PyErr_SetString(PyExc_TypeError,"This searchList is not iterable!");
371 goto done;
373 while ( (nameSpace = PyIter_Next(iterator)) ) {
374 checkForNameInNameSpaceAndReturnIfFound(TRUE);
375 Py_DECREF(nameSpace);
376 if(PyErr_CheckSignals()) {
377 theValue = NULL;
378 goto done;
381 if (PyErr_Occurred()) {
382 theValue = NULL;
383 goto done;
386 nameSpace = PyEval_GetGlobals();
387 checkForNameInNameSpaceAndReturnIfFound(FALSE);
389 nameSpace = PyEval_GetBuiltins();
390 checkForNameInNameSpaceAndReturnIfFound(FALSE);
392 excString = Py_BuildValue("s", "[locals()]+searchList+[globals(), __builtins__]");
393 setNotFoundException(nameChunks[0], excString);
394 Py_DECREF(excString);
396 done:
397 Py_XDECREF(iterator);
398 free(nameCopy);
399 return theValue;
402 static PyObject *
403 namemapper_valueFromFrame(PyObject *self, PyObject *args, PyObject *keywds)
406 /* python function args */
407 char *name;
408 int executeCallables = 0;
410 /* locals */
411 char *tmpPntr1 = NULL;
412 char *tmpPntr2 = NULL;
414 char *nameCopy = NULL;
415 char *nameChunks[MAXCHUNKS];
416 int numChunks;
418 PyObject *nameSpace = NULL;
419 PyObject *theValue = NULL;
420 PyObject *excString = NULL;
422 static char *kwlist[] = {"name", "executeCallables", NULL};
424 if (!PyArg_ParseTupleAndKeywords(args, keywds, "s|i", kwlist, &name, &executeCallables)) {
425 return NULL;
428 createNameCopyAndChunks();
430 nameSpace = PyEval_GetLocals();
431 checkForNameInNameSpaceAndReturnIfFound(FALSE);
433 nameSpace = PyEval_GetGlobals();
434 checkForNameInNameSpaceAndReturnIfFound(FALSE);
436 nameSpace = PyEval_GetBuiltins();
437 checkForNameInNameSpaceAndReturnIfFound(FALSE);
439 excString = Py_BuildValue("s", "[locals(), globals(), __builtins__]");
440 setNotFoundException(nameChunks[0], excString);
441 Py_DECREF(excString);
442 done:
443 free(nameCopy);
444 return theValue;
447 /* *************************************************************************** */
448 /* Method registration table: name-string -> function-pointer */
450 static struct PyMethodDef namemapper_methods[] = {
451 {"valueForKey", namemapper_valueForKey, 1},
452 {"valueForName", (PyCFunction)namemapper_valueForName, METH_VARARGS|METH_KEYWORDS},
453 {"valueFromSearchList", (PyCFunction)namemapper_valueFromSearchList, METH_VARARGS|METH_KEYWORDS},
454 {"valueFromFrame", (PyCFunction)namemapper_valueFromFrame, METH_VARARGS|METH_KEYWORDS},
455 {"valueFromFrameOrSearchList", (PyCFunction)namemapper_valueFromFrameOrSearchList, METH_VARARGS|METH_KEYWORDS},
456 {NULL, NULL}
460 /* *************************************************************************** */
461 /* Initialization function (import-time) */
463 DL_EXPORT(void)
464 init_namemapper(void)
466 PyObject *m, *d, *pprintMod;
468 /* create the module and add the functions */
469 m = Py_InitModule("_namemapper", namemapper_methods); /* registration hook */
471 /* add symbolic constants to the module */
472 d = PyModule_GetDict(m);
473 NotFound = PyErr_NewException("NameMapper.NotFound",PyExc_LookupError,NULL);
474 TooManyPeriods = PyErr_NewException("NameMapper.TooManyPeriodsInName",NULL,NULL);
475 PyDict_SetItemString(d, "NotFound", NotFound);
476 PyDict_SetItemString(d, "TooManyPeriodsInName", TooManyPeriods);
477 pprintMod = PyImport_ImportModule("pprint"); /* error check this */
478 pprintMod_pformat = PyObject_GetAttrString(pprintMod, "pformat");
479 Py_DECREF(pprintMod);
480 /* check for errors */
481 if (PyErr_Occurred())
482 Py_FatalError("Can't initialize module _namemapper");
485 #ifdef __cplusplus
487 #endif