+ for (opt = PyTuple_Size(py_opts) - 1; opt >= 0; opt--) {
+ py_opt = PyTuple_GetItem(py_opts, opt);
+ if (!py_opt)
+ goto except_out;
+
+ if (!PyDict_Check(py_opt)) {
+ srd_err("Protocol decoder %s options: each option "
+ "must consist of a dictionary.", d->name);
+ goto err_out;
+ }
+
+ o = g_malloc0(sizeof(struct srd_decoder_option));
+ /* Add to list right away so it doesn't get lost. */
+ options = g_slist_prepend(options, o);
+
+ py_str = PyDict_GetItemString(py_opt, "id");
+ if (!py_str) {
+ srd_err("Protocol decoder %s option %zd has no id.",
+ d->name, opt);
+ goto err_out;
+ }
+ if (py_str_as_str(py_str, &o->id) != SRD_OK)
+ goto err_out;
+
+ py_str = PyDict_GetItemString(py_opt, "desc");
+ if (py_str) {
+ if (py_str_as_str(py_str, &o->desc) != SRD_OK)
+ goto err_out;
+ }
+
+ py_default = PyDict_GetItemString(py_opt, "default");
+ if (py_default) {
+ gvar = py_obj_to_variant(py_default);
+ if (!gvar) {
+ srd_err("Protocol decoder %s option 'default' has "
+ "invalid default value.", d->name);
+ goto err_out;
+ }
+ o->def = g_variant_ref_sink(gvar);
+ }
+
+ py_values = PyDict_GetItemString(py_opt, "values");
+ if (py_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);
+ goto err_out;
+ }
+ if (!PyTuple_Check(py_values)) {
+ srd_err("Option '%s' values should be a tuple.", o->id);
+ goto err_out;
+ }
+
+ for (i = PyTuple_Size(py_values) - 1; i >= 0; i--) {
+ py_item = PyTuple_GetItem(py_values, i);
+ if (!py_item)
+ goto except_out;
+
+ 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);
+ goto err_out;
+ }
+ gvar = py_obj_to_variant(py_item);
+ if (!gvar) {
+ srd_err("Protocol decoder %s option 'values' "
+ "contains invalid value.", d->name);
+ goto err_out;
+ }
+ o->values = g_slist_prepend(o->values,
+ g_variant_ref_sink(gvar));
+ }
+ }
+ }
+ d->options = options;
+ Py_DECREF(py_opts);
+
+ return SRD_OK;
+
+except_out:
+ srd_exception_catch("Failed to get %s decoder options", d->name);
+err_out:
+ g_slist_free_full(options, &decoder_option_free);
+ Py_XDECREF(py_opts);
+
+ return SRD_ERR_PYTHON;
+}
+
+/* Convert annotation class attribute to GSList of char **.
+ */
+static int get_annotations(struct srd_decoder *dec)
+{
+ PyObject *py_annlist, *py_ann;
+ GSList *annotations;
+ char **annpair;
+ ssize_t i;
+
+ if (!PyObject_HasAttrString(dec->py_dec, "annotations"))
+ return SRD_OK;
+
+ annotations = NULL;
+
+ py_annlist = PyObject_GetAttrString(dec->py_dec, "annotations");
+ if (!py_annlist)
+ goto except_out;
+
+ if (!PyTuple_Check(py_annlist)) {
+ srd_err("Protocol decoder %s annotations should "
+ "be a tuple.", dec->name);