From: Bert Vermeulen Date: Tue, 19 Mar 2013 00:47:53 +0000 (+0100) Subject: use GVariant for passing decoder options and probes X-Git-Tag: libsigrokdecode-0.2.0~14 X-Git-Url: https://sigrok.org/gitaction?a=commitdiff_plain;h=2f395bff8f096ef738140913e2d01ff0a8c07002;p=libsigrokdecode.git use GVariant for passing decoder options and probes Decoder options are now exposed in struct srd_decoder, via a GSList of the new struct srd_decoder_option. The 'def' field represents the default value as set in the decoder, converted to GVariant. This allows a library user to determine the type as well as default value. --- diff --git a/controller.c b/controller.c index cabca3b..3c3f409 100644 --- a/controller.c +++ b/controller.c @@ -291,9 +291,12 @@ SRD_API int srd_inst_option_set(struct srd_decoder_inst *di, PyObject *py_dec_options, *py_dec_optkeys, *py_di_options, *py_optval; PyObject *py_optlist, *py_classval; Py_UNICODE *py_ustr; + GVariant *value; unsigned long long int val_ull; + gint64 val_int; int num_optkeys, ret, size, i; - char *key, *value; + const char *val_str; + char *dbg, *key; if (!PyObject_HasAttrString(di->decoder->py_dec, "options")) { /* Decoder has no options. */ @@ -332,20 +335,32 @@ SRD_API int srd_inst_option_set(struct srd_decoder_inst *di, } if ((value = g_hash_table_lookup(options, key))) { + dbg = g_variant_print(value, TRUE); + srd_dbg("got option '%s' = %s", key, dbg); + g_free(dbg); /* An override for this option was provided. */ if (PyUnicode_Check(py_classval)) { - if (!(py_optval = PyUnicode_FromString(value))) { + if (!g_variant_is_of_type(value, G_VARIANT_TYPE_STRING)) { + srd_err("Option '%s' requires a string value.", key); + goto err_out; + } + val_str = g_variant_get_string(value, NULL); + if (!(py_optval = PyUnicode_FromString(val_str))) { /* Some UTF-8 encoding error. */ PyErr_Clear(); + srd_err("Option '%s' requires a UTF-8 string value.", key); goto err_out; } } else if (PyLong_Check(py_classval)) { - if (!(py_optval = PyLong_FromString(value, NULL, 0))) { + if (!g_variant_is_of_type(value, G_VARIANT_TYPE_INT64)) { + srd_err("Option '%s' requires an integer value.", key); + goto err_out; + } + val_int = g_variant_get_int64(value); + if (!(py_optval = PyLong_FromLong(val_int))) { /* ValueError Exception */ PyErr_Clear(); - srd_err("Option %s has invalid value " - "%s: expected integer.", - key, value); + srd_err("Option '%s' has invalid integer value.", key); goto err_out; } } @@ -416,11 +431,12 @@ static gint compare_probe_id(const struct srd_probe *a, const char *probe_id) SRD_API int srd_inst_probe_set_all(struct srd_decoder_inst *di, GHashTable *new_probes) { + GVariant *probe_val; GList *l; GSList *sl; struct srd_probe *p; int *new_probemap, new_probenum; - char *probe_id, *probenum_str; + char *probe_id; int i, num_required_probes; srd_dbg("set probes called for instance %s with list of %d probes", @@ -453,22 +469,22 @@ SRD_API int srd_inst_probe_set_all(struct srd_decoder_inst *di, for (l = g_hash_table_get_keys(new_probes); l; l = l->next) { probe_id = l->data; - probenum_str = g_hash_table_lookup(new_probes, probe_id); - if (!probenum_str) { + probe_val= g_hash_table_lookup(new_probes, probe_id); + if (!g_variant_is_of_type(probe_val, G_VARIANT_TYPE_INT32)) { /* Probe name was specified without a value. */ srd_err("No probe number was specified for %s.", - probe_id); + probe_id); g_free(new_probemap); return SRD_ERR_ARG; } - new_probenum = strtol(probenum_str, NULL, 10); + new_probenum = g_variant_get_int32(probe_val); if (!(sl = g_slist_find_custom(di->decoder->probes, probe_id, (GCompareFunc)compare_probe_id))) { /* Fall back on optional probes. */ if (!(sl = g_slist_find_custom(di->decoder->opt_probes, probe_id, (GCompareFunc) compare_probe_id))) { srd_err("Protocol decoder %s has no probe " - "'%s'.", di->decoder->name, probe_id); + "'%s'.", di->decoder->name, probe_id); g_free(new_probemap); return SRD_ERR_ARG; } diff --git a/decoder.c b/decoder.c index 3d20b26..f606bb7 100644 --- a/decoder.c +++ b/decoder.c @@ -139,6 +139,93 @@ err_out: 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); + } + Py_DecRef(py_keys); + Py_DecRef(py_values); + + ret = SRD_OK; + +err_out: + Py_XDECREF(py_opts); + g_free(key); + + return ret; +} + /** * Load a protocol decoder module into the embedded Python interpreter. * @@ -222,17 +309,8 @@ SRD_API int srd_decoder_load(const char *module_name) } Py_CLEAR(py_method); - /* If present, options must be a dictionary. */ - if (PyObject_HasAttrString(d->py_dec, "options")) { - py_attr = PyObject_GetAttrString(d->py_dec, "options"); - if (!PyDict_Check(py_attr)) { - srd_err("Protocol decoder %s options attribute is not " - "a dictionary.", d->name); - Py_DecRef(py_attr); - goto err_out; - } - Py_DecRef(py_attr); - } + if (get_options(d) != SRD_OK) + goto err_out; /* Check and import required probes. */ if (get_probes(d, "probes", &d->probes) != SRD_OK) @@ -370,6 +448,9 @@ static void free_probes(GSList *probelist) */ SRD_API int srd_decoder_unload(struct srd_decoder *dec) { + struct srd_decoder_option *o; + GSList *l; + srd_dbg("Unloading protocol decoder '%s'.", dec->name); /* @@ -380,6 +461,15 @@ SRD_API int srd_decoder_unload(struct srd_decoder *dec) */ srd_inst_free_all(NULL); + for (l = dec->options; l; l = l->next) { + o = l->data; + g_free(o->id); + g_free(o->desc); + g_variant_unref(o->def); + g_free(o); + } + g_slist_free(dec->options); + free_probes(dec->probes); free_probes(dec->opt_probes); g_free(dec->id); diff --git a/sigrokdecode.h.in b/sigrokdecode.h.in index a7221fa..3de1271 100644 --- a/sigrokdecode.h.in +++ b/sigrokdecode.h.in @@ -186,6 +186,9 @@ struct srd_decoder { */ GSList *annotations; + /** List of decoder options. */ + GSList *options; + /** Python module. */ PyObject *py_mod; @@ -208,6 +211,12 @@ struct srd_probe { int order; }; +struct srd_decoder_option { + char *id; + char *desc; + GVariant *def; +}; + struct srd_decoder_inst { struct srd_decoder *decoder; PyObject *py_inst;