]> sigrok.org Git - libsigrokdecode.git/blobdiff - decoder.c
Build: Reduce autogen.sh to trivial stub
[libsigrokdecode.git] / decoder.c
index a44a86a094ddfc6fa8b615aa3724e3b404e1bd13..a5341b3651daedf5e1a349f8d5b27c6d5820267b 100644 (file)
--- a/decoder.c
+++ b/decoder.c
@@ -19,8 +19,8 @@
  */
 
 #include "config.h"
-#include "libsigrokdecode.h" /* First, so we avoid a _POSIX_C_SOURCE warning. */
-#include "libsigrokdecode-internal.h"
+#include "libsigrokdecode-internal.h" /* First, so we avoid a _POSIX_C_SOURCE warning. */
+#include "libsigrokdecode.h"
 #include <glib.h>
 
 /**
 static GSList *pd_list = NULL;
 
 /* srd.c */
-extern GSList *searchpaths;
+extern SRD_PRIV GSList *searchpaths;
 
 /* session.c */
-extern GSList *sessions;
-extern int max_session_id;
+extern SRD_PRIV GSList *sessions;
+extern SRD_PRIV int max_session_id;
 
 /* module_sigrokdecode.c */
 extern SRD_PRIV PyObject *mod_sigrokdecode;
@@ -66,7 +66,7 @@ static gboolean srd_check_init(void)
 /**
  * Returns the list of supported/loaded protocol decoders.
  *
- * This is a GSList containing the names of the decoders as strings.
+ * This is a GSList of pointers to struct srd_decoder items.
  *
  * @return List of decoders, NULL if none are supported or loaded.
  *
@@ -132,11 +132,7 @@ static int get_channels(const struct srd_decoder *d, const char *attr,
                        break;
                }
 
-               if (!(pdch = g_try_malloc(sizeof(struct srd_channel)))) {
-                       srd_err("Failed to g_malloc() struct srd_channel.");
-                       ret = SRD_ERR_MALLOC;
-                       break;
-               }
+               pdch = g_malloc(sizeof(struct srd_channel));
 
                if ((py_dictitem_as_str(py_entry, "id", &pdch->id)) != SRD_OK) {
                        ret = SRD_ERR_PYTHON;
@@ -331,11 +327,7 @@ SRD_API int srd_decoder_load(const char *module_name)
 
        py_basedec = py_method = py_attr = NULL;
 
-       if (!(d = g_try_malloc0(sizeof(struct srd_decoder)))) {
-               srd_dbg("Failed to g_malloc() struct srd_decoder.");
-               ret = SRD_ERR_MALLOC;
-               goto err_out;
-       }
+       d = g_malloc0(sizeof(struct srd_decoder));
 
        ret = SRD_ERR_PYTHON;
 
@@ -366,6 +358,17 @@ SRD_API int srd_decoder_load(const char *module_name)
        }
        Py_CLEAR(py_basedec);
 
+       /*
+        * Check that this decoder has the correct PD API version.
+        * PDs of different API versions are incompatible and cannot work.
+        */
+       py_long = PyObject_GetAttrString(d->py_dec, "api_version");
+       if (PyLong_AsLong(py_long) != 2) {
+               srd_err("Only PDs of API version 2 are supported.");
+               goto err_out;
+       }
+       Py_CLEAR(py_long);
+
        /* Check for a proper start() method. */
        if (!PyObject_HasAttrString(d->py_dec, "start")) {
                srd_err("Protocol decoder %s has no start() method Decoder "
@@ -676,14 +679,98 @@ SRD_API int srd_decoder_unload(struct srd_decoder *dec)
        return SRD_OK;
 }
 
+static void srd_decoder_load_all_zip_path(char *path)
+{
+       PyObject *zipimport_mod, *zipimporter_class, *zipimporter;
+       PyObject *prefix_obj, *files, *key, *value, *set, *modname;
+       Py_ssize_t pos = 0;
+       char *prefix;
+       size_t prefix_len;
+
+       set = files = prefix_obj = zipimporter = zipimporter_class = NULL;
+
+       zipimport_mod = PyImport_ImportModule("zipimport");
+       if (zipimport_mod == NULL)
+               goto err_out;
+
+       zipimporter_class = PyObject_GetAttrString(zipimport_mod, "zipimporter");
+       if (zipimporter_class == NULL)
+               goto err_out;
+
+       zipimporter = PyObject_CallFunction(zipimporter_class, "s", path);
+       if (zipimporter == NULL)
+               goto err_out;
+
+       prefix_obj = PyObject_GetAttrString(zipimporter, "prefix");
+       if (prefix_obj == NULL)
+               goto err_out;
+
+       files = PyObject_GetAttrString(zipimporter, "_files");
+       if (files == NULL)
+               goto err_out;
+
+       set = PySet_New(NULL);
+       if (set == NULL)
+               goto err_out;
+
+       if (py_str_as_str(prefix_obj, &prefix) != SRD_OK)
+               goto err_out;
+
+       prefix_len = strlen(prefix);
+
+       while (PyDict_Next(files, &pos, &key, &value)) {
+               char *path, *slash;
+               if (py_str_as_str(key, &path) == SRD_OK) {
+                       if (strlen(path) > prefix_len &&
+                           !memcmp(path, prefix, prefix_len) &&
+                           (slash = strchr(path+prefix_len, '/'))) {
+                               modname =
+                                 PyUnicode_FromStringAndSize(path+prefix_len,
+                                                             slash-(path+prefix_len));
+                               if (modname == NULL) {
+                                       PyErr_Clear();
+                               } else {
+                                       PySet_Add(set, modname);
+                                       Py_XDECREF(modname);
+                               }
+                       }
+                       free(path);
+               }
+       }
+
+       free(prefix);
+
+       while ((modname = PySet_Pop(set))) {
+               char *modname_str;
+               if (py_str_as_str(modname, &modname_str) == SRD_OK) {
+                       /* The directory name is the module name (e.g. "i2c"). */
+                       srd_decoder_load(modname_str);
+                       free(modname_str);
+               }
+               Py_XDECREF(modname);
+       }
+
+err_out:
+       Py_XDECREF(set);
+       Py_XDECREF(files);
+       Py_XDECREF(prefix_obj);
+       Py_XDECREF(zipimporter);
+       Py_XDECREF(zipimporter_class);
+       Py_XDECREF(zipimport_mod);
+       PyErr_Clear();
+}
+
 static void srd_decoder_load_all_path(char *path)
 {
        GDir *dir;
        const gchar *direntry;
 
-       if (!(dir = g_dir_open(path, 0, NULL)))
+       if (!(dir = g_dir_open(path, 0, NULL))) {
                /* Not really fatal */
+               /* Try zipimport method too */
+               srd_decoder_load_all_zip_path(path);
                return;
+       }
 
        /* This ignores errors returned by srd_decoder_load(). That
         * function will have logged the cause, but in any case we