From c1756f78cbf3007438b3eb2fbfbd632d070be6ca Mon Sep 17 00:00:00 2001 From: Mark Wooding Date: Sun, 20 Oct 2019 17:51:13 +0100 Subject: [PATCH] pyke/, ...: Extract utilities into a sort-of reusable library. This commit changes no code, but it moves a lot of it about. Tidying up will come later. --- .skelrc | 9 + catacomb-python.h | 564 ----------------------------------- catacomb.c | 188 ------------ mapping.c | 425 ++++++++++++++++++++++++++ pyke-mLib.c | 131 ++++++++ pyke-mLib.h | 62 ++++ pyke.c | 371 +++++++++++++++++++++++ pyke.h | 363 +++++++++++++++++++++++ util.c | 873 ------------------------------------------------------ 9 files changed, 1361 insertions(+), 1625 deletions(-) create mode 100644 .skelrc delete mode 100644 catacomb-python.h delete mode 100644 catacomb.c create mode 100644 mapping.c create mode 100644 pyke-mLib.c create mode 100644 pyke-mLib.h create mode 100644 pyke.c create mode 100644 pyke.h delete mode 100644 util.c diff --git a/.skelrc b/.skelrc new file mode 100644 index 0000000..21912db --- /dev/null +++ b/.skelrc @@ -0,0 +1,9 @@ +;;; -*-emacs-lisp-*- + +(setq skel-alist + (append + '((author . "Straylight/Edgeware") + (licence-text . "[[gpl]]") + (full-title . "Pyke: the Python Kit for Extensions") + (program . "Pyke")) + skel-alist)) diff --git a/catacomb-python.h b/catacomb-python.h deleted file mode 100644 index 5c5611e..0000000 --- a/catacomb-python.h +++ /dev/null @@ -1,564 +0,0 @@ -/* -*-c-*- - * - * Definitions for Catacomb bindings - * - * (c) 2004 Straylight/Edgeware - */ - -/*----- Licensing notice --------------------------------------------------* - * - * This file is part of the Python interface to Catacomb. - * - * Catacomb/Python is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * Catacomb/Python is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Catacomb/Python; if not, write to the Free Software Foundation, - * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef CATACOMB_PYTHON_H -#define CATACOMB_PYTHON_H - -#ifdef __cplusplus - extern "C" { -#endif - -/*----- Header files ------------------------------------------------------*/ - -#define PY_SSIZE_T_CLEAN - -#include -#include -#include - -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include - -#include -#include -#include - -#include -#include - -#include -#include -#include - -#include -#include -#include - -#include -#include - -/*----- Other preliminaries -----------------------------------------------*/ - -#define GOBBLE_SEMI extern int notexist -#if defined(__GNUC__) && defined(__ELF__) -# define PRIVATE_SYMBOLS _Pragma("GCC visibility push(hidden)") GOBBLE_SEMI -# define PUBLIC_SYMBOLS _Pragma("GCC visibility pop") GOBBLE_SEMI -# define EXPORT __attribute__((__visibility__("default"))) -#else -# define PRIVATE_SYMBOLS GOBBLE_SEMI -# define PUBLIC_SYMBOLS GOBBLE_SEMI -# define EXPORT -#endif - -PRIVATE_SYMBOLS; - -/*----- Utility macros ----------------------------------------------------*/ - -#define RETURN_OBJ(obj) do { Py_INCREF(obj); return (obj); } while (0) -#define RETURN_NONE RETURN_OBJ(Py_None) -#define RETURN_NOTIMPL RETURN_OBJ(Py_NotImplemented) -#define RETURN_TRUE RETURN_OBJ(Py_True) -#define RETURN_FALSE RETURN_OBJ(Py_False) -#define RETURN_ME RETURN_OBJ(me) - -#define EXCERR(exc, str) do { \ - PyErr_SetString(exc, str); \ - 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) -#define SYSERR(str) EXCERR(PyExc_SystemError, str) -#define NIERR(str) EXCERR(PyExc_NotImplementedError, str) -#define INDEXERR(idx) do { \ - PyErr_SetObject(PyExc_KeyError, idx); \ - goto end; \ -} while (0) -#define OSERR(name) do { \ - PyErr_SetFromErrnoWithFilename(PyExc_OSError, name); \ - 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) \ - { \ - if (!PyObject_TypeCheck(o, ty##_pytype)) \ - TYERR("wanted a " #ty); \ - *(cty *)p = ext(o); \ - return (1); \ - end: \ - return (0); \ - } - -#define root_pytype 0 -#define type_pytype &PyType_Type -#define INITTYPE_META(ty, base, meta) do { \ - ty##_pytype_skel.tp_base = base##_pytype; \ - ty##_pytype = inittype(&ty##_pytype_skel, meta##_pytype); \ -} while (0) -#define INITTYPE(ty, base) INITTYPE_META(ty, base, type) - -extern PyObject *home_module; -extern PyObject *modname; - -#define INSERT(name, ob) do { \ - PyObject *_o = (PyObject *)(ob); \ - Py_INCREF(_o); \ - PyModule_AddObject(mod, name, _o); \ -} while (0) - -#define INSEXC(name, var, base, meth) \ - INSERT(name, var = mkexc(mod, base, name, meth)) - -#define METH(func, doc) \ - { #func, METHNAME(func), METH_VARARGS, doc }, -#define KWMETH(func, doc) \ - { #func, (PyCFunction)METHNAME(func), \ - METH_VARARGS | METH_KEYWORDS, doc }, - -#define GET(func, doc) \ - { #func, GETSETNAME(get, func), 0, doc }, -#define GETSET(func, doc) \ - { #func, GETSETNAME(get, func), GETSETNAME(set, func), doc }, - -#define MEMBER(name, ty, f, doc) \ - { #name, ty, offsetof(MEMBERSTRUCT, name), f, doc }, - -#define MODULES(_) \ - _(util) \ - _(bytestring) _(buffer) \ - _(rand) _(algorithms) _(pubkey) _(pgen) \ - _(mp) _(field) _(ec) _(group) \ - _(passphrase) _(share) _(key) -#define DOMODINIT(m) m##_pyinit(); -#define DOMODINSERT(m) m##_pyinsert(mod); -#define INIT_MODULES do { MODULES(DOMODINIT) } while (0) -#define INSERT_MODULES do { MODULES(DOMODINSERT) } while (0) -#define DECLARE_MODINIT(m) \ - extern void m##_pyinit(void); \ - extern void m##_pyinsert(PyObject *); - -MODULES(DECLARE_MODINIT) - -#define FREEOBJ(obj) \ - (((PyObject *)(obj))->ob_type->tp_free((PyObject *)(obj))) - -#define GEN(func, base) \ - static PyObject *func(void) \ - { \ - PyObject *d = PyDict_New(); \ - PyObject *o; \ - int i; \ - \ - for (i = 0; g##base##tab[i]; i++) { \ - o = gc##base##_pywrap((/*unconst*/ gc##base *)g##base##tab[i]); \ - PyDict_SetItemString(d, \ - (/*unconst*/ char *)g##base##tab[i]->name, \ - o); \ - Py_DECREF(o); \ - } \ - return (d); \ - } - -#define KWLIST (/*unconst*/ char **)kwlist - -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, - PyObject *(*id)(PyObject *), - int (*fill)(void *, PyObject *, - PyObject *, PyObject *), - PyObject *(*exp)(PyObject *, void *, int), - void (*drop)(void *)); - -extern int convulong(PyObject *, void *); -#define DECL_CONVU_(n) extern int convu##n(PyObject *, void *); -DOUINTSZ(DECL_CONVU_) -extern int convmpw(PyObject *, void *); -extern int convuint(PyObject *, void *); -extern int convk64(PyObject *, void *); -extern int convszt(PyObject *, void *); -extern int convbool(PyObject *, void *); -extern PyObject *abstract_pynew(PyTypeObject *, PyObject *, PyObject *); -extern PyObject *getbool(int); -extern PyObject *getulong(unsigned long); -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 PyMethodDef *donemethods(void); - -/*----- Mapping methods ---------------------------------------------------*/ - -#define GMAP_METH(func, doc) { #func, gmapmeth_##func, METH_VARARGS, doc }, -#define GMAP_KWMETH(func, doc) \ - { #func, (PyCFunction)gmapmeth_##func, METH_VARARGS|METH_KEYWORDS, doc }, -#define GMAP_METHDECL(func, doc) \ - extern PyObject *gmapmeth_##func(PyObject *, PyObject *); -#define GMAP_KWMETHDECL(func, doc) \ - extern PyObject *gmapmeth_##func(PyObject *, PyObject *, PyObject *); - -#define GMAP_DOROMETHODS(METH, KWMETH) \ - METH (has_key, "D.has_key(KEY) -> BOOL") \ - METH (keys, "D.keys() -> LIST") \ - METH (values, "D.values() -> LIST") \ - METH (items, "D.items() -> LIST") \ - METH (iterkeys, "D.iterkeys() -> ITER") \ - METH (itervalues, "D.itervalues() -> ITER") \ - METH (iteritems, "D.iteritems() -> ITER") \ - KWMETH(get, "D.get(KEY, [default = None]) -> VALUE") - -#define GMAP_DOMETHODS(METH, KWMETH) \ - GMAP_DOROMETHODS(METH, KWMETH) \ - METH (clear, "D.clear()") \ - KWMETH(setdefault, "D.setdefault(K, [default = None]) -> VALUE") \ - KWMETH(pop, "D.pop(KEY, [default = ]) -> VALUE") \ - METH (popitem, "D.popitem() -> (KEY, VALUE)") \ - METH (update, "D.update(MAP)") - -GMAP_DOMETHODS(GMAP_METHDECL, GMAP_KWMETHDECL) -#define GMAP_ROMETHODS GMAP_DOROMETHODS(GMAP_METH, GMAP_KWMETH) -#define GMAP_METHODS GMAP_DOMETHODS(GMAP_METH, GMAP_KWMETH) -extern Py_ssize_t gmap_pysize(PyObject *); -extern PySequenceMethods gmap_pysequence; -extern PyMethodDef gmap_pymethods[]; - -/*----- Bytestrings -------------------------------------------------------*/ - -PyObject *bytestring_pywrap(const void *, size_t); -PyObject *bytestring_pywrapbuf(buf *); - -/*----- Multiprecision arithmetic -----------------------------------------*/ - -typedef struct mp_pyobj { - PyObject_HEAD - mp *x; -} mp_pyobj; - -extern PyTypeObject *mp_pytype; -extern PyTypeObject *gf_pytype; -#define MP_X(o) (((mp_pyobj *)(o))->x) -#define MP_PYCHECK(o) PyObject_TypeCheck((o), mp_pytype) -#define GF_PYCHECK(o) PyObject_TypeCheck((o), gf_pytype) - -extern mp *mp_frompylong(PyObject *); -extern PyObject *mp_topylong(mp *); -extern mp *tomp(PyObject *); -extern mp *getmp(PyObject *); -extern int convmp(PyObject *, void *); -extern mp *getgf(PyObject *); -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 *); -extern int mp_tolong_checked(mp *, long *, int); - -/*----- Abstract fields ---------------------------------------------------*/ - -typedef struct field_pyobj { - PyHeapTypeObject ty; - field *f; -} field_pyobj; - -extern PyTypeObject *field_pytype; -extern PyTypeObject *primefield_pytype; -extern PyTypeObject *niceprimefield_pytype; -extern PyTypeObject *binfield_pytype; -extern PyTypeObject *binpolyfield_pytype; -extern PyTypeObject *binnormfield_pytype; -#define FIELD_PYCHECK(o) PyObject_TypeCheck((o), field_pytype) -#define FIELD_F(o) (((field_pyobj *)(o))->f) -extern PyObject *field_pywrap(field *); -extern field *field_copy(field *); - -typedef struct fe_pyobj { - PyObject_HEAD - field *f; - mp *x; -} fe_pyobj; - -extern PyTypeObject *fe_pytype; -#define FE_PYCHECK(o) PyObject_TypeCheck((o), fe_pytype) -#define FE_F(o) (((fe_pyobj *)(o))->f) -#define FE_FOBJ(o) ((PyObject *)(o)->ob_type) -#define FE_X(o) (((fe_pyobj *)(o))->x) -extern PyObject *fe_pywrap(PyObject *, mp *); - -/*----- Elliptic curves ---------------------------------------------------*/ - -typedef struct eccurve_pyobj { - PyHeapTypeObject ty; - ec_curve *c; - PyObject *fobj; -} eccurve_pyobj; - -extern PyTypeObject *eccurve_pytype; -extern PyTypeObject *ecprimecurve_pytype; -extern PyTypeObject *ecprimeprojcurve_pytype; -extern PyTypeObject *ecbincurve_pytype; -extern PyTypeObject *ecbinprojcurve_pytype; -#define ECCURVE_PYCHECK(o) PyObject_TypeCheck((o), eccurve_pytype) -#define ECCURVE_C(o) (((eccurve_pyobj *)(o))->c) -#define ECCURVE_FOBJ(o) (((eccurve_pyobj *)(o))->fobj) -extern PyObject *eccurve_pywrap(PyObject *, ec_curve *); -extern ec_curve *eccurve_copy(ec_curve *); - -typedef struct ecpt_pyobj { - PyObject_HEAD - ec_curve *c; - ec p; -} ecpt_pyobj; - -extern PyTypeObject *ecpt_pytype, *ecptcurve_pytype; -#define ECPT_PYCHECK(o) PyObject_TypeCheck((o), ecpt_pytype) -#define ECPTCURVE_PYCHECK(o) PyObject_TypeCheck((o), ecptcurve_pytype) -#define ECPT_C(o) (((ecpt_pyobj *)(o))->c) -#define ECPT_COBJ(o) ((PyObject *)(o)->ob_type) -#define ECPT_FOBJ(o) ECCURVE_FOBJ(ECPT_COBJ((o))) -#define ECPT_P(o) (&((ecpt_pyobj *)(o))->p) -extern PyObject *ecpt_pywrap(PyObject *, ec *); -extern PyObject *ecpt_pywrapout(void *, ec *); -extern int toecpt(ec_curve *, ec *, PyObject *); -extern int getecpt(ec_curve *, ec *, PyObject *); -extern void getecptout(ec *, PyObject *); -extern int convecpt(PyObject *, void *); - -typedef struct ecinfo_pyobj { - PyObject_HEAD - ec_info ei; - PyObject *cobj; -} ecinfo_pyobj; - -extern PyTypeObject *ecinfo_pytype; -#define ECINFO_PYCHECK(o) PyObject_TypeCheck((o), ecinfo_pytype) -#define ECINFO_EI(o) (&((ecinfo_pyobj *)(o))->ei) -#define ECINFO_COBJ(o) (((ecinfo_pyobj *)(o))->cobj) -extern void ecinfo_copy(ec_info *, const ec_info *); -extern PyObject *ecinfo_pywrap(ec_info *); - -/*----- Cyclic groups -----------------------------------------------------*/ - -typedef struct ge_pyobj { - PyObject_HEAD - ge *x; - group *g; -} ge_pyobj; - -extern PyTypeObject *ge_pytype; -#define GE_PYCHECK(o) PyObject_TypeCheck((o), ge_pytype) -#define GE_X(o) (((ge_pyobj *)(o))->x) -#define GE_G(o) (((ge_pyobj *)(o))->g) -#define GE_GOBJ(o) ((PyObject *)(group_pyobj *)(o)->ob_type) -extern PyObject *ge_pywrap(PyObject *, ge *); - -typedef struct group_pyobj { - PyHeapTypeObject ty; - group *g; -} group_pyobj; - -extern PyTypeObject *group_pytype; -#define GROUP_G(o) (((group_pyobj *)(o))->g) -extern PyObject *group_pywrap(group *); -extern group *group_copy(group *); - -/*----- Random number generators ------------------------------------------*/ - -#define f_freeme 1u - -typedef struct grand_pyobj { - PyObject_HEAD - unsigned f; - grand *r; -} grand_pyobj; - -extern PyTypeObject *grand_pytype; -extern PyObject *rand_pyobj; -#define GRAND_PYCHECK(o) PyObject_TypeCheck((o), grand_pytype) -#define GRAND_F(o) (((grand_pyobj *)(o))->f) -#define GRAND_R(o) (((grand_pyobj *)(o))->r) -extern PyObject *grand_pywrap(grand *, unsigned); -extern int convgrand(PyObject *, void *); - -/*----- Symmetric cryptography --------------------------------------------*/ - -extern PyObject *keysz_pywrap(const octet *); - -extern int convgccipher(PyObject *, void *); -extern PyObject *gccipher_pywrap(gccipher *); - -typedef struct gchash_pyobj { - PyHeapTypeObject ty; - gchash *ch; -} gchash_pyobj; - -extern PyTypeObject *gchash_pytype; -extern PyObject *sha_pyobj, *has160_pyobj; -#define GCHASH_PYCHECK(o) PyObject_TypeCheck((o), gchash_pytype) -#define GCHASH_CH(o) (((gchash_pyobj *)(o))->ch) -extern PyObject *ghash_pywrap(PyObject *, ghash *); -extern int convgchash(PyObject *, void *); -extern int convghash(PyObject *, void *); - -extern int convgcmac(PyObject *, void *); - -/*----- Key generation ----------------------------------------------------*/ - -typedef struct pfilt_pyobj { - PyObject_HEAD - pfilt f; - int st; -} pfilt_pyobj; - -extern PyTypeObject *pfilt_pytype; -#define PFILT_PYCHECK(o) PyObject_TypeCheck(o, pfilt_pytype) -#define PFILT_F(o) (&((pfilt_pyobj *)(o))->f) -#define PFILT_ST(o) (((pfilt_pyobj *)(o))->st) - -typedef struct { pgen_proc *proc; void *ctx; } pgev; -#define PGEV_HEAD PyObject_HEAD pgev pg; - -typedef struct pgev_pyobj { - PGEV_HEAD -} pgev_pyobj; - -extern PyTypeObject *pgev_pytype; -#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(pypgev *); -extern void pgenerr(struct excinfo *exc); - -/*----- That's all, folks -------------------------------------------------*/ - -#ifdef __cplusplus - } -#endif - -#endif diff --git a/catacomb.c b/catacomb.c deleted file mode 100644 index b54227f..0000000 --- a/catacomb.c +++ /dev/null @@ -1,188 +0,0 @@ -/* -*-c-*- - * - * Where the fun begins - * - * (c) 2004 Straylight/Edgeware - */ - -/*----- Licensing notice --------------------------------------------------* - * - * This file is part of the Python interface to Catacomb. - * - * Catacomb/Python is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * Catacomb/Python is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Catacomb/Python; if not, write to the Free Software Foundation, - * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/*----- Header files ------------------------------------------------------*/ - -#include "catacomb-python.h" - -/*----- Main code ---------------------------------------------------------*/ - -static const struct nameval consts[] = { -#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), - 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), - C(KF_NONSECRET), - C(KF_BURN), C(KF_OPT), - C(EC_XONLY), C(EC_YBIT), C(EC_LSB), C(EC_CMPR), C(EC_EXPLY), C(EC_SORT), - C(X25519_KEYSZ), C(X25519_PUBSZ), C(X25519_OUTSZ), - C(X448_KEYSZ), C(X448_PUBSZ), C(X448_OUTSZ), - C(ED25519_KEYSZ), C(ED25519_PUBSZ), C(ED25519_SIGSZ), - C(ED25519_MAXPERSOSZ), - C(ED448_KEYSZ), C(ED448_PUBSZ), C(ED448_SIGSZ), C(ED448_MAXPERSOSZ), - C(AEADF_PCHSZ), C(AEADF_PCMSZ), C(AEADF_PCTSZ), - C(AEADF_AADNDEP), C(AEADF_AADFIRST), C(AEADF_NOAAD), -#define ENTRY(tag, val, str) C(KERR_##tag), - KEY_ERRORS(ENTRY) -#undef ENTRY -#undef C -#undef CF - { 0 } -}; - -PyObject *mexp_common(PyObject *me, PyObject *arg, - size_t efsz, - PyObject *(*id)(PyObject *), - int (*fill)(void *, PyObject *, - PyObject *, PyObject *), - PyObject *(*exp)(PyObject *, void *, int), - void (*drop)(void *)) -{ - int i = 0, j, n, flat; - PyObject *qq, *x, *y, *z = 0; - char *v = 0, *vv; - - if (PyTuple_GET_SIZE(arg) == 1) - arg = PyTuple_GET_ITEM(arg, 0); - Py_INCREF(arg); - if (!PySequence_Check(arg)) TYERR("not a sequence"); - 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; - else { - if (n % 2) VALERR("must have even number of arguments"); - n /= 2; - flat = 1; - } - Py_DECREF(x); - - v = xmalloc(n * efsz); - for (i = j = 0, vv = v; i < n; i++, vv += efsz) { - if (flat) { - x = PySequence_GetItem(arg, j++); - y = PySequence_GetItem(arg, j++); - } else { - qq = PySequence_GetItem(arg, j++); - if (!qq) goto end; - if (!PySequence_Check(qq) || PySequence_Size(qq) != 2) { - Py_DECREF(qq); - TYERR("want a sequence of pairs"); - } - x = PySequence_GetItem(qq, 0); - y = PySequence_GetItem(qq, 1); - Py_DECREF(qq); - } - if (!x || !y) goto end; - if (fill(vv, me, x, y)) { - Py_DECREF(x); - Py_DECREF(y); - if (!PyErr_Occurred()) - PyErr_SetString(PyExc_TypeError, "type mismatch"); - goto end; - } - Py_DECREF(x); - Py_DECREF(y); - } - z = exp(me, v, n); - -end: - if (v) { - for (j = 0, vv = v; j < i; j++, vv += efsz) - drop(vv); - xfree(v); - } - Py_DECREF(arg); - return (z); -} - -static PyObject *smallprimes(void) -{ - PyObject *v = PyList_New(NPRIME); - int i; - - for (i = 0; i < NPRIME; i++) - PyList_SET_ITEM(v, i, PyInt_FromLong(primetab[i])); - return (v); -} - -static PyObject *meth__ego(PyObject *me, PyObject *arg) -{ - char *argv0; - if (!PyArg_ParseTuple(arg, "s:_ego", &argv0)) - return (0); - if (STRCMP(QUIS, ==, "")) - ego(argv0); - RETURN_NONE; -} - -static PyMethodDef methods[] = { -#define METHNAME(func) meth_##func - METH (_ego, "_ego(ARGV0)") -#undef METHNAME - { 0 } -}; - -static void init_random(void) -{ -#if PY_VERSION_HEX >= 0x02060000 - char *seed; - uint32 r; - - if (!Py_HashRandomizationFlag) return; - seed = getenv("PYTHONHASHSEED"); - if (!seed || STRCMP(seed, ==, "random")) r = GR_WORD(&rand_global); - else r = strtoul(seed, 0, 0); - if (!r) r = 0xe011f220; /* zero doesn't work well */ - unihash_setkey(&unihash_global, r); -#endif -} - -EXPORT void init_base(void) -{ - PyObject *mod; - - modname = PyString_FromString("catacomb"); - addmethods(methods); - INIT_MODULES; - init_random(); - mod = Py_InitModule("catacomb._base", donemethods()); - INSERT_MODULES; - INSERT("smallprimes", smallprimes()); - setconstants(mod, consts); -} - -/*----- That's all, folks -------------------------------------------------*/ diff --git a/mapping.c b/mapping.c new file mode 100644 index 0000000..229dfa9 --- /dev/null +++ b/mapping.c @@ -0,0 +1,425 @@ +/* -*-c-*- + * + * Generic mapping support + * + * (c) 2019 Straylight/Edgeware + */ + +/*----- Licensing notice --------------------------------------------------* + * + * This file is part of Pyke: the Python Kit for Extensions. + * + * Pyke is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Pyke is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * along with Pyke. If not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/*----- Header files ------------------------------------------------------*/ + +#include "pyke.h" + +/*----- Iteration ---------------------------------------------------------*/ + +static PyTypeObject *itemiter_pytype, *valiter_pytype; + +typedef struct iter_pyobj { + PyObject_HEAD + PyObject *map; + PyObject *i; +} iter_pyobj; +#define ITER_MAP(o) (((iter_pyobj *)(o))->map) +#define ITER_I(o) (((iter_pyobj *)(o))->i) + +static void iter_pydealloc(PyObject *me) + { Py_DECREF(ITER_MAP(me)); Py_DECREF(ITER_I(me)); FREEOBJ(me); } + +static PyObject *itemiter_pynext(PyObject *me) +{ + PyObject *k = 0, *v = 0, *rc = 0; + + if ((k = PyIter_Next(ITER_I(me))) != 0 && + (v = PyObject_GetItem(ITER_MAP(me), k)) != 0) + rc = Py_BuildValue("(OO)", k, v); + Py_XDECREF(k); Py_XDECREF(v); + return (rc); +} + +static PyTypeObject itemiter_pytype_skel = { + PyObject_HEAD_INIT(0) 0, /* Header */ + "ItemIter", /* @tp_name@ */ + sizeof(iter_pyobj), /* @tp_basicsize@ */ + 0, /* @tp_itemsize@ */ + + iter_pydealloc, /* @tp_dealloc@ */ + 0, /* @tp_print@ */ + 0, /* @tp_getattr@ */ + 0, /* @tp_setattr@ */ + 0, /* @tp_compare@ */ + 0, /* @tp_repr@ */ + 0, /* @tp_as_number@ */ + 0, /* @tp_as_sequence@ */ + 0, /* @tp_as_mapping@ */ + 0, /* @tp_hash@ */ + 0, /* @tp_call@ */ + 0, /* @tp_str@ */ + 0, /* @tp_getattro@ */ + 0, /* @tp_setattro@ */ + 0, /* @tp_as_buffer@ */ + Py_TPFLAGS_DEFAULT | /* @tp_flags@ */ + Py_TPFLAGS_BASETYPE, + + /* @tp_doc@ */ + "Iterates over the items of a mapping.", + + 0, /* @tp_traverse@ */ + 0, /* @tp_clear@ */ + 0, /* @tp_richcompare@ */ + 0, /* @tp_weaklistoffset@ */ + PyObject_SelfIter, /* @tp_iter@ */ + itemiter_pynext, /* @tp_iternext@ */ + 0, /* @tp_methods@ */ + 0, /* @tp_members@ */ + 0, /* @tp_getset@ */ + 0, /* @tp_base@ */ + 0, /* @tp_dict@ */ + 0, /* @tp_descr_get@ */ + 0, /* @tp_descr_set@ */ + 0, /* @tp_dictoffset@ */ + 0, /* @tp_init@ */ + PyType_GenericAlloc, /* @tp_alloc@ */ + abstract_pynew, /* @tp_new@ */ + 0, /* @tp_free@ */ + 0 /* @tp_is_gc@ */ +}; + +static PyObject *valiter_pynext(PyObject *me) +{ + PyObject *k = 0, *rc = 0; + + if ((k = PyIter_Next(ITER_I(me))) != 0) + rc = PyObject_GetItem(ITER_MAP(me), k); + Py_XDECREF(k); + return (rc); +} + +static PyTypeObject valiter_pytype_skel = { + PyObject_HEAD_INIT(0) 0, /* Header */ + "ValueIter", /* @tp_name@ */ + sizeof(iter_pyobj), /* @tp_basicsize@ */ + 0, /* @tp_itemsize@ */ + + iter_pydealloc, /* @tp_dealloc@ */ + 0, /* @tp_print@ */ + 0, /* @tp_getattr@ */ + 0, /* @tp_setattr@ */ + 0, /* @tp_compare@ */ + 0, /* @tp_repr@ */ + 0, /* @tp_as_number@ */ + 0, /* @tp_as_sequence@ */ + 0, /* @tp_as_mapping@ */ + 0, /* @tp_hash@ */ + 0, /* @tp_call@ */ + 0, /* @tp_str@ */ + 0, /* @tp_getattro@ */ + 0, /* @tp_setattro@ */ + 0, /* @tp_as_buffer@ */ + Py_TPFLAGS_DEFAULT | /* @tp_flags@ */ + Py_TPFLAGS_BASETYPE, + + /* @tp_doc@ */ + "Iterates over the values of a mapping.", + + 0, /* @tp_traverse@ */ + 0, /* @tp_clear@ */ + 0, /* @tp_richcompare@ */ + 0, /* @tp_weaklistoffset@ */ + PyObject_SelfIter, /* @tp_iter@ */ + valiter_pynext, /* @tp_iternext@ */ + 0, /* @tp_methods@ */ + 0, /* @tp_members@ */ + 0, /* @tp_getset@ */ + 0, /* @tp_base@ */ + 0, /* @tp_dict@ */ + 0, /* @tp_descr_get@ */ + 0, /* @tp_descr_set@ */ + 0, /* @tp_dictoffset@ */ + 0, /* @tp_init@ */ + PyType_GenericAlloc, /* @tp_alloc@ */ + abstract_pynew, /* @tp_new@ */ + 0, /* @tp_free@ */ + 0 /* @tp_is_gc@ */ +}; + +PySequenceMethods gmap_pysequence = { + 0, /* @sq_length@ */ + 0, /* @sq_concat@ */ + 0, /* @sq_repeat@ */ + 0, /* @sq_item@ */ + 0, /* @sq_slice@ */ + 0, /* @sq_ass_item@ */ + 0, /* @sq_ass_slice@ */ + PyMapping_HasKey, /* @sq_contains@ */ + 0, /* @sq_inplace_concat@ */ + 0 /* @sq_inplace_repeat@ */ +}; + +/*----- Other mapping protocol support ------------------------------------*/ + +Py_ssize_t gmap_pysize(PyObject *me) +{ + PyObject *i = 0, *x = 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; } + if (PyErr_Occurred()) goto done; + rc = n; +done: + Py_XDECREF(i); Py_XDECREF(x); + return (rc); +} + +PyObject *gmapmeth_has_key(PyObject *me, PyObject *arg) +{ + PyObject *k; + if (!PyArg_ParseTuple(arg, "O:has_key", &k)) return (0); + return (getbool(PyMapping_HasKey(me, k))); +} + +PyObject *gmapmeth_keys(PyObject *me, PyObject *arg) +{ + PyObject *l = 0, *i = 0, *k, *rc = 0; + int err; + + if (!PyArg_ParseTuple(arg, ":keys") || + (l = PyList_New(0)) == 0 || + (i = PyObject_GetIter(me)) == 0) + goto done; + while ((k = PyIter_Next(i)) != 0) + { err = PyList_Append(l, k); Py_DECREF(k); if (err) goto done; } + if (PyErr_Occurred()) goto done; + rc = l; l = 0; +done: + Py_XDECREF(l); Py_XDECREF(i); + return (rc); +} + +PyObject *gmapmeth_values(PyObject *me, PyObject *arg) +{ + PyObject *l = 0, *i = 0, *k, *v, *rc = 0; + int err = 0; + + if (!PyArg_ParseTuple(arg, ":values") || + (l = PyList_New(0)) == 0 || + (i = PyObject_GetIter(me)) == 0) + goto done; + while ((k = PyIter_Next(i)) != 0) { + if ((v = PyObject_GetItem(me, k)) == 0 || + PyList_Append(l, v)) + err = -1; + Py_DECREF(k); Py_XDECREF(v); + if (err) goto done; + } + if (PyErr_Occurred()) goto done; + rc = l; l = 0; +done: + Py_XDECREF(l); Py_XDECREF(i); + return (rc); +} + +PyObject *gmapmeth_items(PyObject *me, PyObject *arg) +{ + PyObject *l = 0, *i = 0, *k, *v, *z, *rc = 0; + int err = 0; + + if (!PyArg_ParseTuple(arg, ":items") || + (l = PyList_New(0)) == 0 || + (i = PyObject_GetIter(me)) == 0) + goto done; + while ((k = PyIter_Next(i)) != 0) { + z = 0; + if ((v = PyObject_GetItem(me, k)) == 0 || + (z = Py_BuildValue("(OO)", k, v)) == 0 || + PyList_Append(l, z)) + err = -1; + Py_DECREF(k); Py_XDECREF(v); Py_XDECREF(z); + if (err) goto done; + } + if (PyErr_Occurred()) goto done; + rc = l; l = 0; +done: + Py_XDECREF(l); Py_XDECREF(i); + return (rc); +} + +PyObject *gmapmeth_iterkeys(PyObject *me, PyObject *arg) +{ + if (!PyArg_ParseTuple(arg, ":iterkeys")) return (0); + return (PyObject_GetIter(me)); +} + +PyObject *gmapmeth_itervalues(PyObject *me, PyObject *arg) +{ + PyObject *i; + iter_pyobj *ii; + + if (!PyArg_ParseTuple(arg, ":itervalues") || + (i = PyObject_GetIter(me)) == 0) + return (0); + ii = PyObject_NEW(iter_pyobj, valiter_pytype); + ii->map = me; Py_INCREF(me); + ii->i = i; + return ((PyObject *)ii); +} + +PyObject *gmapmeth_iteritems(PyObject *me, PyObject *arg) +{ + PyObject *i; + iter_pyobj *ii; + + if (!PyArg_ParseTuple(arg, ":iteritems") || + (i = PyObject_GetIter(me)) == 0) + return (0); + ii = PyObject_NEW(iter_pyobj, itemiter_pytype); + ii->map = me; Py_INCREF(me); + ii->i = i; + return ((PyObject *)ii); +} + +PyObject *gmapmeth_clear(PyObject *me, PyObject *arg) +{ + PyObject *i = 0, *k = 0, *rc = 0; + + if (!PyArg_ParseTuple(arg, ":clear") || + (i = PyObject_GetIter(me)) == 0) + goto end; + while ((k = PyIter_Next(i)) != 0) { + PyObject_DelItem(me, k); + Py_DECREF(k); + } + if (PyErr_Occurred()) goto end; + rc = me; Py_INCREF(me); +end: + Py_XDECREF(i); + return (rc); +} + +static const char *const def_kwlist[] = { "key", "default", 0 }; + +PyObject *gmapmeth_get(PyObject *me, PyObject *arg, PyObject *kw) +{ + PyObject *k, *def = Py_None, *v; + + if (!PyArg_ParseTupleAndKeywords(arg, kw, "O|O:get", + (/*unconst*/ char **)def_kwlist, + &k, &def)) + return (0); + if ((v = PyObject_GetItem(me, k)) != 0) return (v); + PyErr_Clear(); + RETURN_OBJ(def); +} + +PyObject *gmapmeth_setdefault(PyObject *me, PyObject *arg, PyObject *kw) +{ + PyObject *k, *def = Py_None, *v; + + if (!PyArg_ParseTupleAndKeywords(arg, kw, "O|O:setdefault", + (/*unconst*/ char **)def_kwlist, + &k, &def)) + return (0); + if ((v = PyObject_GetItem(me, k)) != 0) return (v); + PyErr_Clear(); + if (PyObject_SetItem(me, k, def)) return (0); + RETURN_OBJ(def); +} + +PyObject *gmapmeth_pop(PyObject *me, PyObject *arg, PyObject *kw) +{ + PyObject *k, *def = 0, *v; + + 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); + } else if (def) { + PyErr_Clear(); + RETURN_OBJ(def); + } else + return (0); +} + +PyObject *gmapmeth_update(PyObject *me, PyObject *arg) +{ + PyObject *map, *i = 0, *k, *v, *rc = 0; + int err = 0; + + if (!PyArg_ParseTuple(arg, "O:update", &map) || + (i = PyObject_GetIter(map)) == 0) + goto end; + while ((k = PyIter_Next(i)) != 0) { + if ((v = PyObject_GetItem(map, k)) == 0 || + PyObject_SetItem(me, k, v)) + err = -1; + Py_DECREF(k); Py_XDECREF(v); + if (err) goto end; + } + if (PyErr_Occurred()) goto end; + rc = me; Py_INCREF(me); +end: + Py_XDECREF(i); + return (rc); +} + +PyObject *gmapmeth_popitem(PyObject *me, PyObject *arg) +{ + PyObject *i = 0, *k = 0, *v = 0, *rc = 0; + + if (!PyArg_ParseTuple(arg, ":popitem") || + (i = PyObject_GetIter(me)) == 0) + goto end; + if ((k = PyIter_Next(i)) == 0) { + if (!PyErr_Occurred()) VALERR("popitem(): mapping is empty"); + goto end; + } + if ((v = PyObject_GetItem(me, k)) == 0 || + PyObject_DelItem(me, k)) + goto end; + rc = Py_BuildValue("(OO)", k, v); +end: + Py_XDECREF(i); Py_XDECREF(k); Py_XDECREF(v); + return (rc); +} + +PyMethodDef gmap_pymethods[] = { + GMAP_METHODS + { 0 } +}; + +/*----- Submodule initialization ------------------------------------------*/ + +void pyke_gmap_pyinit(void) +{ + INITTYPE(itemiter, root); + INITTYPE(valiter, root); +} + +void pyke_gmap_pyinsert(PyObject *mod) +{ + INSERT("ItemIter", itemiter_pytype); + INSERT("ValueIter", valiter_pytype); +} + +/*----- That's all, folks -------------------------------------------------*/ diff --git a/pyke-mLib.c b/pyke-mLib.c new file mode 100644 index 0000000..a29f34c --- /dev/null +++ b/pyke-mLib.c @@ -0,0 +1,131 @@ +/* -*-c-*- + * + * Pyke: the Python Kit for Extensions, mLib integration + * + * (c) 2019 Straylight/Edgeware + */ + +/*----- Licensing notice --------------------------------------------------* + * + * This file is part of Pyke: the Python Kit for Extensions. + * + * Pyke is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Pyke is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * along with Pyke. If not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/*----- Header files ------------------------------------------------------*/ + +#include "pyke-mLib.h" + +/* #undef HAVE_LONG_LONG */ + +/*----- Conversions -------------------------------------------------------*/ + +#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 (init_i32()) goto end; + if ((i = PyLong_FromUnsignedLong(HI64(u))) == 0) goto end; + if ((t = PyNumber_InPlaceLshift(i, i32)) == 0) goto end; + Py_DECREF(i); i = t; + if ((j = PyLong_FromUnsignedLong(LO64(u))) == 0) goto end; + if ((t = PyNumber_InPlaceOr(i, j)) == 0) goto end; + Py_DECREF(i); i = t; + if ((rc = PyNumber_Int(i)) == 0) goto end; +end: + Py_XDECREF(i); + Py_XDECREF(j); + return (rc); +#endif +} + +#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 (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); \ + } +DOUINTSZ(CONVU_) + +int convk64(PyObject *o, void *pp) +{ + PyObject *i = 0; + int rc = 0; +#if HAVE_LONG_LONG + unsigned PY_LONG_LONG t; +#else + PyObject *t; + uint32 lo, hi; +#endif + +#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); + if ((t = PyNumber_InPlaceRshift(i, i32)) == 0) goto end; + Py_DECREF(i); i = t; + hi = PyInt_AsUnsignedLongMask(i); + if ((t = PyNumber_InPlaceRshift(i, i32)) == 0) goto end; + Py_DECREF(i); i = t; + if (PyObject_IsTrue(i)) VALERR("out of range"); + SET64(*(kludge64 *)pp, hi, lo); +#endif + rc = 1; + +end: + Py_XDECREF(i); + return (rc); +} + +/*----- That's all, folks -------------------------------------------------*/ diff --git a/pyke-mLib.h b/pyke-mLib.h new file mode 100644 index 0000000..f1e8cd2 --- /dev/null +++ b/pyke-mLib.h @@ -0,0 +1,62 @@ +/* -*-c-*- + * + * Pyke: the Python Kit for Extensions, mLib integration + * + * (c) 2019 Straylight/Edgeware + */ + +/*----- Licensing notice --------------------------------------------------* + * + * This file is part of Pyke: the Python Kit for Extensions. + * + * Pyke is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Pyke is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * along with Pyke. If not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef PYKE_MLIB_H +#define PYKE_MLIB_H + +#ifdef __cplusplus + extern "C" { +#endif + +/*----- Header files ------------------------------------------------------*/ + +#ifndef PYKE_H +# include "pyke.h" +#endif + +PUBLIC_SYMBOLS; +#include +PRIVATE_SYMBOLS; + +/*----- Conversions -------------------------------------------------------*/ + +#define DECL_CONVU_(n) extern int convu##n(PyObject *, void *); +DOUINTSZ(DECL_CONVU_) + /* Define an `O&' input conversion `convuN' for each mLib type `uintN'. */ + +extern int convk64(PyObject *, void *); + /* Input conversion for `kludge64'. */ + +extern PyObject *getk64(kludge64); + /* Output conversion for `kludge64'. */ + +/*----- That's all, folks -------------------------------------------------*/ + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/pyke.c b/pyke.c new file mode 100644 index 0000000..883223a --- /dev/null +++ b/pyke.c @@ -0,0 +1,371 @@ +/* -*-c-*- + * + * Pyke: the Python Kit for Extensions + * + * (c) 2019 Straylight/Edgeware + */ + +/*----- Licensing notice --------------------------------------------------* + * + * This file is part of Pyke: the Python Kit for Extensions. + * + * Pyke is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Pyke is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * along with Pyke. If not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/*----- Header files ------------------------------------------------------*/ + +#include "pyke.h" + +/*----- External variables ------------------------------------------------*/ + +PyObject *modname; +PyObject *home_module; + +/*----- Conversions -------------------------------------------------------*/ + +PyObject *getulong(unsigned long w) +{ + if (w <= LONG_MAX) return (PyInt_FromLong(w)); + else return (PyLong_FromUnsignedLong(w)); +} + +PyObject *getbool(int b) + { if (b) RETURN_TRUE; else RETURN_FALSE; } + +int convulong(PyObject *o, void *pp) +{ + long i; + unsigned long *p = pp; + PyObject *t; + + if (!o) VALERR("can't delete"); + if (PyInt_Check(o)) { + i = PyInt_AS_LONG(o); + if (i < 0) VALERR("must be nonnegative"); + *p = i; + } else { + if ((t = PyNumber_Long(o)) == 0) goto end; + *p = PyLong_AsUnsignedLong(t); + Py_DECREF(t); + if (PyErr_Occurred()) goto end; + } + return (1); +end: + return (0); +} + +int convuint(PyObject *o, void *pp) +{ + unsigned long u; + unsigned *p = pp; + + if (!convulong(o, &u)) goto end; + if (u > UINT_MAX) VALERR("out of range"); + *p = u; + return (1); +end: + return (0); +} + +int convszt(PyObject *o, void *pp) +{ + unsigned long u; + size_t *p = pp; + + if (!convulong(o, &u)) goto end; + if (u > ~(size_t)0) VALERR("out of range"); + *p = u; + return (1); +end: + return (0); +} + +int convbool(PyObject *o, void *pp) +{ + if (!o) VALERR("can't delete"); + *(int *)pp = PyObject_IsTrue(o); + return (1); +end: + return (0); +} + +/*----- Miscellaneous utilities -------------------------------------------*/ + +PyObject *abstract_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw) +{ + PyErr_SetString(PyExc_TypeError, "can't instantiate this class"); + return (0); +} + +/*----- Saving and restoring exceptions ----------------------------------*/ + +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); + } +} + +/*----- Type definitions --------------------------------------------------*/ + +static const PyTypeObject emptytype = { 0 }; + +void *newtype(PyTypeObject *metaty, + const PyTypeObject *skel, + const char *name) +{ + PyHeapTypeObject *ty = + (PyHeapTypeObject *)_PyObject_GC_Malloc(_PyObject_VAR_SIZE(metaty, 0)); + if (!skel) skel = &emptytype; + memcpy(ty, skel, sizeof(*skel)); + if (ty->ht_type.tp_base) Py_INCREF(ty->ht_type.tp_base); +#define COPY(blah) do { \ + if (ty->ht_type.tp_as_##blah) { \ + memcpy(&ty->as_##blah, \ + ty->ht_type.tp_as_##blah, \ + sizeof(ty->as_##blah)); \ + ty->ht_type.tp_as_##blah = &ty->as_##blah; \ + } \ + } while (0) + COPY(number); + COPY(sequence); + COPY(mapping); + COPY(buffer); +#undef COPY + if (name) + ty->ht_name = PyString_FromString(name); + else if (ty->ht_type.tp_name) + ty->ht_name = PyString_FromString(ty->ht_type.tp_name); + if (ty->ht_name) + ty->ht_type.tp_name = PyString_AS_STRING(ty->ht_name); + (void)PyObject_INIT(&ty->ht_type, metaty); + Py_INCREF(metaty); + return (ty); +} + +void typeready(PyTypeObject *ty) +{ + PyType_Ready(ty); + PyDict_SetItemString(ty->tp_dict, "__module__", modname); +} + +PyTypeObject *inittype(PyTypeObject *tyskel, PyTypeObject *meta) +{ + PyTypeObject *ty = newtype(meta, tyskel, 0); + ty->tp_flags |= Py_TPFLAGS_HEAPTYPE; + typeready(ty); + return (ty); +} + +/*----- Populating modules ------------------------------------------------*/ + +PyObject *mkexc(PyObject *mod, PyObject *base, + const char *name, PyMethodDef *mm) +{ + PyObject *nameobj = 0; + PyObject *dict = 0; + PyObject *exc = 0; + PyObject *func = 0; + PyObject *meth = 0; + + if ((dict = PyDict_New()) == 0) goto fail; + + if (mm) { + while (mm->ml_name) { + if ((func = PyCFunction_NewEx(mm, 0, mod)) == 0 || + (meth = PyMethod_New(func, 0, exc)) == 0 || + PyDict_SetItemString(dict, mm->ml_name, meth)) + goto fail; + Py_DECREF(func); func = 0; + Py_DECREF(meth); meth = 0; + mm++; + } + } + + 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); + return (exc); + +fail: + Py_XDECREF(exc); + Py_XDECREF(func); + Py_XDECREF(meth); + exc = 0; + goto done; +} + +void setconstants(PyObject *mod, const struct nameval *c) +{ + PyObject *x; + unsigned long u; + + while (c->name) { + 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++; + } +} + +/*----- Submodules --------------------------------------------------------*/ + +static PyMethodDef *global_methods; +static size_t nmethods, methodsz; + +void addmethods(const PyMethodDef *m) +{ + size_t n, want, newsz; + + for (n = 0; m[n].ml_name; n++); + want = nmethods + n + 1; + if (want > methodsz) { + newsz = methodsz ? 2*methodsz : 16; + while (want > newsz) newsz *= 2; + if (!global_methods) + global_methods = PyObject_Malloc(newsz*sizeof(PyMethodDef)); + else + global_methods = PyObject_Realloc(global_methods, + newsz*sizeof(PyMethodDef)); + assert(global_methods); + methodsz = newsz; + } + memcpy(global_methods + nmethods, m, n*sizeof(PyMethodDef)); + nmethods += n; + global_methods[nmethods].ml_name = 0; +} + +PyMethodDef *donemethods(void) { return (global_methods); } + +/*----- Low-level Python interface ----------------------------------------*/ + +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 pyke_core_pyinit(void) { addmethods(methods); } +void pyke_core_pyinsert(PyObject *mod) { ; } + +/*----- That's all, folks -------------------------------------------------*/ diff --git a/pyke.h b/pyke.h new file mode 100644 index 0000000..1f6232c --- /dev/null +++ b/pyke.h @@ -0,0 +1,363 @@ +/* -*-c-*- + * + * Pyke: the Python Kit for Extensions + * + * (c) 2019 Straylight/Edgeware + */ + +/*----- Licensing notice --------------------------------------------------* + * + * This file is part of Pyke: the Python Kit for Extensions. + * + * Pyke is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Pyke is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * along with Pyke. If not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef PYKE_H +#define PYKE_H + +#ifdef __cplusplus + extern "C" { +#endif + +/*----- Header files ------------------------------------------------------*/ + +#define PY_SSIZE_T_CLEAN + +#include +#include + +/*----- Other preliminaries -----------------------------------------------*/ + +#define NOTHING +#define COMMA , + +/*----- Symbol visibility -------------------------------------------------* + * + * This library is very messy regarding symbol namespace. Keep this mess + * within our shared-object. + */ + +#define GOBBLE_SEMI extern int notexist +#if defined(__GNUC__) && defined(__ELF__) +# define PRIVATE_SYMBOLS _Pragma("GCC visibility push(hidden)") GOBBLE_SEMI +# define PUBLIC_SYMBOLS _Pragma("GCC visibility pop") GOBBLE_SEMI +# define EXPORT __attribute__((__visibility__("default"))) +#else +# define PRIVATE_SYMBOLS GOBBLE_SEMI +# define PUBLIC_SYMBOLS GOBBLE_SEMI +# define EXPORT +#endif + +PRIVATE_SYMBOLS; + +/*----- Utilities for returning values and exceptions ---------------------*/ + +/* Returning values. */ +#define RETURN_OBJ(obj) do { Py_INCREF(obj); return (obj); } while (0) +#define RETURN_NONE RETURN_OBJ(Py_None) +#define RETURN_NOTIMPL RETURN_OBJ(Py_NotImplemented) +#define RETURN_TRUE RETURN_OBJ(Py_True) +#define RETURN_FALSE RETURN_OBJ(Py_False) +#define RETURN_ME RETURN_OBJ(me) + +/* Returning exceptions. (Note that `KeyError' is `MAPERR' here, because + * Catacomb has its own kind of `KeyError'.) + */ +#define EXCERR(exc, str) do { \ + PyErr_SetString(exc, str); \ + 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) +#define SYSERR(str) EXCERR(PyExc_SystemError, str) +#define NIERR(str) EXCERR(PyExc_NotImplementedError, str) +#define INDEXERR(idx) do { \ + PyErr_SetObject(PyExc_KeyError, idx); \ + goto end; \ +} while (0) +#define OSERR(name) do { \ + PyErr_SetFromErrnoWithFilename(PyExc_OSError, name); \ + goto end; \ +} while (0) + +/* Saving and restoring exceptions. */ +struct excinfo { PyObject *ty, *val, *tb; }; +#define EXCINFO_INIT { 0, 0, 0 } +#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 *, ...); + +/*----- Conversions -------------------------------------------------------*/ + +/* Define an input conversion (`O&') function: check that the object has + * Python type TY, and extract a C pointer to CTY by calling EXT on the + * object (which may well be a macro). + */ +#define CONVFUNC(ty, cty, ext) \ + int conv##ty(PyObject *o, void *p) \ + { \ + if (!PyObject_TypeCheck(o, ty##_pytype)) \ + TYERR("wanted a " #ty); \ + *(cty *)p = ext(o); \ + return (1); \ + end: \ + return (0); \ + } + +/* Input conversion functions for standard kinds of objects, with overflow + * checking where applicable. + */ +extern int convulong(PyObject *, void *); /* unsigned long */ +extern int convuint(PyObject *, void *); /* unsigned int */ +extern int convszt(PyObject *, void *); /* size_t */ +extern int convbool(PyObject *, void *); /* bool */ + +/* Output conversions. */ +extern PyObject *getbool(int); /* bool */ +extern PyObject *getulong(unsigned long); /* any kind of unsigned integer */ + +/*----- Miscellaneous utilities -------------------------------------------*/ + +#define FREEOBJ(obj) \ + (((PyObject *)(obj))->ob_type->tp_free((PyObject *)(obj))) + /* Actually free OBJ, e.g., in a deallocation function. */ + +extern PyObject *abstract_pynew(PyTypeObject *, PyObject *, PyObject *); + /* A `tp_new' function which refuses to make the object. */ + +#define KWLIST (/*unconst*/ char **)kwlist + /* Strip `const' qualifiers from the keyword list `kwlist'. Useful when + * calling `PyArg_ParseTupleAndKeywords', which isn't `const'-correct. + */ + +/*----- Type definitions --------------------------------------------------* + * + * Pyke types are defined in a rather unusual way. + * + * The main code defines a `type skeleton' of type `PyTypeObject', + * conventionally named `TY_pytype_skel'. Unlike typical Python type + * definitions in extensions, this can (and should) be read-only. Also, + * there's no point in setting the `tp_base' pointer here, because the actual + * runtime base type object won't, in general, be known at compile time. + * Instead, the type skeletons are converted into Python `heap types' by the + * `INITTYPE' macro. The main difference is that Python code can add + * attributes to heap types, and we make extensive use of this ability. + */ + +extern void *newtype(PyTypeObject */*meta*/, + const PyTypeObject */*skel*/, const char */*name*/); + /* Make and return a new Python type object, of type META (typically + * `PyType_Type', but may be a subclass), filled in from the skeleton SKEL + * (null to inherit everything), and named NAME. The caller can mess with + * the type object further at this time: call `typeready' when it's set up + * properly. + */ + +extern void typeready(PyTypeObject *); + /* The type object is now ready to be used. */ + +extern PyTypeObject *inittype(PyTypeObject */*skel*/, + PyTypeObject */*meta*/); + /* All-in-one function to construct a working type from a type skeleton + * SKEL, with metaclass META. The caller is expected to have filled in the + * direct superclass in SKEL->tp_base. + */ + +/* Alias for built-in types, to fit in with Pyke naming conventions. */ +#define root_pytype 0 +#define type_pytype &PyType_Type + +#define INITTYPE_META(ty, base, meta) do { \ + ty##_pytype_skel.tp_base = base##_pytype; \ + ty##_pytype = inittype(&ty##_pytype_skel, meta##_pytype); \ +} while (0) +#define INITTYPE(ty, base) INITTYPE_META(ty, base, type) + /* Macros to initialize a type from its skeleton. */ + +/* Convenience wrappers for filling in `PyMethodDef' tables, following + * Pyke naming convention. Define `METHNAME' locally as + * + * #define METHNAME(name) foometh_##func + * + * around the method table. + */ +#define METH(func, doc) \ + { #func, METHNAME(func), METH_VARARGS, doc }, +#define KWMETH(func, doc) \ + { #func, (PyCFunction)METHNAME(func), \ + METH_VARARGS | METH_KEYWORDS, doc }, + +/* Convenience wrappers for filling in `PyGetSetDef' tables, following Pyke + * naming convention. Define `GETSETNAME' locally as + * + * #define GETSETNAME(op, name) foo##op##_##func + * + * around the get/set table. + */ +#define GET(func, doc) \ + { #func, GETSETNAME(get, func), 0, doc }, +#define GETSET(func, doc) \ + { #func, GETSETNAME(get, func), GETSETNAME(set, func), doc }, + +/* Convenience wrapper for filling in `PyMemberDef' tables. Define + * `MEMBERSTRUCT' locally as + * + * #define MEMBERSTRUCT foo_pyobj + * + * around the member table. + */ +#define MEMBER(name, ty, f, doc) \ + { #name, ty, offsetof(MEMBERSTRUCT, name), f, doc }, + +/*----- Populating modules ------------------------------------------------*/ + +extern PyObject *modname; + /* The overall module name. Set this with `PyString_FromString'. */ + +extern PyObject *home_module; + /* The overall module object. */ + +extern PyObject *mkexc(PyObject */*mod*/, PyObject */*base*/, + const char */*name*/, PyMethodDef */*methods*/); + /* Make and return an exception class called NAME, which will end up in + * module MOD (though it is not added at this time). The new class is a + * subclass of BASE. Attach the METHODS to it. + */ + +#define INSERT(name, ob) do { \ + PyObject *_o = (PyObject *)(ob); \ + Py_INCREF(_o); \ + PyModule_AddObject(mod, name, _o); \ +} while (0) + /* Insert a Python object OB into the module `mod' under the given NAME. */ + +/* Numeric constants. */ +struct nameval { const char *name; unsigned f; unsigned long value; }; +#define CF_SIGNED 1u +extern void setconstants(PyObject *, const struct nameval *); + +#define INSEXC(name, var, base, meth) \ + INSERT(name, var = mkexc(mod, base, name, meth)) + /* Insert an exception class into the module `mod'; other arguments are as + * for `mkexc'. + */ + +/*----- Submodules --------------------------------------------------------* + * + * It's useful to split the Python module up into multiple source files, and + * have each one contribute its definitions into the main module. + * + * Define a list-macro `MODULES' in the master header file naming the + * submodules to be processed, and run + * + * MODULES(DECLARE_MODINIT) + * + * to declare the interface functions. + * + * Each submodule FOO defines two functions: `FOO_pyinit' initializes types + * (see `INITTYPE' above) and accumulates methods (`addmethods' below), while + * `FOO_pyinsert' populates the module with additional definitions + * (especially types, though also constants). + * + * The top-level module initialization should call `INIT_MODULES' before + * creating the Python module, and `INSERT_MODULES' afterwards to make + * everything work. + */ + +extern void addmethods(const PyMethodDef *); +extern PyMethodDef *donemethods(void); + /* Accumulate method-table fragments, and return the combined table of all + * of the fragments. + */ + +#define DECLARE_MODINIT(m) \ + extern void m##_pyinit(void); \ + extern void m##_pyinsert(PyObject *); + /* Declare submodule interface functions. */ + +#define DOMODINIT(m) m##_pyinit(); +#define DOMODINSERT(m) m##_pyinsert(mod); +#define INIT_MODULES do { MODULES(DOMODINIT) } while (0) +#define INSERT_MODULES do { MODULES(DOMODINSERT) } while (0) + /* Top-level dispatch to the various submodules. */ + +/*----- Generic mapping support -------------------------------------------*/ + +/* Mapping methods. */ +#define GMAP_METH(func, doc) { #func, gmapmeth_##func, METH_VARARGS, doc }, +#define GMAP_KWMETH(func, doc) \ + { #func, (PyCFunction)gmapmeth_##func, METH_VARARGS|METH_KEYWORDS, doc }, +#define GMAP_METHDECL(func, doc) \ + extern PyObject *gmapmeth_##func(PyObject *, PyObject *); +#define GMAP_KWMETHDECL(func, doc) \ + extern PyObject *gmapmeth_##func(PyObject *, PyObject *, PyObject *); + +#define GMAP_DOROMETHODS(METH, KWMETH) \ + METH (has_key, "D.has_key(KEY) -> BOOL") \ + METH (keys, "D.keys() -> LIST") \ + METH (values, "D.values() -> LIST") \ + METH (items, "D.items() -> LIST") \ + METH (iterkeys, "D.iterkeys() -> ITER") \ + METH (itervalues, "D.itervalues() -> ITER") \ + METH (iteritems, "D.iteritems() -> ITER") \ + KWMETH(get, "D.get(KEY, [default = None]) -> VALUE") + +#define GMAP_DOMETHODS(METH, KWMETH) \ + GMAP_DOROMETHODS(METH, KWMETH) \ + METH (clear, "D.clear()") \ + KWMETH(setdefault, "D.setdefault(K, [default = None]) -> VALUE") \ + KWMETH(pop, "D.pop(KEY, [default = ]) -> VALUE") \ + METH (popitem, "D.popitem() -> (KEY, VALUE)") \ + METH (update, "D.update(MAP)") + +GMAP_DOMETHODS(GMAP_METHDECL, GMAP_KWMETHDECL) +#define GMAP_ROMETHODS GMAP_DOROMETHODS(GMAP_METH, GMAP_KWMETH) +#define GMAP_METHODS GMAP_DOMETHODS(GMAP_METH, GMAP_KWMETH) + +/* Mapping protocol implementation. */ +extern Py_ssize_t gmap_pysize(PyObject *); /* for `mp_length' */ +extern PySequenceMethods gmap_pysequence; /* for `tp_as_sequence' */ +extern PyMethodDef gmap_pymethods[]; /* all the standard methods */ + +/*----- That's all, folks -------------------------------------------------*/ + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/util.c b/util.c deleted file mode 100644 index 03a39af..0000000 --- a/util.c +++ /dev/null @@ -1,873 +0,0 @@ -/* -*-c-*- - * - * Miscellaneous utilities (not Catacomb-specific) - * - * (c) 2005 Straylight/Edgeware - */ - -/*----- Licensing notice --------------------------------------------------* - * - * This file is part of the Python interface to Catacomb. - * - * Catacomb/Python is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * Catacomb/Python is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Catacomb/Python; if not, write to the Free Software Foundation, - * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/*----- Header files ------------------------------------------------------*/ - -#include "catacomb-python.h" - -/* #undef HAVE_LONG_LONG */ - -/*----- External values ---------------------------------------------------*/ - -PyObject *modname = 0; -PyObject *home_module = 0; - -/*----- Conversions -------------------------------------------------------*/ - -PyObject *getulong(unsigned long w) -{ - if (w <= LONG_MAX) - return (PyInt_FromLong(w)); - else - 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 (init_i32()) goto end; - if ((i = PyLong_FromUnsignedLong(HI64(u))) == 0) goto end; - if ((t = PyNumber_InPlaceLshift(i, i32)) == 0) goto end; - Py_DECREF(i); i = t; - if ((j = PyLong_FromUnsignedLong(LO64(u))) == 0) goto end; - if ((t = PyNumber_InPlaceOr(i, j)) == 0) goto end; - Py_DECREF(i); i = t; - if ((rc = PyNumber_Int(i)) == 0) goto end; -end: - Py_XDECREF(i); - Py_XDECREF(j); - return (rc); -#endif -} - -PyObject *getbool(int b) -{ - if (b) RETURN_TRUE; - else RETURN_FALSE; -} - -PyObject *abstract_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw) -{ - PyErr_SetString(PyExc_TypeError, "can't instantiate this class"); - return (0); -} - -int convulong(PyObject *o, void *pp) -{ - long i; - unsigned long *p = pp; - PyObject *t; - - if (!o) VALERR("can't delete"); - if (PyInt_Check(o)) { - i = PyInt_AS_LONG(o); - if (i < 0) VALERR("must be nonnegative"); - *p = i; - } else { - if ((t = PyNumber_Long(o)) == 0) goto end; - *p = PyLong_AsUnsignedLong(t); - Py_DECREF(t); - if (PyErr_Occurred()) goto end; - } - return (1); -end: - 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 (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); \ - } -DOUINTSZ(CONVU_) - -int convuint(PyObject *o, void *pp) -{ - unsigned long u; - unsigned *p = pp; - - if (!convulong(o, &u)) goto end; - if (u > UINT_MAX) VALERR("out of range"); - *p = u; - return (1); -end: - return (0); -} - -int convk64(PyObject *o, void *pp) -{ - 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); - if ((t = PyNumber_InPlaceRshift(i, i32)) == 0) goto end; - Py_DECREF(i); i = t; - hi = PyInt_AsUnsignedLongMask(i); - if ((t = PyNumber_InPlaceRshift(i, i32)) == 0) goto end; - Py_DECREF(i); i = t; - if (PyObject_IsTrue(i)) VALERR("out of range"); - SET64(*(kludge64 *)pp, hi, lo); -#endif - rc = 1; - -end: - Py_XDECREF(i); - return (rc); -} - -int convmpw(PyObject *o, void *pp) -{ - unsigned long u; - unsigned *p = pp; - - if (!convulong(o, &u)) goto end; - if (u > MPW_MAX) VALERR("out of range"); - *p = u; - return (1); -end: - return (0); -} - -int convszt(PyObject *o, void *pp) -{ - unsigned long u; - size_t *p = pp; - - if (!convulong(o, &u)) goto end; - if (u > ~(size_t)0) VALERR("out of range"); - *p = u; - return (1); -end: - return (0); -} - -int convbool(PyObject *o, void *pp) -{ - if (!o) VALERR("can't delete"); - *(int *)pp = PyObject_IsTrue(o); - return (1); -end: - return (0); -} - -/*----- Type messing ------------------------------------------------------*/ - -static const PyTypeObject emptytype = { 0 }; - -void *newtype(PyTypeObject *metaty, - const PyTypeObject *skel, - const char *name) -{ - PyHeapTypeObject *ty = - (PyHeapTypeObject *)_PyObject_GC_Malloc(_PyObject_VAR_SIZE(metaty, 0)); - if (!skel) skel = &emptytype; - memcpy(ty, skel, sizeof(*skel)); - if (ty->ht_type.tp_base) Py_INCREF(ty->ht_type.tp_base); -#define COPY(blah) do { \ - if (ty->ht_type.tp_as_##blah) { \ - memcpy(&ty->as_##blah, \ - ty->ht_type.tp_as_##blah, \ - sizeof(ty->as_##blah)); \ - ty->ht_type.tp_as_##blah = &ty->as_##blah; \ - } \ - } while (0) - COPY(number); - COPY(sequence); - COPY(mapping); - COPY(buffer); -#undef COPY - if (name) - ty->ht_name = PyString_FromString(name); - else if (ty->ht_type.tp_name) - ty->ht_name = PyString_FromString(ty->ht_type.tp_name); - if (ty->ht_name) - ty->ht_type.tp_name = PyString_AS_STRING(ty->ht_name); - (void)PyObject_INIT(&ty->ht_type, metaty); - Py_INCREF(metaty); - return (ty); -} - -void typeready(PyTypeObject *ty) -{ - PyType_Ready(ty); - PyDict_SetItemString(ty->tp_dict, "__module__", modname); -} - -PyTypeObject *inittype(PyTypeObject *tyskel, PyTypeObject *meta) -{ - PyTypeObject *ty = newtype(meta, tyskel, 0); - ty->tp_flags |= Py_TPFLAGS_HEAPTYPE; - typeready(ty); - return (ty); -} - -/*----- Constants ---------------------------------------------------------*/ - -void setconstants(PyObject *mod, const struct nameval *c) -{ - PyObject *x; - unsigned long u; - - while (c->name) { - 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++; - } -} - -/*----- Building method tables --------------------------------------------*/ - -static PyMethodDef *global_methods; -static size_t nmethods, methodsz; - -void addmethods(const PyMethodDef *m) -{ - size_t n, want, newsz; - - for (n = 0; m[n].ml_name; n++); - want = nmethods + n + 1; - if (want > methodsz) { - newsz = methodsz ? 2*methodsz : 16; - while (want > newsz) newsz *= 2; - if (!global_methods) - global_methods = PyObject_Malloc(newsz*sizeof(PyMethodDef)); - else - global_methods = PyObject_Realloc(global_methods, - newsz*sizeof(PyMethodDef)); - assert(global_methods); - methodsz = newsz; - } - memcpy(global_methods + nmethods, m, n*sizeof(PyMethodDef)); - nmethods += n; - global_methods[nmethods].ml_name = 0; -} - -PyMethodDef *donemethods(void) { return (global_methods); } - -/*----- Exceptions --------------------------------------------------------*/ - -PyObject *mkexc(PyObject *mod, PyObject *base, - const char *name, PyMethodDef *mm) -{ - PyObject *nameobj = 0; - PyObject *dict = 0; - PyObject *exc = 0; - PyObject *func = 0; - PyObject *meth = 0; - - if ((dict = PyDict_New()) == 0) goto fail; - - if (mm) { - while (mm->ml_name) { - if ((func = PyCFunction_NewEx(mm, 0, mod)) == 0 || - (meth = PyMethod_New(func, 0, exc)) == 0 || - PyDict_SetItemString(dict, mm->ml_name, meth)) - goto fail; - Py_DECREF(func); func = 0; - Py_DECREF(meth); meth = 0; - mm++; - } - } - - 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); - return (exc); - -fail: - Py_XDECREF(exc); - Py_XDECREF(func); - Py_XDECREF(meth); - exc = 0; - 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; - -typedef struct iter_pyobj { - PyObject_HEAD - PyObject *map; - PyObject *i; -} iter_pyobj; -#define ITER_MAP(o) (((iter_pyobj *)(o))->map) -#define ITER_I(o) (((iter_pyobj *)(o))->i) - -static void iter_pydealloc(PyObject *me) - { Py_DECREF(ITER_MAP(me)); Py_DECREF(ITER_I(me)); FREEOBJ(me); } - -static PyObject *itemiter_pynext(PyObject *me) -{ - PyObject *k = 0, *v = 0, *rc = 0; - - if ((k = PyIter_Next(ITER_I(me))) != 0 && - (v = PyObject_GetItem(ITER_MAP(me), k)) != 0) - rc = Py_BuildValue("(OO)", k, v); - Py_XDECREF(k); Py_XDECREF(v); - return (rc); -} - -static PyTypeObject itemiter_pytype_skel = { - PyObject_HEAD_INIT(0) 0, /* Header */ - "ItemIter", /* @tp_name@ */ - sizeof(iter_pyobj), /* @tp_basicsize@ */ - 0, /* @tp_itemsize@ */ - - iter_pydealloc, /* @tp_dealloc@ */ - 0, /* @tp_print@ */ - 0, /* @tp_getattr@ */ - 0, /* @tp_setattr@ */ - 0, /* @tp_compare@ */ - 0, /* @tp_repr@ */ - 0, /* @tp_as_number@ */ - 0, /* @tp_as_sequence@ */ - 0, /* @tp_as_mapping@ */ - 0, /* @tp_hash@ */ - 0, /* @tp_call@ */ - 0, /* @tp_str@ */ - 0, /* @tp_getattro@ */ - 0, /* @tp_setattro@ */ - 0, /* @tp_as_buffer@ */ - Py_TPFLAGS_DEFAULT | /* @tp_flags@ */ - Py_TPFLAGS_BASETYPE, - - /* @tp_doc@ */ - "Iterates over the items of a mapping.", - - 0, /* @tp_traverse@ */ - 0, /* @tp_clear@ */ - 0, /* @tp_richcompare@ */ - 0, /* @tp_weaklistoffset@ */ - PyObject_SelfIter, /* @tp_iter@ */ - itemiter_pynext, /* @tp_iternext@ */ - 0, /* @tp_methods@ */ - 0, /* @tp_members@ */ - 0, /* @tp_getset@ */ - 0, /* @tp_base@ */ - 0, /* @tp_dict@ */ - 0, /* @tp_descr_get@ */ - 0, /* @tp_descr_set@ */ - 0, /* @tp_dictoffset@ */ - 0, /* @tp_init@ */ - PyType_GenericAlloc, /* @tp_alloc@ */ - abstract_pynew, /* @tp_new@ */ - 0, /* @tp_free@ */ - 0 /* @tp_is_gc@ */ -}; - -static PyObject *valiter_pynext(PyObject *me) -{ - PyObject *k = 0, *rc = 0; - - if ((k = PyIter_Next(ITER_I(me))) != 0) - rc = PyObject_GetItem(ITER_MAP(me), k); - Py_XDECREF(k); - return (rc); -} - -static PyTypeObject valiter_pytype_skel = { - PyObject_HEAD_INIT(0) 0, /* Header */ - "ValueIter", /* @tp_name@ */ - sizeof(iter_pyobj), /* @tp_basicsize@ */ - 0, /* @tp_itemsize@ */ - - iter_pydealloc, /* @tp_dealloc@ */ - 0, /* @tp_print@ */ - 0, /* @tp_getattr@ */ - 0, /* @tp_setattr@ */ - 0, /* @tp_compare@ */ - 0, /* @tp_repr@ */ - 0, /* @tp_as_number@ */ - 0, /* @tp_as_sequence@ */ - 0, /* @tp_as_mapping@ */ - 0, /* @tp_hash@ */ - 0, /* @tp_call@ */ - 0, /* @tp_str@ */ - 0, /* @tp_getattro@ */ - 0, /* @tp_setattro@ */ - 0, /* @tp_as_buffer@ */ - Py_TPFLAGS_DEFAULT | /* @tp_flags@ */ - Py_TPFLAGS_BASETYPE, - - /* @tp_doc@ */ - "Iterates over the values of a mapping.", - - 0, /* @tp_traverse@ */ - 0, /* @tp_clear@ */ - 0, /* @tp_richcompare@ */ - 0, /* @tp_weaklistoffset@ */ - PyObject_SelfIter, /* @tp_iter@ */ - valiter_pynext, /* @tp_iternext@ */ - 0, /* @tp_methods@ */ - 0, /* @tp_members@ */ - 0, /* @tp_getset@ */ - 0, /* @tp_base@ */ - 0, /* @tp_dict@ */ - 0, /* @tp_descr_get@ */ - 0, /* @tp_descr_set@ */ - 0, /* @tp_dictoffset@ */ - 0, /* @tp_init@ */ - PyType_GenericAlloc, /* @tp_alloc@ */ - abstract_pynew, /* @tp_new@ */ - 0, /* @tp_free@ */ - 0 /* @tp_is_gc@ */ -}; - -PySequenceMethods gmap_pysequence = { - 0, /* @sq_length@ */ - 0, /* @sq_concat@ */ - 0, /* @sq_repeat@ */ - 0, /* @sq_item@ */ - 0, /* @sq_slice@ */ - 0, /* @sq_ass_item@ */ - 0, /* @sq_ass_slice@ */ - PyMapping_HasKey, /* @sq_contains@ */ - 0, /* @sq_inplace_concat@ */ - 0 /* @sq_inplace_repeat@ */ -}; - -Py_ssize_t gmap_pysize(PyObject *me) -{ - PyObject *i = 0, *x = 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; } - if (PyErr_Occurred()) goto done; - rc = n; -done: - Py_XDECREF(i); Py_XDECREF(x); - return (rc); -} - -PyObject *gmapmeth_has_key(PyObject *me, PyObject *arg) -{ - PyObject *k; - if (!PyArg_ParseTuple(arg, "O:has_key", &k)) return (0); - return (getbool(PyMapping_HasKey(me, k))); -} - -PyObject *gmapmeth_keys(PyObject *me, PyObject *arg) -{ - PyObject *l = 0, *i = 0, *k, *rc = 0; - int err; - - if (!PyArg_ParseTuple(arg, ":keys") || - (l = PyList_New(0)) == 0 || - (i = PyObject_GetIter(me)) == 0) - goto done; - while ((k = PyIter_Next(i)) != 0) - { err = PyList_Append(l, k); Py_DECREF(k); if (err) goto done; } - if (PyErr_Occurred()) goto done; - rc = l; l = 0; -done: - Py_XDECREF(l); Py_XDECREF(i); - return (rc); -} - -PyObject *gmapmeth_values(PyObject *me, PyObject *arg) -{ - PyObject *l = 0, *i = 0, *k, *v, *rc = 0; - int err = 0; - - if (!PyArg_ParseTuple(arg, ":values") || - (l = PyList_New(0)) == 0 || - (i = PyObject_GetIter(me)) == 0) - goto done; - while ((k = PyIter_Next(i)) != 0) { - if ((v = PyObject_GetItem(me, k)) == 0 || - PyList_Append(l, v)) - err = -1; - Py_DECREF(k); Py_XDECREF(v); - if (err) goto done; - } - if (PyErr_Occurred()) goto done; - rc = l; l = 0; -done: - Py_XDECREF(l); Py_XDECREF(i); - return (rc); -} - -PyObject *gmapmeth_items(PyObject *me, PyObject *arg) -{ - PyObject *l = 0, *i = 0, *k, *v, *z, *rc = 0; - int err = 0; - - if (!PyArg_ParseTuple(arg, ":items") || - (l = PyList_New(0)) == 0 || - (i = PyObject_GetIter(me)) == 0) - goto done; - while ((k = PyIter_Next(i)) != 0) { - z = 0; - if ((v = PyObject_GetItem(me, k)) == 0 || - (z = Py_BuildValue("(OO)", k, v)) == 0 || - PyList_Append(l, z)) - err = -1; - Py_DECREF(k); Py_XDECREF(v); Py_XDECREF(z); - if (err) goto done; - } - if (PyErr_Occurred()) goto done; - rc = l; l = 0; -done: - Py_XDECREF(l); Py_XDECREF(i); - return (rc); -} - -PyObject *gmapmeth_iterkeys(PyObject *me, PyObject *arg) -{ - if (!PyArg_ParseTuple(arg, ":iterkeys")) return (0); - return (PyObject_GetIter(me)); -} - -PyObject *gmapmeth_itervalues(PyObject *me, PyObject *arg) -{ - PyObject *i; - iter_pyobj *ii; - - if (!PyArg_ParseTuple(arg, ":itervalues") || - (i = PyObject_GetIter(me)) == 0) - return (0); - ii = PyObject_NEW(iter_pyobj, valiter_pytype); - ii->map = me; Py_INCREF(me); - ii->i = i; - return ((PyObject *)ii); -} - -PyObject *gmapmeth_iteritems(PyObject *me, PyObject *arg) -{ - PyObject *i; - iter_pyobj *ii; - - if (!PyArg_ParseTuple(arg, ":iteritems") || - (i = PyObject_GetIter(me)) == 0) - return (0); - ii = PyObject_NEW(iter_pyobj, itemiter_pytype); - ii->map = me; Py_INCREF(me); - ii->i = i; - return ((PyObject *)ii); -} - -PyObject *gmapmeth_clear(PyObject *me, PyObject *arg) -{ - PyObject *i = 0, *k = 0, *rc = 0; - - if (!PyArg_ParseTuple(arg, ":clear") || - (i = PyObject_GetIter(me)) == 0) - goto end; - while ((k = PyIter_Next(i)) != 0) { - PyObject_DelItem(me, k); - Py_DECREF(k); - } - if (PyErr_Occurred()) goto end; - rc = me; Py_INCREF(me); -end: - Py_XDECREF(i); - return (rc); -} - -static const char *const def_kwlist[] = { "key", "default", 0 }; - -PyObject *gmapmeth_get(PyObject *me, PyObject *arg, PyObject *kw) -{ - PyObject *k, *def = Py_None, *v; - - if (!PyArg_ParseTupleAndKeywords(arg, kw, "O|O:get", - (/*unconst*/ char **)def_kwlist, - &k, &def)) - return (0); - if ((v = PyObject_GetItem(me, k)) != 0) return (v); - PyErr_Clear(); - RETURN_OBJ(def); -} - -PyObject *gmapmeth_setdefault(PyObject *me, PyObject *arg, PyObject *kw) -{ - PyObject *k, *def = Py_None, *v; - - if (!PyArg_ParseTupleAndKeywords(arg, kw, "O|O:setdefault", - (/*unconst*/ char **)def_kwlist, - &k, &def)) - return (0); - if ((v = PyObject_GetItem(me, k)) != 0) return (v); - PyErr_Clear(); - if (PyObject_SetItem(me, k, def)) return (0); - RETURN_OBJ(def); -} - -PyObject *gmapmeth_pop(PyObject *me, PyObject *arg, PyObject *kw) -{ - PyObject *k, *def = 0, *v; - - 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); - } else if (def) { - PyErr_Clear(); - RETURN_OBJ(def); - } else - return (0); -} - -PyObject *gmapmeth_update(PyObject *me, PyObject *arg) -{ - PyObject *map, *i = 0, *k, *v, *rc = 0; - int err = 0; - - if (!PyArg_ParseTuple(arg, "O:update", &map) || - (i = PyObject_GetIter(map)) == 0) - goto end; - while ((k = PyIter_Next(i)) != 0) { - if ((v = PyObject_GetItem(map, k)) == 0 || - PyObject_SetItem(me, k, v)) - err = -1; - Py_DECREF(k); Py_XDECREF(v); - if (err) goto end; - } - if (PyErr_Occurred()) goto end; - rc = me; Py_INCREF(me); -end: - Py_XDECREF(i); - return (rc); -} - -PyObject *gmapmeth_popitem(PyObject *me, PyObject *arg) -{ - PyObject *i = 0, *k = 0, *v = 0, *rc = 0; - - if (!PyArg_ParseTuple(arg, ":popitem") || - (i = PyObject_GetIter(me)) == 0) - goto end; - if ((k = PyIter_Next(i)) == 0) { - if (!PyErr_Occurred()) VALERR("popitem(): mapping is empty"); - goto end; - } - if ((v = PyObject_GetItem(me, k)) == 0 || - PyObject_DelItem(me, k)) - goto end; - rc = Py_BuildValue("(OO)", k, v); -end: - Py_XDECREF(i); Py_XDECREF(k); Py_XDECREF(v); - return (rc); -} - -PyMethodDef gmap_pymethods[] = { - GMAP_METHODS - { 0 } -}; - -/*----- 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) -{ - INITTYPE(itemiter, root); - INITTYPE(valiter, root); - addmethods(methods); -} - -void util_pyinsert(PyObject *mod) -{ - INSERT("ItemIter", itemiter_pytype); - INSERT("ValueIter", valiter_pytype); -} - -/*----- That's all, folks -------------------------------------------------*/ -- 2.11.0