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.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 */
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");
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
);
124 static int getNameChunks(char *nameChunks
[], char *name
, char *nameCopy
)
128 int currChunkNum
= 0;
130 currChunk
= nameCopy
;
131 while ('\0' != (c
= *nameCopy
)){
133 if (currChunkNum
>= (MAXCHUNKS
-2)) { /* avoid overflowing nameChunks[] */
134 PyErr_SetString(TooManyPeriods
, name
);
139 nameChunks
[currChunkNum
++] = currChunk
;
141 currChunk
= nameCopy
;
145 if (nameCopy
> currChunk
) {
146 nameChunks
[currChunkNum
++] = currChunk
;
153 PyNamemapper_hasKey(PyObject
*obj
, char *key
)
155 if (PyMapping_Check(obj
) && PyMapping_HasKeyString(obj
, key
)) {
157 } else if (PyObject_HasAttrString(obj
, key
)) {
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
);
176 setNotFoundException(key
, obj
);
183 PyNamemapper_valueForName(PyObject
*obj
, char *nameChunks
[],
185 int executeCallables
)
189 PyObject
*currentVal
= NULL
;
190 PyObject
*nextVal
= NULL
;
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 */
197 Py_DECREF(currentVal
);
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
);
207 setNotFoundException(currentKey
, currentVal
);
209 Py_DECREF(currentVal
);
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
))){
224 currentVal
= nextVal
;
232 /* *************************************************************************** */
233 /* Now the wrapper functions to export into the Python module */
234 /* *************************************************************************** */
238 namemapper_valueForKey(PyObject
*self
, PyObject
*args
)
243 if (!PyArg_ParseTuple(args
, "Os", &obj
, &key
)) {
247 return PyNamemapper_valueForKey(obj
, key
);
252 namemapper_valueForName(PyObject
*self
, PyObject
*args
, PyObject
*keywds
)
258 int executeCallables
= 0;
260 char *nameCopy
= NULL
;
261 char *tmpPntr1
= NULL
;
262 char *tmpPntr2
= NULL
;
263 char *nameChunks
[MAXCHUNKS
];
268 static char *kwlist
[] = {"obj", "name", "executeCallables", NULL
};
270 if (!PyArg_ParseTupleAndKeywords(args
, keywds
, "Os|i", kwlist
, &obj
, &name
, &executeCallables
)) {
274 createNameCopyAndChunks();
276 theValue
= PyNamemapper_valueForName(obj
, nameChunks
, numChunks
, executeCallables
);
278 if (wrapInternalNotFoundException(name
, obj
)) {
286 namemapper_valueFromSearchList(PyObject
*self
, PyObject
*args
, PyObject
*keywds
)
289 PyObject
*searchList
;
291 int executeCallables
= 0;
293 char *nameCopy
= NULL
;
294 char *tmpPntr1
= NULL
;
295 char *tmpPntr2
= NULL
;
296 char *nameChunks
[MAXCHUNKS
];
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
)) {
310 createNameCopyAndChunks();
312 iterator
= PyObject_GetIter(searchList
);
313 if (iterator
== NULL
) {
314 PyErr_SetString(PyExc_TypeError
,"This searchList is not iterable!");
318 while ( (nameSpace
= PyIter_Next(iterator
)) ) {
319 checkForNameInNameSpaceAndReturnIfFound(TRUE
);
320 Py_DECREF(nameSpace
);
321 if(PyErr_CheckSignals()) {
326 if (PyErr_Occurred()) {
331 setNotFoundException(nameChunks
[0], searchList
);
333 Py_XDECREF(iterator
);
339 namemapper_valueFromFrameOrSearchList(PyObject
*self
, PyObject
*args
, PyObject
*keywds
)
342 /* python function args */
344 int executeCallables
= 0;
345 PyObject
*searchList
= NULL
;
348 char *nameCopy
= NULL
;
349 char *tmpPntr1
= NULL
;
350 char *tmpPntr2
= NULL
;
351 char *nameChunks
[MAXCHUNKS
];
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
)) {
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!");
376 while ( (nameSpace
= PyIter_Next(iterator
)) ) {
377 checkForNameInNameSpaceAndReturnIfFound(TRUE
);
378 Py_DECREF(nameSpace
);
379 if(PyErr_CheckSignals()) {
384 if (PyErr_Occurred()) {
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
);
400 Py_XDECREF(iterator
);
406 namemapper_valueFromFrame(PyObject
*self
, PyObject
*args
, PyObject
*keywds
)
409 /* python function args */
411 int executeCallables
= 0;
414 char *tmpPntr1
= NULL
;
415 char *tmpPntr2
= NULL
;
417 char *nameCopy
= NULL
;
418 char *nameChunks
[MAXCHUNKS
];
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
)) {
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
);
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
},
463 /* *************************************************************************** */
464 /* Initialization function (import-time) */
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");