use GVariant for passing decoder options and probes
authorBert Vermeulen <bert@biot.com>
Tue, 19 Mar 2013 00:47:53 +0000 (01:47 +0100)
committerBert Vermeulen <bert@biot.com>
Tue, 19 Mar 2013 00:58:22 +0000 (01:58 +0100)
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.

controller.c
decoder.c
sigrokdecode.h.in

index cabca3b5edbf5a6acb57243d684291013142d7aa..3c3f4094c73da445e2864d320a6d79630ffb8358 100644 (file)
@@ -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;
                        }
index 3d20b26b115770daca4eb1a14172c19662a4f377..f606bb7aefc56dce6ace36effa4ab712a52a9ecb 100644 (file)
--- 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);
index a7221faa7bdb3071ff0f63e779ec39eb94fd91a4..3de1271eab3f1679cfcb038a44a8b6f5fb046df0 100644 (file)
@@ -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;