summaryrefslogtreecommitdiffstats
path: root/python/enum.c
diff options
context:
space:
mode:
Diffstat (limited to 'python/enum.c')
-rw-r--r--python/enum.c259
1 files changed, 259 insertions, 0 deletions
diff --git a/python/enum.c b/python/enum.c
new file mode 100644
index 0000000..b57a880
--- /dev/null
+++ b/python/enum.c
@@ -0,0 +1,259 @@
+/*------------------------------------------------------------------------
+ * Copyright 2009-2010 (c) Jeff Brown <spadix@users.sourceforge.net>
+ *
+ * This file is part of the ZBar Bar Code Reader.
+ *
+ * The ZBar Bar Code Reader is free software; you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * The ZBar Bar Code Reader 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 Lesser Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser Public License
+ * along with the ZBar Bar Code Reader; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ *
+ * http://sourceforge.net/projects/zbar
+ *------------------------------------------------------------------------*/
+
+#include "zbarmodule.h"
+
+static char enumitem_doc[] =
+ PyDoc_STR("simple enumeration item.\n"
+ "\n"
+ "associates an int value with a name for printing.");
+
+static zbarEnumItem *enumitem_new(PyTypeObject *type, PyObject *args,
+ PyObject *kwds)
+{
+ int val = 0;
+ PyObject *name = NULL;
+ static char *kwlist[] = { "value", "name", NULL };
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "iS", kwlist, &val, &name))
+ return (NULL);
+
+ zbarEnumItem *self = (zbarEnumItem *)type->tp_alloc(type, 0);
+ if (!self)
+ return (NULL);
+
+#if PY_MAJOR_VERSION >= 3
+ PyLongObject *longval = (PyLongObject *)PyLong_FromLong(val);
+ if (!longval) {
+ Py_DECREF(self);
+ return (NULL);
+ }
+
+ /* we assume the "fast path" for a single-digit ints (see longobject.c) */
+ /* this also holds if we get a small_int preallocated long */
+#if PY_VERSION_HEX >= 0x030900A4
+ Py_SET_SIZE(&self->val, Py_SIZE(longval));
+#else
+ Py_SIZE(&self->val) = Py_SIZE(longval);
+#endif
+#if PY_VERSION_HEX >= 0x030c0000
+ self->val.long_value.ob_digit[0] = longval->long_value.ob_digit[0];
+#else
+ self->val.ob_digit[0] = longval->ob_digit[0];
+#endif
+ Py_DECREF(longval);
+#else
+ self->val.ob_ival = val;
+#endif
+ self->name = name;
+ return (self);
+}
+
+static void enumitem_dealloc(zbarEnumItem *self)
+{
+ Py_CLEAR(self->name);
+ ((PyObject *)self)->ob_type->tp_free((PyObject *)self);
+}
+
+static PyObject *enumitem_str(zbarEnumItem *self)
+{
+ Py_INCREF(self->name);
+ return (self->name);
+}
+
+#if PY_MAJOR_VERSION < 3
+/* tp_print was dropped on Python 3.9 */
+static int enumitem_print(zbarEnumItem *self, FILE *fp, int flags)
+{
+ return (self->name->ob_type->tp_print(self->name, fp, flags));
+}
+#endif
+
+static PyObject *enumitem_repr(zbarEnumItem *self)
+{
+ PyObject *name = PyObject_Repr(self->name);
+ if (!name)
+ return (NULL);
+#if PY_MAJOR_VERSION >= 3
+ PyObject *repr = PyUnicode_FromFormat("%s(%ld, %U)",
+ ((PyObject *)self)->ob_type->tp_name,
+ PyLong_AsLong((PyObject *)self),
+ name);
+#else
+ char *namestr = PyString_AsString(name);
+ PyObject *repr = PyString_FromFormat("%s(%ld, %s)",
+ ((PyObject *)self)->ob_type->tp_name,
+ self->val.ob_ival, namestr);
+#endif
+ Py_DECREF(name);
+ return ((PyObject *)repr);
+}
+
+PyTypeObject zbarEnumItem_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0).tp_name = "zbar.EnumItem",
+ .tp_doc = enumitem_doc,
+ .tp_basicsize = sizeof(zbarEnumItem),
+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+ .tp_new = (newfunc)enumitem_new,
+ .tp_dealloc = (destructor)enumitem_dealloc,
+ .tp_str = (reprfunc)enumitem_str,
+#if PY_MAJOR_VERSION < 3
+ .tp_print = (printfunc)enumitem_print,
+#endif
+ .tp_repr = (reprfunc)enumitem_repr,
+};
+
+zbarEnumItem *zbarEnumItem_New(PyObject *byname, PyObject *byvalue, int val,
+ const char *name)
+{
+ zbarEnumItem *self = PyObject_New(zbarEnumItem, &zbarEnumItem_Type);
+ if (!self)
+ return (NULL);
+#if PY_MAJOR_VERSION >= 3
+ PyLongObject *longval = (PyLongObject *)PyLong_FromLong(val);
+ if (!longval) {
+ Py_DECREF(self);
+ return (NULL);
+ }
+
+ /* we assume the "fast path" for a single-digit ints (see longobject.c) */
+ /* this also holds if we get a small_int preallocated long */
+#if PY_VERSION_HEX >= 0x030900A4
+ Py_SET_SIZE(&self->val, Py_SIZE(longval));
+#else
+ Py_SIZE(&self->val) = Py_SIZE(longval);
+#endif
+#if PY_VERSION_HEX >= 0x030c0000
+ self->val.long_value.ob_digit[0] = longval->long_value.ob_digit[0];
+#else
+ self->val.ob_digit[0] = longval->ob_digit[0];
+#endif
+ Py_DECREF(longval);
+
+ self->name = PyUnicode_FromString(name);
+#else
+ self->val.ob_ival = val;
+ self->name = PyString_FromString(name);
+#endif
+ if (!self->name ||
+ (byname && PyDict_SetItem(byname, self->name, (PyObject *)self)) ||
+ (byvalue &&
+ PyDict_SetItem(byvalue, (PyObject *)self, (PyObject *)self))) {
+ Py_DECREF((PyObject *)self);
+ return (NULL);
+ }
+ return (self);
+}
+
+static char enum_doc[] = PyDoc_STR("enumeration container for EnumItems.\n"
+ "\n"
+ "exposes items as read-only attributes");
+
+/* FIXME add iteration */
+
+static int enum_traverse(zbarEnum *self, visitproc visit, void *arg)
+{
+ Py_VISIT(self->byname);
+ Py_VISIT(self->byvalue);
+ return (0);
+}
+
+static int enum_clear(zbarEnum *self)
+{
+ Py_CLEAR(self->byname);
+ Py_CLEAR(self->byvalue);
+ return (0);
+}
+
+static void enum_dealloc(zbarEnum *self)
+{
+ enum_clear(self);
+ ((PyObject *)self)->ob_type->tp_free((PyObject *)self);
+}
+
+PyTypeObject zbarEnum_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0).tp_name = "zbar.Enum",
+
+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,
+
+ .tp_doc = enum_doc,
+ .tp_basicsize = sizeof(zbarEnum),
+ .tp_dictoffset = offsetof(zbarEnum, byname),
+ .tp_traverse = (traverseproc)enum_traverse,
+ .tp_clear = (inquiry)enum_clear,
+ .tp_dealloc = (destructor)enum_dealloc,
+};
+
+zbarEnum *zbarEnum_New()
+{
+ zbarEnum *self = PyObject_GC_New(zbarEnum, &zbarEnum_Type);
+ if (!self)
+ return (NULL);
+ self->byname = PyDict_New();
+ self->byvalue = PyDict_New();
+ if (!self->byname || !self->byvalue) {
+ Py_DECREF(self);
+ return (NULL);
+ }
+ return (self);
+}
+
+int zbarEnum_Add(zbarEnum *self, int val, const char *name)
+{
+ zbarEnumItem *item;
+ item = zbarEnumItem_New(self->byname, self->byvalue, val, name);
+ if (!item)
+ return (-1);
+ return (0);
+}
+
+zbarEnumItem *zbarEnum_LookupValue(zbarEnum *self, int val)
+{
+#if PY_MAJOR_VERSION >= 3
+ PyObject *key = PyLong_FromLong(val);
+#else
+ PyObject *key = PyInt_FromLong(val);
+#endif
+ zbarEnumItem *e = (zbarEnumItem *)PyDict_GetItem(self->byvalue, key);
+ if (!e)
+ return ((zbarEnumItem *)key);
+ Py_INCREF((PyObject *)e);
+ Py_DECREF(key);
+ return (e);
+}
+
+PyObject *zbarEnum_SetFromMask(zbarEnum *self, unsigned int mask)
+{
+ PyObject *result = PySet_New(NULL);
+ PyObject *key, *item;
+ Py_ssize_t i = 0;
+ while (PyDict_Next(self->byvalue, &i, &key, &item)) {
+#if PY_MAJOR_VERSION >= 3
+ unsigned long val = (unsigned long)PyLong_AsLong(item);
+#else
+ int val = PyInt_AsLong(item);
+#endif
+ if (val < sizeof(mask) * 8 && ((mask >> val) & 1))
+ PySet_Add(result, item);
+ }
+ return (result);
+}