+static int get_probes(const struct srd_decoder *d, const char *attr,
+ GSList **pl)
+{
+ PyObject *py_probelist, *py_entry;
+ struct srd_probe *p;
+ int ret, num_probes, i;
+
+ if (!PyObject_HasAttrString(d->py_dec, attr))
+ /* No probes of this type specified. */
+ return SRD_OK;
+
+ ret = SRD_ERR_PYTHON;
+ py_probelist = py_entry = NULL;
+
+ py_probelist = PyObject_GetAttrString(d->py_dec, attr);
+ if (!PyList_Check(py_probelist)) {
+ srd_err("Protocol decoder %s %s attribute is not "
+ "a list.", d->name, attr);
+ goto err_out;
+ }
+
+ num_probes = PyList_Size(py_probelist);
+ if (num_probes == 0)
+ /* Empty probelist. */
+ return SRD_OK;
+
+ for (i = 0; i < num_probes; i++) {
+ py_entry = PyList_GetItem(py_probelist, i);
+ if (!PyDict_Check(py_entry)) {
+ srd_err("Protocol decoder %s %s attribute is not "
+ "a list with dict elements.", d->name, attr);
+ goto err_out;
+ }
+
+ if (!(p = g_try_malloc(sizeof(struct srd_probe)))) {
+ srd_err("Failed to g_malloc() struct srd_probe.");
+ ret = SRD_ERR_MALLOC;
+ goto err_out;
+ }
+
+ if ((py_dictitem_as_str(py_entry, "id", &p->id)) != SRD_OK)
+ goto err_out;
+ if ((py_dictitem_as_str(py_entry, "name", &p->name)) != SRD_OK)
+ goto err_out;
+ if ((py_dictitem_as_str(py_entry, "desc", &p->desc)) != SRD_OK)
+ goto err_out;
+ p->order = i;
+
+ *pl = g_slist_append(*pl, p);
+ }
+ ret = SRD_OK;
+
+err_out:
+ Py_DecRef(py_entry);
+ Py_DecRef(py_probelist);
+
+ return ret;
+}
+
+static int get_options(struct srd_decoder *d)
+{
+ PyObject *py_opts, *py_keys, *py_values, *py_val, *py_desc, *py_default;
+ Py_ssize_t i;
+ struct srd_decoder_option *o;
+ gint64 def_long;
+ int num_keys, overflow, ret;
+ char *key, *def_str;
+
+ ret = SRD_ERR_PYTHON;
+ key = NULL;
+
+ if (!PyObject_HasAttrString(d->py_dec, "options"))
+ /* That's fine. */
+ return SRD_OK;
+
+ /* If present, options must be a dictionary. */
+ py_opts = PyObject_GetAttrString(d->py_dec, "options");
+ if (!PyDict_Check(py_opts)) {
+ srd_err("Protocol decoder %s options attribute is not "
+ "a dictionary.", d->name);
+ goto err_out;
+ }
+
+ py_keys = PyDict_Keys(py_opts);
+ py_values = PyDict_Values(py_opts);
+ num_keys = PyList_Size(py_keys);
+ for (i = 0; i < num_keys; i++) {
+ py_str_as_str(PyList_GetItem(py_keys, i), &key);
+ srd_dbg("option '%s'", key);
+ py_val = PyList_GetItem(py_values, i);
+ if (!PyList_Check(py_val) || PyList_Size(py_val) != 2) {
+ srd_err("Protocol decoder %s option '%s' value must be "
+ "a list with two elements.", d->name, key);
+ goto err_out;
+ }
+ py_desc = PyList_GetItem(py_val, 0);
+ if (!PyUnicode_Check(py_desc)) {
+ srd_err("Protocol decoder %s option '%s' has no "
+ "description.", d->name, key);
+ goto err_out;
+ }
+ py_default = PyList_GetItem(py_val, 1);
+ if (!PyUnicode_Check(py_default) && !PyLong_Check(py_default)) {
+ srd_err("Protocol decoder %s option '%s' has default "
+ "of unsupported type '%s'.", d->name, key,
+ Py_TYPE(py_default)->tp_name);
+ goto err_out;
+ }
+ if (!(o = g_try_malloc(sizeof(struct srd_decoder_option)))) {
+ srd_err("option malloc failed");
+ goto err_out;
+ }
+ o->id = g_strdup(key);
+ py_str_as_str(py_desc, &o->desc);
+ if (PyUnicode_Check(py_default)) {
+ /* UTF-8 string */
+ py_str_as_str(py_default, &def_str);
+ o->def = g_variant_new_string(def_str);
+ g_free(def_str);
+ } else {
+ /* Long */
+ def_long = PyLong_AsLongAndOverflow(py_default, &overflow);
+ if (overflow) {
+ /* Value is < LONG_MIN or > LONG_MAX */
+ PyErr_Clear();
+ srd_err("Protocol decoder %s option '%s' has "
+ "invalid default value.", d->name, key);
+ goto err_out;
+ }
+ o->def = g_variant_new_int64(def_long);
+ }
+ g_variant_ref_sink(o->def);
+ d->options = g_slist_append(d->options, o);
+ g_free(key);
+ key = NULL;
+ }
+ Py_DecRef(py_keys);
+ Py_DecRef(py_values);
+
+ ret = SRD_OK;
+
+err_out:
+ Py_XDECREF(py_opts);
+ g_free(key);
+
+ return ret;
+}