PyErr_SetFromErrnoWithFilename(PyExc_OSError, name); \
goto end; \
} while (0)
-#define PGENERR do { pgenerr(); goto end; } while (0)
+#define PGENERR(exc) do { pgenerr(exc); goto end; } while (0)
#define CONVFUNC(ty, cty, ext) \
int conv##ty(PyObject *o, void *p) \
} while (0)
#define INITTYPE(ty, base) INITTYPE_META(ty, base, type)
-#define INSERT(name, ob) do { \
+extern PyObject *home_module;
+
+#define INSERT(name, ob) do { \
PyObject *_o = (PyObject *)(ob); \
Py_INCREF(_o); \
PyModule_AddObject(mod, name, _o); \
extern PyObject *getk64(kludge64);
extern void *newtype(PyTypeObject *, const PyTypeObject *, const char *);
+struct excinfo { PyObject *ty, *val, *tb; };
+#define EXCINFO_INIT { 0, 0, 0 }
+
extern PyObject *mkexc(PyObject *, PyObject *, const char *, PyMethodDef *);
+#define INIT_EXCINFO(exc) do { \
+ struct excinfo *_exc = (exc); _exc->ty = _exc->val = _exc->tb = 0; \
+} while (0)
+#define RELEASE_EXCINFO(exc) do { \
+ struct excinfo *_exc = (exc); \
+ Py_XDECREF(_exc->ty); _exc->ty = 0; \
+ Py_XDECREF(_exc->val); _exc->val = 0; \
+ Py_XDECREF(_exc->tb); _exc->tb = 0; \
+} while (0)
+#define STASH_EXCINFO(exc) do { \
+ struct excinfo *_exc = (exc); \
+ PyErr_Fetch(&_exc->ty, &_exc->val, &_exc->tb); \
+ PyErr_NormalizeException(&_exc->ty, &_exc->val, &_exc->tb); \
+} while (0)
+#define RESTORE_EXCINFO(exc) do { \
+ struct excinfo *_exc = (exc); \
+ PyErr_Restore(_exc->ty, _exc->val, _exc->tb); \
+ _exc->ty = _exc->val = _exc->tb = 0; \
+} while (0)
+extern void report_lost_exception(struct excinfo *, const char *, ...);
+extern void report_lost_exception_v(struct excinfo *, const char *, va_list);
+extern void stash_exception(struct excinfo *, const char *, ...);
+extern void restore_exception(struct excinfo *, const char *, ...);
+
extern void typeready(PyTypeObject *);
extern PyTypeObject *inittype(PyTypeObject *, PyTypeObject *);
extern void addmethods(const PyMethodDef *);
#define PGEV_PYCHECK(o) PyObject_TypeCheck(o, pgev_pytype)
#define PGEV_PG(o) (&((pgev_pyobj *)(o))->pg)
+typedef struct pypgev {
+ pgev ev;
+ PyObject *obj;
+ struct excinfo *exc;
+} pypgev;
+
extern int convpgev(PyObject *, void *);
-extern void droppgev(pgev *);
-extern void pgenerr(void);
+extern void droppgev(pypgev *);
+extern void pgenerr(struct excinfo *exc);
/*----- That's all, folks -------------------------------------------------*/
/*----- External values ---------------------------------------------------*/
static PyObject *modname = 0;
+PyObject *home_module = 0;
/*----- Conversions -------------------------------------------------------*/
goto done;
}
+void report_lost_exception_v(struct excinfo *exc,
+ const char *why, va_list ap)
+{
+ PyObject *hookfn = 0;
+ PyObject *whyobj = 0;
+ PyObject *obj = 0;
+
+ /* Make sure we start out without a pending exception, or this will get
+ * really confusing.
+ */
+ assert(!PyErr_Occurred());
+
+ /* Format the explanation. */
+ if (why) whyobj = PyString_FromFormatV(why, ap);
+ else { whyobj = Py_None; Py_INCREF(whyobj); }
+
+ /* Find our home module's `lostexchook' function. This won't work if
+ * there's no module, or the function isn't defined, or it's `None'.
+ */
+ if (!home_module) goto sys;
+ hookfn = PyObject_GetAttrString(home_module, "lostexchook");
+ if (hookfn == Py_None) goto sys;
+ else if (hookfn) ;
+ else if (!PyErr_ExceptionMatches(PyExc_AttributeError)) goto ouch;
+ else { PyErr_Clear(); goto sys; }
+
+ /* Call the hook function. */
+ obj = PyObject_CallFunction(hookfn, "(OOOO)",
+ whyobj, exc->ty, exc->val, exc->tb);
+ if (!obj) goto ouch;
+ goto end;
+
+ /* Something went wrong reporting the problem. */
+ouch:
+ PySys_WriteStderr("\n!!! FAILURE REPORTING LOST EXCEPTION\n");
+ PyErr_Print();
+ /* drop through... */
+
+ /* There was no hook, so try to do something sensible using
+ * `sys.excepthook'.
+ */
+sys:
+ PySys_WriteStderr("\n!!! LOST EXCEPTION: %s\n",
+ PyString_AS_STRING(whyobj));
+ RESTORE_EXCINFO(exc);
+ PyErr_Print();
+ /* drop through... */
+
+ /* Clean up afterwards. */
+end:
+ Py_XDECREF(hookfn);
+ Py_XDECREF(whyobj);
+ Py_XDECREF(obj);
+}
+
+void report_lost_exception(struct excinfo *exc, const char *why, ...)
+{
+ va_list ap;
+
+ va_start(ap, why);
+ report_lost_exception_v(exc, why, ap);
+ va_end(ap);
+}
+
+void stash_exception(struct excinfo *exc, const char *why, ...)
+{
+ va_list ap;
+ struct excinfo stash;
+
+ if (!exc->ty)
+ STASH_EXCINFO(exc);
+ else {
+ va_start(ap, why);
+ STASH_EXCINFO(&stash);
+ report_lost_exception_v(&stash, why, ap);
+ va_end(ap);
+ }
+}
+
+void restore_exception(struct excinfo *exc, const char *why, ...)
+{
+ va_list ap;
+ struct excinfo stash;
+
+ if (!PyErr_Occurred())
+ RESTORE_EXCINFO(exc);
+ else {
+ va_start(ap, why);
+ STASH_EXCINFO(&stash);
+ report_lost_exception_v(exc, why, ap);
+ RESTORE_EXCINFO(&stash);
+ va_end(ap);
+ }
+}
+
/*----- Generic dictionary methods ----------------------------------------*/
static PyTypeObject *itemiter_pytype, *valiter_pytype;
/*----- Initialization ----------------------------------------------------*/
+static PyObject *meth__set_home_module(PyObject *me, PyObject *arg)
+{
+ PyObject *mod;
+
+ if (!PyArg_ParseTuple(arg, "O!:_set_home_module", &PyModule_Type, &mod))
+ return (0);
+ Py_XDECREF(home_module); home_module = mod; Py_INCREF(home_module);
+ RETURN_NONE;
+}
+
+static const PyMethodDef methods[] = {
+#define METHNAME(func) meth_##func
+ METH (_set_home_module, "_set_home_module(MOD)")
+#undef METHNAME
+ { 0 }
+};
+
void util_pyinit(void)
{
modname = PyString_FromString("catacomb");
INITTYPE(itemiter, root);
INITTYPE(valiter, root);
+ addmethods(methods);
}
void util_pyinsert(PyObject *mod)