X-Git-Url: https://git.distorted.org.uk/~mdw/mLib-python/blobdiff_plain/83a72c0dad2f0da52131224e9b072ef3490db56f..6c2569879c220eeac35957cdba9a043e8a5ea9ed:/pyke.h diff --git a/pyke.h b/pyke.h index 06c30c2..a60fd76 100644 --- a/pyke.h +++ b/pyke.h @@ -64,6 +64,15 @@ PRIVATE_SYMBOLS; /*----- Python version compatibility hacks --------------------------------*/ +/* Explicit version switching. */ +#if PY_VERSION_HEX >= 0x03000000 +# define PY3 1 +# define PY23(two, three) three +#else +# define PY2 1 +# define PY23(two, three) two +#endif + /* The handy `Py_TYPE' and `Py_SIZE' macros turned up in 2.6. Define them if * they're not already here. */ @@ -82,6 +91,18 @@ PRIVATE_SYMBOLS; # define PyVarObject_HEAD_INIT(super, sz) PyObject_HEAD_INIT(super) sz, #endif +/* Python 3 doesn't have `int', only `long', even though it's called `int' at + * the Python level. Provide some obvious macros to fill in the gaps. + */ +#ifdef PY3 +# define PyInt_Check PyLong_Check +# define PyInt_FromLong PyLong_FromLong +# define PyInt_AS_LONG PyLong_AS_LONG +# define PyInt_AsLong PyLong_AsLong +# define PyInt_AsUnsignedLongMask PyLong_AsUnsignedLongMask +# define PyNumber_Int PyNumber_Long +#endif + /* Python 3.2 changed the type of hash values, so paper over this annoying * difference. */ @@ -89,6 +110,13 @@ PRIVATE_SYMBOLS; typedef long Py_hash_t; #endif +/* Python 3 always has the `CHECKTYPES' behaviour, and doesn't define the + * flag. + */ +#ifdef PY3 +# define Py_TPFLAGS_CHECKTYPES 0 +#endif + /* Plain octet strings. Python 2 calls these `str', while Python 3 calls * them `bytes'. We call them `bin' here, and define the following. * @@ -115,6 +143,25 @@ PRIVATE_SYMBOLS; # * `YN' is a format character for `PyArg_ParseTuple...' for retrieving an * octet string and length from any sort-of vaguely binary-ish object. */ +#ifdef PY3 +# define BINOBJ PyBytesObject +# define BIN_TYPE PyBytes_Type +# define BIN_CHECK(obj) PyBytes_Check(obj) +# define BIN_PTR(obj) PyBytes_AS_STRING(obj) +# define BIN_LEN(obj) PyBytes_GET_SIZE(obj) +# define BIN_FROMSTR(str) PyBytes_FromString(str) +# define BIN_FROMSTRLEN(str, len) PyBytes_FromStringAndSize(str, len) +# define BIN_FORMAT PyBytes_FromFormat +# define BIN_VFORMAT PyBytes_FromFormatV +# define BIN_PREPAREWRITE(obj, ptr, sz) do { \ + (obj) = PyBytes_FromStringAndSize(0, (sz)); \ + (ptr) = PyBytes_AS_STRING(obj); \ + } while (0) +# define BIN_DONEWRITE(obj, sz) do Py_SIZE(obj) = (sz); while (0) +# define BIN_SETLEN(obj, len) do Py_SIZE(obj) = (len); while (0) +# define Y "y" +# define YN "y#" +#else # define BINOBJ PyStringObject # define BIN_TYPE PyString_Type # define BIN_CHECK(obj) PyString_Check(obj) @@ -132,6 +179,7 @@ PRIVATE_SYMBOLS; # define BIN_SETLEN(obj, len) do Py_SIZE(obj) = (len); while (0) # define Y "s" # define YN "s#" +#endif /* Text strings. Both Python 2 and Python 3 call these `str', but they're * very different because a Python 3 `str' is Unicode inside. When dealing @@ -161,6 +209,52 @@ PRIVATE_SYMBOLS; * * (Use `s' and `s#' in `PyArg_ParseTuple...'.) */ +#ifdef PY3 +# define TEXTOBJ PyUnicodeObject +# define TEXT_TYPE PyUnicode_Type +# define TEXT_CHECK(obj) PyUnicode_Check(obj) +# if PY_VERSION_HEX >= 0x03030000 +# define TEXT_PTR(obj) PyUnicode_AsUTF8(obj) +# define TEXT_STR(obj) PyUnicode_AsUTF8(obj) +# define TEXT_PTRLEN(obj, ptr, len) do { \ + Py_ssize_t len_; \ + (ptr) = PyUnicode_AsUTF8AndSize((obj), &len_); \ + (len) = len_; \ + } while (0) +# define TEXT_PREPAREWRITE(obj, ptr, sz) do { \ + (obj) = PyUnicode_New((sz), 127); \ + (ptr) = PyUnicode_DATA(obj); \ + } while (0) +# define TEXT_DONEWRITE(obj, len) do { \ + size_t len_ = (len); \ + assert(PyUnicode_IS_COMPACT_ASCII(obj)); \ + ((char *)PyUnicode_DATA(obj))[len_] = 0; \ + ((PyASCIIObject *)(obj))->length = len_; \ + } while (0) +# else +# define TEXT_PTR(obj) _PyUnicode_AsString(obj) +# define TEXT_STR(obj) _PyUnicode_AsString(obj) +# define TEXT_PTRLEN(obj, ptr, len) do { \ + Py_ssize_t len_; \ + (ptr) = _PyUnicode_AsStringAndSize((obj), &len_); \ + (len) = len_; \ + } while (0) +# define TEXT_PREPAREWRITE(obj, ptr, sz) do { \ + (obj) = PyBytes_FromStringAndSize(0, (sz)); \ + (ptr) = PyBytes_AS_STRING(obj); \ + } while (0) +# define TEXT_DONEWRITE(obj, len) do { \ + PyObject *new_; \ + Py_SIZE(obj) = (len); \ + new_ = PyUnicode_FromEncodedObject(obj, 0, 0); \ + assert(new_); Py_DECREF(obj); (obj) = new_; \ + } while (0) +# endif +# define TEXT_FORMAT PyUnicode_FromFormat +# define TEXT_VFORMAT PyUnicode_FromFormatV +# define TEXT_FROMSTR(str) PyUnicode_FromString(str) +# define TEXT_FROMSTRLEN(str, len) PyUnicode_FromStringAndSize(str, len) +#else # define TEXTOBJ PyStringObject # define TEXT_TYPE PyString_Type # define TEXT_CHECK(obj) PyString_Check(obj) @@ -179,6 +273,7 @@ PRIVATE_SYMBOLS; # define TEXT_DONEWRITE(obj, sz) do { Py_SIZE(obj) = (sz); } while (0) # define TEXT_FROMSTR(str) PyString_FromString(str) # define TEXT_FROMSTRLEN(str, len) PyString_FromStringAndSize(str, len) +#endif /*----- Utilities for returning values and exceptions ---------------------*/ @@ -556,6 +651,13 @@ typedef struct gmap_pyobj { #define GMAP_NAMETHDECL(func, doc) \ extern PyObject *gmapmeth_##func(PyObject *); +#ifdef PY3 +# define GMAP_DOROMETHODS(METH, KWMETH, NAMETH) \ + NAMETH(keys, "D.keys() -> LIST") \ + NAMETH(values, "D.values() -> LIST") \ + NAMETH(items, "D.items() -> LIST") \ + KWMETH(get, "D.get(KEY, [default = None]) -> VALUE") +#else # define GMAP_DOROMETHODS(METH, KWMETH, NAMETH) \ METH (has_key, "D.has_key(KEY) -> BOOL") \ NAMETH(keys, "D.keys() -> LIST") \ @@ -565,6 +667,7 @@ typedef struct gmap_pyobj { NAMETH(itervalues, "D.itervalues() -> ITER") \ NAMETH(iteritems, "D.iteritems() -> ITER") \ KWMETH(get, "D.get(KEY, [default = None]) -> VALUE") +#endif #define GMAP_DOMETHODS(METH, KWMETH, NAMETH) \ GMAP_DOROMETHODS(METH, KWMETH, NAMETH) \