Simplify auth.
[pyTivo/wmcbrine/lucasnz.git] / Cheetah / _namemapper.c
blob30b68cfc978d17e25757db0befb56a113c41c970
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.33 2007/10/08 04:01:24 tavis_rudd Exp $
8 Authors: Tavis Rudd <tavis@damnsimple.com>
9 Version: $Revision: 1.33 $
10 Start Date: 2001/08/07
11 Last Revision Date: $Date: 2007/10/08 04:01:24 $
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");
103 if (isAlreadyWrapped != NULL) {
104 if (PyInt_AsLong(isAlreadyWrapped)==-1) { /* only wrap once */
105 PyString_ConcatAndDel(&excValue, Py_BuildValue("s", " while searching for '"));
106 PyString_ConcatAndDel(&excValue, Py_BuildValue("s", fullName));
107 PyString_ConcatAndDel(&excValue, Py_BuildValue("s", "'"));
108 if (INCLUDE_NAMESPACE_REPR_IN_NOTFOUND_EXCEPTIONS) {
109 PyString_ConcatAndDel(&excValue, Py_BuildValue("s", " in "));
110 PyString_ConcatAndDel(&excValue, Py_BuildValue("s", "the top-level namespace "));
111 PyString_ConcatAndDel(&excValue,
112 PyObject_CallFunctionObjArgs(pprintMod_pformat, namespace, NULL));
115 Py_DECREF(isAlreadyWrapped);
117 PyErr_Restore(excType, excValue, excTraceback);
118 return -1;
119 } else {
120 return 0;
124 static int getNameChunks(char *nameChunks[], char *name, char *nameCopy)
126 char c;
127 char *currChunk;
128 int currChunkNum = 0;
130 currChunk = nameCopy;
131 while ('\0' != (c = *nameCopy)){
132 if ('.' == c) {
133 if (currChunkNum >= (MAXCHUNKS-2)) { /* avoid overflowing nameChunks[] */
134 PyErr_SetString(TooManyPeriods, name);
135 return 0;
138 *nameCopy ='\0';
139 nameChunks[currChunkNum++] = currChunk;
140 nameCopy++;
141 currChunk = nameCopy;
142 } else
143 nameCopy++;
145 if (nameCopy > currChunk) {
146 nameChunks[currChunkNum++] = currChunk;
148 return currChunkNum;
152 static int
153 PyNamemapper_hasKey(PyObject *obj, char *key)
155 if (PyMapping_Check(obj) && PyMapping_HasKeyString(obj, key)) {
156 return TRUE;
157 } else if (PyObject_HasAttrString(obj, key)) {
158 return TRUE;
159 } else {
160 return FALSE;
165 static PyObject *
166 PyNamemapper_valueForKey(PyObject *obj, char *key)
168 PyObject *theValue = NULL;
170 if (PyMapping_Check(obj) && PyMapping_HasKeyString(obj, key)) {
171 theValue = PyMapping_GetItemString(obj, key);
172 } else if (PyObject_HasAttrString(obj, key)) {
173 theValue = PyObject_GetAttrString(obj, key);
175 } else {
176 setNotFoundException(key, obj);
179 return theValue;
182 static PyObject *
183 PyNamemapper_valueForName(PyObject *obj, char *nameChunks[],
184 int numChunks,
185 int executeCallables)
187 int i;
188 char *currentKey;
189 PyObject *currentVal = NULL;
190 PyObject *nextVal = NULL;
192 currentVal = obj;
193 for (i=0; i < numChunks;i++) {
194 currentKey = nameChunks[i];
195 if (PyErr_CheckSignals()) { /* not sure if I really need to do this here, but what the hell */
196 if (i>0) {
197 Py_DECREF(currentVal);
199 return NULL;
202 if (PyMapping_Check(currentVal) && PyMapping_HasKeyString(currentVal, currentKey)) {
203 nextVal = PyMapping_GetItemString(currentVal, currentKey);
204 } else if (PyObject_HasAttrString(currentVal, currentKey)) {
205 nextVal = PyObject_GetAttrString(currentVal, currentKey);
206 } else {
207 setNotFoundException(currentKey, currentVal);
208 if (i>0) {
209 Py_DECREF(currentVal);
211 return NULL;
213 if (i>0) {
214 Py_DECREF(currentVal);
216 if (executeCallables && PyCallable_Check(nextVal) && (!PyInstance_Check(nextVal))
217 && (!PyClass_Check(nextVal)) && (!PyType_Check(nextVal)) ) {
218 if (!(currentVal = PyObject_CallObject(nextVal, NULL))){
219 Py_DECREF(nextVal);
220 return NULL;
222 Py_DECREF(nextVal);
223 } else {
224 currentVal = nextVal;
228 return currentVal;
232 /* *************************************************************************** */
233 /* Now the wrapper functions to export into the Python module */
234 /* *************************************************************************** */
237 static PyObject *
238 namemapper_valueForKey(PyObject *self, PyObject *args)
240 PyObject *obj;
241 char *key;
243 if (!PyArg_ParseTuple(args, "Os", &obj, &key)) {
244 return NULL;
247 return PyNamemapper_valueForKey(obj, key);
251 static PyObject *
252 namemapper_valueForName(PyObject *self, PyObject *args, PyObject *keywds)
256 PyObject *obj;
257 char *name;
258 int executeCallables = 0;
260 char *nameCopy = NULL;
261 char *tmpPntr1 = NULL;
262 char *tmpPntr2 = NULL;
263 char *nameChunks[MAXCHUNKS];
264 int numChunks;
266 PyObject *theValue;
268 static char *kwlist[] = {"obj", "name", "executeCallables", NULL};
270 if (!PyArg_ParseTupleAndKeywords(args, keywds, "Os|i", kwlist, &obj, &name, &executeCallables)) {
271 return NULL;
274 createNameCopyAndChunks();
276 theValue = PyNamemapper_valueForName(obj, nameChunks, numChunks, executeCallables);
277 free(nameCopy);
278 if (wrapInternalNotFoundException(name, obj)) {
279 theValue = NULL;
281 return theValue;
285 static PyObject *
286 namemapper_valueFromSearchList(PyObject *self, PyObject *args, PyObject *keywds)
289 PyObject *searchList;
290 char *name;
291 int executeCallables = 0;
293 char *nameCopy = NULL;
294 char *tmpPntr1 = NULL;
295 char *tmpPntr2 = NULL;
296 char *nameChunks[MAXCHUNKS];
297 int numChunks;
299 PyObject *nameSpace = NULL;
300 PyObject *theValue = NULL;
301 PyObject *iterator = NULL;
303 static char *kwlist[] = {"searchList", "name", "executeCallables", NULL};
305 if (!PyArg_ParseTupleAndKeywords(args, keywds, "Os|i", kwlist, &searchList, &name,
306 &executeCallables)) {
307 return NULL;
310 createNameCopyAndChunks();
312 iterator = PyObject_GetIter(searchList);
313 if (iterator == NULL) {
314 PyErr_SetString(PyExc_TypeError,"This searchList is not iterable!");
315 goto done;
318 while ( (nameSpace = PyIter_Next(iterator)) ) {
319 checkForNameInNameSpaceAndReturnIfFound(TRUE);
320 Py_DECREF(nameSpace);
321 if(PyErr_CheckSignals()) {
322 theValue = NULL;
323 goto done;
326 if (PyErr_Occurred()) {
327 theValue = NULL;
328 goto done;
331 setNotFoundException(nameChunks[0], searchList);
332 done:
333 Py_XDECREF(iterator);
334 free(nameCopy);
335 return theValue;
338 static PyObject *
339 namemapper_valueFromFrameOrSearchList(PyObject *self, PyObject *args, PyObject *keywds)
342 /* python function args */
343 char *name;
344 int executeCallables = 0;
345 PyObject *searchList = NULL;
347 /* locals */
348 char *nameCopy = NULL;
349 char *tmpPntr1 = NULL;
350 char *tmpPntr2 = NULL;
351 char *nameChunks[MAXCHUNKS];
352 int numChunks;
354 PyObject *nameSpace = NULL;
355 PyObject *theValue = NULL;
356 PyObject *excString = NULL;
357 PyObject *iterator = NULL;
359 static char *kwlist[] = {"searchList", "name", "executeCallables", NULL};
361 if (!PyArg_ParseTupleAndKeywords(args, keywds, "Os|i", kwlist, &searchList, &name,
362 &executeCallables)) {
363 return NULL;
366 createNameCopyAndChunks();
368 nameSpace = PyEval_GetLocals();
369 checkForNameInNameSpaceAndReturnIfFound(FALSE);
371 iterator = PyObject_GetIter(searchList);
372 if (iterator == NULL) {
373 PyErr_SetString(PyExc_TypeError,"This searchList is not iterable!");
374 goto done;
376 while ( (nameSpace = PyIter_Next(iterator)) ) {
377 checkForNameInNameSpaceAndReturnIfFound(TRUE);
378 Py_DECREF(nameSpace);
379 if(PyErr_CheckSignals()) {
380 theValue = NULL;
381 goto done;
384 if (PyErr_Occurred()) {
385 theValue = NULL;
386 goto done;
389 nameSpace = PyEval_GetGlobals();
390 checkForNameInNameSpaceAndReturnIfFound(FALSE);
392 nameSpace = PyEval_GetBuiltins();
393 checkForNameInNameSpaceAndReturnIfFound(FALSE);
395 excString = Py_BuildValue("s", "[locals()]+searchList+[globals(), __builtins__]");
396 setNotFoundException(nameChunks[0], excString);
397 Py_DECREF(excString);
399 done:
400 Py_XDECREF(iterator);
401 free(nameCopy);
402 return theValue;
405 static PyObject *
406 namemapper_valueFromFrame(PyObject *self, PyObject *args, PyObject *keywds)
409 /* python function args */
410 char *name;
411 int executeCallables = 0;
413 /* locals */
414 char *tmpPntr1 = NULL;
415 char *tmpPntr2 = NULL;
417 char *nameCopy = NULL;
418 char *nameChunks[MAXCHUNKS];
419 int numChunks;
421 PyObject *nameSpace = NULL;
422 PyObject *theValue = NULL;
423 PyObject *excString = NULL;
425 static char *kwlist[] = {"name", "executeCallables", NULL};
427 if (!PyArg_ParseTupleAndKeywords(args, keywds, "s|i", kwlist, &name, &executeCallables)) {
428 return NULL;
431 createNameCopyAndChunks();
433 nameSpace = PyEval_GetLocals();
434 checkForNameInNameSpaceAndReturnIfFound(FALSE);
436 nameSpace = PyEval_GetGlobals();
437 checkForNameInNameSpaceAndReturnIfFound(FALSE);
439 nameSpace = PyEval_GetBuiltins();
440 checkForNameInNameSpaceAndReturnIfFound(FALSE);
442 excString = Py_BuildValue("s", "[locals(), globals(), __builtins__]");
443 setNotFoundException(nameChunks[0], excString);
444 Py_DECREF(excString);
445 done:
446 free(nameCopy);
447 return theValue;
450 /* *************************************************************************** */
451 /* Method registration table: name-string -> function-pointer */
453 static struct PyMethodDef namemapper_methods[] = {
454 {"valueForKey", namemapper_valueForKey, 1},
455 {"valueForName", (PyCFunction)namemapper_valueForName, METH_VARARGS|METH_KEYWORDS},
456 {"valueFromSearchList", (PyCFunction)namemapper_valueFromSearchList, METH_VARARGS|METH_KEYWORDS},
457 {"valueFromFrame", (PyCFunction)namemapper_valueFromFrame, METH_VARARGS|METH_KEYWORDS},
458 {"valueFromFrameOrSearchList", (PyCFunction)namemapper_valueFromFrameOrSearchList, METH_VARARGS|METH_KEYWORDS},
459 {NULL, NULL}
463 /* *************************************************************************** */
464 /* Initialization function (import-time) */
466 DL_EXPORT(void)
467 init_namemapper(void)
469 PyObject *m, *d, *pprintMod;
471 /* create the module and add the functions */
472 m = Py_InitModule("_namemapper", namemapper_methods); /* registration hook */
474 /* add symbolic constants to the module */
475 d = PyModule_GetDict(m);
476 NotFound = PyErr_NewException("NameMapper.NotFound",PyExc_LookupError,NULL);
477 TooManyPeriods = PyErr_NewException("NameMapper.TooManyPeriodsInName",NULL,NULL);
478 PyDict_SetItemString(d, "NotFound", NotFound);
479 PyDict_SetItemString(d, "TooManyPeriodsInName", TooManyPeriods);
480 pprintMod = PyImport_ImportModule("pprint"); /* error check this */
481 pprintMod_pformat = PyObject_GetAttrString(pprintMod, "pformat");
482 Py_DECREF(pprintMod);
483 /* check for errors */
484 if (PyErr_Occurred())
485 Py_FatalError("Can't initialize module _namemapper");
488 #ifdef __cplusplus
490 #endif