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
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 */
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 */
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);\
38 while ((*tmpPntr2++ = *tmpPntr1++)); \
39 numChunks = getNameChunks(nameChunks, name, nameCopy); \
40 if (PyErr_Occurred()) { /* there might have been TooManyPeriods */\
46 #define OLD_checkForNameInNameSpaceAndReturnIfFound() { \
47 if ( PyNamemapper_hasKey(nameSpace, nameChunks[0]) ) {\
48 theValue = PyNamemapper_valueForName(nameSpace, nameChunks, numChunks, executeCallables);\
50 if (wrapInternalNotFoundException(name, nameSpace)) {\
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)) {\
70 /* *************************************************************************** */
71 /* First the c versions of the functions */
72 /* *************************************************************************** */
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
);
93 wrapInternalNotFoundException(char *fullName
, PyObject
*namespace)
95 PyObject
*excType
, *excValue
, *excTraceback
, *isAlreadyWrapped
= NULL
;
96 if (!ALLOW_WRAPPING_OF_NOTFOUND_EXCEPTIONS
) {
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
);
121 static int getNameChunks(char *nameChunks
[], char *name
, char *nameCopy
)
125 int currChunkNum
= 0;
127 currChunk
= nameCopy
;
128 while ('\0' != (c
= *nameCopy
)){
130 if (currChunkNum
>= (MAXCHUNKS
-2)) { /* avoid overflowing nameChunks[] */
131 PyErr_SetString(TooManyPeriods
, name
);
136 nameChunks
[currChunkNum
++] = currChunk
;
138 currChunk
= nameCopy
;
142 if (nameCopy
> currChunk
) {
143 nameChunks
[currChunkNum
++] = currChunk
;
150 PyNamemapper_hasKey(PyObject
*obj
, char *key
)
152 if (PyMapping_Check(obj
) && PyMapping_HasKeyString(obj
, key
)) {
154 } else if (PyObject_HasAttrString(obj
, key
)) {
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
);
173 setNotFoundException(key
, obj
);
180 PyNamemapper_valueForName(PyObject
*obj
, char *nameChunks
[],
182 int executeCallables
)
186 PyObject
*currentVal
= NULL
;
187 PyObject
*nextVal
= NULL
;
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 */
194 Py_DECREF(currentVal
);
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
);
204 setNotFoundException(currentKey
, currentVal
);
206 Py_DECREF(currentVal
);
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
))){
221 currentVal
= nextVal
;
229 /* *************************************************************************** */
230 /* Now the wrapper functions to export into the Python module */
231 /* *************************************************************************** */
235 namemapper_valueForKey(PyObject
*self
, PyObject
*args
)
240 if (!PyArg_ParseTuple(args
, "Os", &obj
, &key
)) {
244 return PyNamemapper_valueForKey(obj
, key
);
249 namemapper_valueForName(PyObject
*self
, PyObject
*args
, PyObject
*keywds
)
255 int executeCallables
= 0;
257 char *nameCopy
= NULL
;
258 char *tmpPntr1
= NULL
;
259 char *tmpPntr2
= NULL
;
260 char *nameChunks
[MAXCHUNKS
];
265 static char *kwlist
[] = {"obj", "name", "executeCallables", NULL
};
267 if (!PyArg_ParseTupleAndKeywords(args
, keywds
, "Os|i", kwlist
, &obj
, &name
, &executeCallables
)) {
271 createNameCopyAndChunks();
273 theValue
= PyNamemapper_valueForName(obj
, nameChunks
, numChunks
, executeCallables
);
275 if (wrapInternalNotFoundException(name
, obj
)) {
283 namemapper_valueFromSearchList(PyObject
*self
, PyObject
*args
, PyObject
*keywds
)
286 PyObject
*searchList
;
288 int executeCallables
= 0;
290 char *nameCopy
= NULL
;
291 char *tmpPntr1
= NULL
;
292 char *tmpPntr2
= NULL
;
293 char *nameChunks
[MAXCHUNKS
];
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
)) {
307 createNameCopyAndChunks();
309 iterator
= PyObject_GetIter(searchList
);
310 if (iterator
== NULL
) {
311 PyErr_SetString(PyExc_TypeError
,"This searchList is not iterable!");
315 while ( (nameSpace
= PyIter_Next(iterator
)) ) {
316 checkForNameInNameSpaceAndReturnIfFound(TRUE
);
317 Py_DECREF(nameSpace
);
318 if(PyErr_CheckSignals()) {
323 if (PyErr_Occurred()) {
328 setNotFoundException(nameChunks
[0], searchList
);
330 Py_XDECREF(iterator
);
336 namemapper_valueFromFrameOrSearchList(PyObject
*self
, PyObject
*args
, PyObject
*keywds
)
339 /* python function args */
341 int executeCallables
= 0;
342 PyObject
*searchList
= NULL
;
345 char *nameCopy
= NULL
;
346 char *tmpPntr1
= NULL
;
347 char *tmpPntr2
= NULL
;
348 char *nameChunks
[MAXCHUNKS
];
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
)) {
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!");
373 while ( (nameSpace
= PyIter_Next(iterator
)) ) {
374 checkForNameInNameSpaceAndReturnIfFound(TRUE
);
375 Py_DECREF(nameSpace
);
376 if(PyErr_CheckSignals()) {
381 if (PyErr_Occurred()) {
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
);
397 Py_XDECREF(iterator
);
403 namemapper_valueFromFrame(PyObject
*self
, PyObject
*args
, PyObject
*keywds
)
406 /* python function args */
408 int executeCallables
= 0;
411 char *tmpPntr1
= NULL
;
412 char *tmpPntr2
= NULL
;
414 char *nameCopy
= NULL
;
415 char *nameChunks
[MAXCHUNKS
];
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
)) {
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
);
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
},
460 /* *************************************************************************** */
461 /* Initialization function (import-time) */
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");