+static int get_channels(const struct srd_decoder *d, const char *attr,
+ GSList **pdchl)
+{
+ PyObject *py_channellist, *py_entry;
+ struct srd_channel *pdch;
+ int ret, num_channels, i;
+
+ if (!PyObject_HasAttrString(d->py_dec, attr))
+ /* No channels of this type specified. */
+ return SRD_OK;
+
+ py_channellist = PyObject_GetAttrString(d->py_dec, attr);
+ if (!PyTuple_Check(py_channellist)) {
+ srd_err("Protocol decoder %s %s attribute is not a tuple.",
+ d->name, attr);
+ return SRD_ERR_PYTHON;
+ }
+
+ if ((num_channels = PyTuple_Size(py_channellist)) == 0)
+ /* Empty channellist. */
+ return SRD_OK;
+
+ ret = SRD_OK;
+ for (i = 0; i < num_channels; i++) {
+ py_entry = PyTuple_GetItem(py_channellist, i);
+ if (!PyDict_Check(py_entry)) {
+ srd_err("Protocol decoder %s %s attribute is not "
+ "a list with dict elements.", d->name, attr);
+ ret = SRD_ERR_PYTHON;
+ break;
+ }
+
+ if (!(pdch = g_try_malloc(sizeof(struct srd_channel)))) {
+ srd_err("Failed to g_malloc() struct srd_channel.");
+ ret = SRD_ERR_MALLOC;
+ break;
+ }
+
+ if ((py_dictitem_as_str(py_entry, "id", &pdch->id)) != SRD_OK) {
+ ret = SRD_ERR_PYTHON;
+ break;
+ }
+ if ((py_dictitem_as_str(py_entry, "name", &pdch->name)) != SRD_OK) {
+ ret = SRD_ERR_PYTHON;
+ break;
+ }
+ if ((py_dictitem_as_str(py_entry, "desc", &pdch->desc)) != SRD_OK) {
+ ret = SRD_ERR_PYTHON;
+ break;
+ }
+ pdch->order = i;
+
+ *pdchl = g_slist_append(*pdchl, pdch);
+ }
+
+ Py_DecRef(py_channellist);
+
+ return ret;
+}
+
+static int get_options(struct srd_decoder *d)
+{
+ PyObject *py_opts, *py_opt, *py_val, *py_default, *py_item;
+ Py_ssize_t opt, i;
+ struct srd_decoder_option *o;
+ GVariant *gvar;
+ gint64 lval;
+ double dval;
+ int overflow;
+ char *sval;
+
+ if (!PyObject_HasAttrString(d->py_dec, "options"))
+ /* No options, that's fine. */
+ return SRD_OK;
+
+ /* If present, options must be a tuple. */
+ py_opts = PyObject_GetAttrString(d->py_dec, "options");
+ if (!PyTuple_Check(py_opts)) {
+ srd_err("Protocol decoder %s: options attribute is not "
+ "a tuple.", d->id);
+ return SRD_ERR_PYTHON;
+ }
+
+ for (opt = 0; opt < PyTuple_Size(py_opts); opt++) {
+ py_opt = PyTuple_GetItem(py_opts, opt);
+ if (!PyDict_Check(py_opt)) {
+ srd_err("Protocol decoder %s options: each option "
+ "must consist of a dictionary.", d->name);
+ return SRD_ERR_PYTHON;
+ }
+ if (!(py_val = PyDict_GetItemString(py_opt, "id"))) {
+ srd_err("Protocol decoder %s option %d has no "
+ "id.", d->name);
+ return SRD_ERR_PYTHON;
+ }
+ o = g_malloc0(sizeof(struct srd_decoder_option));
+ py_str_as_str(py_val, &o->id);
+
+ if ((py_val = PyDict_GetItemString(py_opt, "desc")))
+ py_str_as_str(py_val, &o->desc);
+
+ if ((py_default = PyDict_GetItemString(py_opt, "default"))) {
+ if (PyUnicode_Check(py_default)) {
+ /* UTF-8 string */
+ py_str_as_str(py_default, &sval);
+ o->def = g_variant_new_string(sval);
+ g_free(sval);
+ } else if (PyLong_Check(py_default)) {
+ /* Long */
+ lval = PyLong_AsLongAndOverflow(py_default, &overflow);
+ if (overflow) {
+ /* Value is < LONG_MIN or > LONG_MAX */
+ PyErr_Clear();
+ srd_err("Protocol decoder %s option 'default' has "
+ "invalid default value.", d->name);
+ return SRD_ERR_PYTHON;
+ }
+ o->def = g_variant_new_int64(lval);
+ } else if (PyFloat_Check(py_default)) {
+ /* Float */
+ if ((dval = PyFloat_AsDouble(py_default)) == -1.0) {
+ PyErr_Clear();
+ srd_err("Protocol decoder %s option 'default' has "
+ "invalid default value.", d->name);
+ return SRD_ERR_PYTHON;
+ }
+ o->def = g_variant_new_double(dval);
+ } else {
+ srd_err("Protocol decoder %s option 'default' has "
+ "value of unsupported type '%s'.", d->name,
+ Py_TYPE(py_default)->tp_name);
+ return SRD_ERR_PYTHON;
+ }
+ g_variant_ref_sink(o->def);
+ }
+
+ if ((py_val = PyDict_GetItemString(py_opt, "values"))) {
+ /* A default is required if a list of values is
+ * given, since it's used to verify their type. */
+ if (!o->def) {
+ srd_err("No default for option '%s'", o->id);
+ return SRD_ERR_PYTHON;
+ }
+ if (!PyTuple_Check(py_val)) {
+ srd_err("Option '%s' values should be a tuple.", o->id);
+ return SRD_ERR_PYTHON;
+ }
+ for (i = 0; i < PyTuple_Size(py_val); i++) {
+ py_item = PyTuple_GetItem(py_val, i);
+ if (Py_TYPE(py_default) != Py_TYPE(py_item)) {
+ srd_err("All values for option '%s' must be "
+ "of the same type as the default.",
+ o->id);
+ return SRD_ERR_PYTHON;
+ }
+ if (PyUnicode_Check(py_item)) {
+ /* UTF-8 string */
+ py_str_as_str(py_item, &sval);
+ gvar = g_variant_new_string(sval);
+ g_variant_ref_sink(gvar);
+ g_free(sval);
+ o->values = g_slist_append(o->values, gvar);
+ } else if (PyLong_Check(py_item)) {
+ /* Long */
+ lval = PyLong_AsLongAndOverflow(py_item, &overflow);
+ if (overflow) {
+ /* Value is < LONG_MIN or > LONG_MAX */
+ PyErr_Clear();
+ srd_err("Protocol decoder %s option 'values' "
+ "has invalid value.", d->name);
+ return SRD_ERR_PYTHON;
+ }
+ gvar = g_variant_new_int64(lval);
+ g_variant_ref_sink(gvar);
+ o->values = g_slist_append(o->values, gvar);
+ } else if (PyFloat_Check(py_item)) {
+ /* Float */
+ if ((dval = PyFloat_AsDouble(py_item)) == -1.0) {
+ PyErr_Clear();
+ srd_err("Protocol decoder %s option 'default' has "
+ "invalid default value.", d->name);
+ return SRD_ERR_PYTHON;
+ }
+ gvar = g_variant_new_double(dval);
+ g_variant_ref_sink(gvar);
+ o->values = g_slist_append(o->values, gvar);
+ }
+ }
+ }
+ d->options = g_slist_append(d->options, o);
+ }
+
+ return SRD_OK;
+}