goto end; \
} while (0)
#define VALERR(str) EXCERR(PyExc_ValueError, str)
+#define OVFERR(str) EXCERR(PyExc_OverflowError, str)
#define TYERR(str) EXCERR(PyExc_TypeError, str)
#define IXERR(str) EXCERR(PyExc_IndexError, str)
#define ZDIVERR(str) EXCERR(PyExc_ZeroDivisionError, str)
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); \
#define KWLIST (/*unconst*/ char **)kwlist
-struct nameval { const char *name; unsigned long value; };
+struct nameval { const char *name; unsigned f; unsigned long value; };
+#define CF_SIGNED 1u
extern void setconstants(PyObject *, const struct nameval *);
extern PyObject *mexp_common(PyObject *, PyObject *, size_t,
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 *);
extern int convgf(PyObject *, void *);
extern PyObject *mp_pywrap(mp *);
extern PyObject *gf_pywrap(mp *);
+extern long mphash(mp *);
extern mp *mp_frompyobject(PyObject *, int);
extern PyObject *mp_topystring(mp *, int,
const char *, const char *, const char *);
#define FE_FOBJ(o) ((PyObject *)(o)->ob_type)
#define FE_X(o) (((fe_pyobj *)(o))->x)
extern PyObject *fe_pywrap(PyObject *, mp *);
-extern mp *getfe(field *, PyObject *);
typedef struct fe_pyobj {
PyObject_HEAD
#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 -------------------------------------------------*/
/*----- Main code ---------------------------------------------------------*/
static const struct nameval consts[] = {
-#define C(x) { #x, x }
+#define CF(f, x) { #x, f, x }
+#define C(x) { #x, (x) >= 0 ? 0 : CF_SIGNED, x }
C(FTY_PRIME), C(FTY_BINARY),
C(PGEN_PASS), C(PGEN_FAIL), C(PGEN_BEGIN), C(PGEN_TRY), C(PGEN_DONE),
C(PGEN_ABORT),
C(MPW_MAX),
+ C(RAND_IBITS),
C(PMODE_READ), C(PMODE_VERIFY),
C(KOPEN_READ), C(KOPEN_WRITE), C(KOPEN_NOFILE),
- C(KEXP_FOREVER), C(KEXP_EXPIRE),
+ CF(0, KEXP_FOREVER), CF(0, KEXP_EXPIRE),
C(KF_ENCMASK), C(KENC_BINARY), C(KENC_MP), C(KENC_STRUCT),
C(KENC_ENCRYPT), C(KENC_STRING), C(KENC_EC),
C(KF_CATMASK), C(KCAT_SYMM), C(KCAT_PRIV), C(KCAT_PUB), C(KCAT_SHARE),
KEY_ERRORS(ENTRY)
#undef ENTRY
#undef C
+#undef CF
{ 0 }
};
arg = PyTuple_GetItem(arg, 0);
Py_INCREF(arg);
if (!PySequence_Check(arg)) TYERR("not a sequence");
- n = PySequence_Size(arg); if (!n) { z = id(me); goto end; }
+ n = PySequence_Size(arg); if (n < 0) goto end;
+ if (!n) { z = id(me); goto end; }
x = PySequence_GetItem(arg, 0);
if (PySequence_Check(x))
flat = 0;
#include "catacomb-python.h"
+/* #undef HAVE_LONG_LONG */
+
/*----- External values ---------------------------------------------------*/
static PyObject *modname = 0;
+PyObject *home_module = 0;
/*----- Conversions -------------------------------------------------------*/
return (PyLong_FromUnsignedLong(w));
}
+#ifndef HAVE_LONG_LONG
static PyObject *i32 = 0;
static int init_i32(void)
{ if (!i32 && (i32 = PyInt_FromLong(32)) == 0) return (-1); return (0); }
+#endif
PyObject *getk64(kludge64 u)
{
+#ifdef HAVE_LONG_LONG
+ return (PyLong_FromUnsignedLongLong(GET64(unsigned PY_LONG_LONG, u)));
+#else
PyObject *i = 0, *j = 0, *t;
PyObject *rc = 0;
if (i) Py_DECREF(i);
if (j) Py_DECREF(j);
return (rc);
+#endif
}
PyObject *getbool(int b)
return (0);
}
+#ifdef HAVE_UINT64
+# define CONVu64(n) do { \
+ kludge64 k; \
+ uint64 t; \
+ if (!convk64(o, &k)) goto end; \
+ t = GET64(uint64, k); \
+ if (t > MASK##n) VALERR("out of range"); \
+ *p = t; \
+ } while (0)
+#else
+# define CONVu64(n) assert(!"shouldn't be possible")
+#endif
+
#define CONVU_(n) \
int convu##n(PyObject *o, void *pp) \
{ \
unsigned long u; \
uint##n *p = pp; \
\
- if (!convulong(o, &u)) goto end; \
- if (u > MASK##n) VALERR("out of range"); \
- *p = u; \
+ if (MASK##n > ULONG_MAX) \
+ CONVu64(n); \
+ else { \
+ if (!convulong(o, &u)) goto end; \
+ if (u > MASK##n) VALERR("out of range"); \
+ *p = u; \
+ } \
return (1); \
end: \
return (0); \
int convk64(PyObject *o, void *pp)
{
- PyObject *i = 0, *t;
+ PyObject *i = 0;
int rc = 0;
+#if HAVE_LONG_LONG
+ unsigned PY_LONG_LONG t;
+#else
+ PyObject *t;
uint32 lo, hi;
+#endif
if (!o) VALERR("can't delete");
+#if HAVE_LONG_LONG
+ if ((i = PyNumber_Long(o)) == 0) goto end;
+ t = PyLong_AsUnsignedLongLong(i);
+ if (t == (unsigned PY_LONG_LONG)-1 && PyErr_Occurred()) goto end;
+ ASSIGN64(*(kludge64 *)pp, t);
+#else
if (init_i32()) goto end;
if ((i = PyNumber_Int(o)) == 0) goto end;
lo = PyInt_AsUnsignedLongMask(i);
Py_DECREF(i); i = t;
if (PyObject_IsTrue(i)) VALERR("out of range");
SET64(*(kludge64 *)pp, hi, lo);
+#endif
rc = 1;
+
end:
if (i) Py_DECREF(i);
return (rc);
void setconstants(PyObject *mod, const struct nameval *c)
{
PyObject *x;
+ unsigned long u;
while (c->name) {
- if (c->value > LONG_MAX)
- x = PyLong_FromUnsignedLong(c->value);
- else
- x = PyInt_FromLong(c->value);
- PyModule_AddObject(mod, (/*unconst*/ char *)c->name, x);
- c++;
+ u = c->value;
+ if (u <= LONG_MAX) x = PyInt_FromLong(u);
+ else if (c->f&CF_SIGNED) x = PyInt_FromLong(-1 - (long)(ULONG_MAX - u));
+ else x = PyLong_FromUnsignedLong(u);
+ PyModule_AddObject(mod, (/*unconst*/ char *)c->name, x); c++;
}
}
PyObject *func = 0;
PyObject *meth = 0;
- if ((nameobj = PyString_FromFormat("%s.%s",
- PyModule_GetName(mod),
- name)) == 0 ||
- (dict = PyDict_New()) == 0 ||
- (exc = PyErr_NewException(PyString_AS_STRING(nameobj),
- base, dict)) == 0)
- goto fail;
+ if ((dict = PyDict_New()) == 0) goto fail;
if (mm) {
while (mm->ml_name) {
}
}
+ if ((nameobj = PyString_FromFormat("%s.%s",
+ PyModule_GetName(mod),
+ name)) == 0 ||
+ (exc = PyErr_NewException(PyString_AS_STRING(nameobj),
+ base, dict)) == 0)
+ goto fail;
+
done:
Py_XDECREF(nameobj);
Py_XDECREF(dict);
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;
Py_TPFLAGS_BASETYPE,
/* @tp_doc@ */
-"Iterates over the items of a mapping.",
+"Iterates over the keys of a mapping.",
0, /* @tp_traverse@ */
0, /* @tp_clear@ */
Py_TPFLAGS_BASETYPE,
/* @tp_doc@ */
-"Iterates over the items of a mapping.",
+"Iterates over the values of a mapping.",
0, /* @tp_traverse@ */
0, /* @tp_clear@ */
Py_ssize_t gmap_pysize(PyObject *me)
{
PyObject *i = 0, *x = 0;
- int rc = -1;
- int n = 0;
+ Py_ssize_t rc = -1, n = 0;
if ((i = PyObject_GetIter(me)) == 0) goto done;
while ((x = PyIter_Next(i)) != 0) { n++; Py_DECREF(x); x = 0; }
{
PyObject *k, *def = Py_None, *v;
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "OO:get",
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O|O:get",
(/*unconst*/ char **)def_kwlist,
&k, &def))
return (0);
{
PyObject *k, *def = Py_None, *v;
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "OO:setdefault",
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O|O:setdefault",
(/*unconst*/ char **)def_kwlist,
&k, &def))
return (0);
{
PyObject *k, *def = 0, *v;
- if (!PyArg_ParseTupleAndKeywords(arg, kw, "OO:pop",
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "O|O:pop",
(/*unconst*/ char **)def_kwlist,
&k, &def))
return (0);
if ((v = PyObject_GetItem(me, k)) != 0) {
PyObject_DelItem(me, k);
return (v);
- }
- PyErr_Clear();
- RETURN_OBJ(def);
+ } else if (def) {
+ PyErr_Clear();
+ RETURN_OBJ(def);
+ } else
+ return (0);
}
PyObject *gmapmeth_update(PyObject *me, PyObject *arg)
PyObject *i = 0, *k = 0, *v = 0, *rc = 0;
if (!PyArg_ParseTuple(arg, ":popitem") ||
- (i = PyObject_GetIter(me)))
+ (i = PyObject_GetIter(me)) == 0)
goto end;
if ((k = PyIter_Next(i)) == 0) {
if (!PyErr_Occurred()) VALERR("popitem(): mapping is empty");
/*----- 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)