zbar-windows/python/enum.c

244 lines
7.3 KiB
C

/*------------------------------------------------------------------------
* 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 */
Py_SIZE(&self->val) = Py_SIZE(longval);
self->val.ob_digit[0] = longval->ob_digit[0];
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 */
Py_SIZE(&self->val) = Py_SIZE(longval);
self->val.ob_digit[0] = longval->ob_digit[0];
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);
}