]> sigrok.org Git - libsigrok.git/blobdiff - src/resource.c
scpi-pps: Support for the EEZ PSU series
[libsigrok.git] / src / resource.c
index bf28169be769f6e6906b844e0a84a240b4812723..a30b4b3f744ee0d154926038e6dfce67dcb029ba 100644 (file)
  * Access to resource files.
  */
 
-/** Retrieve the size of the open stream @a file.
+/**
+ * Get a list of paths where we look for resource (e.g. firmware) files.
+ *
+ * @param res_type The type of resource to get the search paths for.
+ *
+ * @return List of strings that must be freed after use, including the strings.
+ *
+ * @since 0.6.0
+ */
+SR_API GSList *sr_resourcepaths_get(int res_type)
+{
+       const char *subdir = NULL;
+       GSList *l = NULL;
+       const char *env;
+       const char *const *datadirs;
+
+       if (res_type == SR_RESOURCE_FIRMWARE) {
+               subdir = "sigrok-firmware";
+
+               env = g_getenv("SIGROK_FIRMWARE_DIR");
+               if (env)
+                       l = g_slist_append(l, g_strdup(env));
+       }
+
+       l = g_slist_append(l, g_build_filename(g_get_user_data_dir(), subdir, NULL));
+
+#ifdef FIRMWARE_DIR
+       if (res_type == SR_RESOURCE_FIRMWARE) {
+               /*
+                * Scan the hard-coded directory before the system directories to
+                * avoid picking up possibly outdated files from a system install.
+                */
+               l = g_slist_append(l, g_strdup(FIRMWARE_DIR));
+       }
+#endif
+
+       datadirs = g_get_system_data_dirs();
+       while (*datadirs)
+               l = g_slist_append(l, g_build_filename(*datadirs++, subdir, NULL));
+
+       return l;
+}
+
+/**
+ * Retrieve the size of the open stream @a file.
  *
  * This function only works on seekable streams. However, the set of seekable
  * streams is generally congruent with the set of streams that have a size.
@@ -82,7 +126,11 @@ static FILE *try_open_file(const char *datadir, const char *subdir,
        char *filename;
        FILE *file;
 
-       filename = g_build_filename(datadir, subdir, name, NULL);
+       if (subdir)
+               filename = g_build_filename(datadir, subdir, name, NULL);
+       else
+               filename = g_build_filename(datadir, name, NULL);
+
        file = g_fopen(filename, "rb");
 
        if (file)
@@ -98,44 +146,29 @@ static FILE *try_open_file(const char *datadir, const char *subdir,
 static int resource_open_default(struct sr_resource *res,
                const char *name, void *cb_data)
 {
+       GSList *paths, *p = NULL;
        int64_t filesize;
-#ifdef FIRMWARE_DIR
-       const char *builtindir;
-#endif
-       const char *subdir;
-       const char *const *datadirs;
-       FILE *file;
+       FILE *file = NULL;
 
        (void)cb_data;
 
-       switch (res->type) {
-       case SR_RESOURCE_FIRMWARE:
-#ifdef FIRMWARE_DIR
-               builtindir = FIRMWARE_DIR;
-#endif
-               subdir = "sigrok-firmware";
-               break;
-       default:
+       paths = sr_resourcepaths_get(res->type);
+
+       /* Currently, the enum only defines SR_RESOURCE_FIRMWARE. */
+       if (res->type != SR_RESOURCE_FIRMWARE) {
                sr_err("%s: unknown type %d.", __func__, res->type);
                return SR_ERR_ARG;
        }
 
-       file = try_open_file(g_get_user_data_dir(), subdir, name);
-       /*
-        * Scan the hard-coded directory before the system directories to
-        * avoid picking up possibly outdated files from a system install.
-        */
-#ifdef FIRMWARE_DIR
-       if (!file)
-               file = try_open_file(builtindir, "", name);
-#endif
-       if (!file) {
-               datadirs = g_get_system_data_dirs();
-               while (*datadirs && !file)
-                       file = try_open_file(*datadirs++, subdir, name);
+       p = paths;
+       while (p && !file) {
+               file = try_open_file((const char *)(p->data), NULL, name);
+               p = p->next;
        }
+       g_slist_free_full(paths, g_free);
+
        if (!file) {
-               sr_err("Failed to locate '%s'.", name);
+               sr_dbg("Failed to locate '%s'.", name);
                return SR_ERR;
        }
 
@@ -173,7 +206,7 @@ static int resource_close_default(struct sr_resource *res, void *cb_data)
        return SR_OK;
 }
 
-static ssize_t resource_read_default(const struct sr_resource *res,
+static gssize resource_read_default(const struct sr_resource *res,
                void *buf, size_t count, void *cb_data)
 {
        FILE *file;
@@ -186,7 +219,7 @@ static ssize_t resource_read_default(const struct sr_resource *res,
                sr_err("%s: invalid handle.", __func__);
                return SR_ERR_ARG;
        }
-       if (count > SSIZE_MAX) {
+       if (count > G_MAXSSIZE) {
                sr_err("%s: count %zu too large.", __func__, count);
                return SR_ERR_ARG;
        }
@@ -224,15 +257,15 @@ SR_API int sr_resource_set_hooks(struct sr_context *ctx,
                return SR_ERR_ARG;
        }
        if (open_cb && close_cb && read_cb) {
-               ctx->resource_open_cb  = open_cb;
+               ctx->resource_open_cb = open_cb;
                ctx->resource_close_cb = close_cb;
-               ctx->resource_read_cb  = read_cb;
-               ctx->resource_cb_data  = cb_data;
+               ctx->resource_read_cb = read_cb;
+               ctx->resource_cb_data = cb_data;
        } else if (!open_cb && !close_cb && !read_cb) {
-               ctx->resource_open_cb  = &resource_open_default;
+               ctx->resource_open_cb = &resource_open_default;
                ctx->resource_close_cb = &resource_close_default;
-               ctx->resource_read_cb  = &resource_read_default;
-               ctx->resource_cb_data  = ctx;
+               ctx->resource_read_cb = &resource_read_default;
+               ctx->resource_cb_data = ctx;
        } else {
                sr_err("%s: inconsistent callback pointers.", __func__);
                return SR_ERR_ARG;
@@ -266,7 +299,8 @@ SR_PRIV int sr_resource_open(struct sr_context *ctx,
        ret = (*ctx->resource_open_cb)(res, name, ctx->resource_cb_data);
 
        if (ret != SR_OK)
-               sr_err("Failed to open resource '%s'.", name);
+               sr_err("Failed to open resource '%s' (use loglevel 5/spew for"
+                      " details).", name);
 
        return ret;
 }
@@ -309,10 +343,10 @@ SR_PRIV int sr_resource_close(struct sr_context *ctx, struct sr_resource *res)
  *
  * @private
  */
-SR_PRIV ssize_t sr_resource_read(struct sr_context *ctx,
+SR_PRIV gssize sr_resource_read(struct sr_context *ctx,
                const struct sr_resource *res, void *buf, size_t count)
 {
-       ssize_t n_read;
+       gssize n_read;
 
        n_read = (*ctx->resource_read_cb)(res, buf, count,
                        ctx->resource_cb_data);
@@ -332,7 +366,7 @@ SR_PRIV ssize_t sr_resource_read(struct sr_context *ctx,
  * @param max_size Size limit. Error out if the resource is larger than this.
  *
  * @return A buffer containing the resource data, or NULL on failure. Must
- *  be freed by the caller using g_free().
+ *         be freed by the caller using g_free().
  *
  * @private
  */
@@ -341,7 +375,8 @@ SR_PRIV void *sr_resource_load(struct sr_context *ctx,
 {
        struct sr_resource res;
        void *buf;
-       ssize_t n_read;
+       size_t res_size;
+       gssize n_read;
 
        if (sr_resource_open(ctx, &res, type, name) != SR_OK)
                return NULL;
@@ -352,17 +387,19 @@ SR_PRIV void *sr_resource_load(struct sr_context *ctx,
                sr_resource_close(ctx, &res);
                return NULL;
        }
-       buf = g_try_malloc(res.size);
+       res_size = res.size;
+
+       buf = g_try_malloc(res_size);
        if (!buf) {
                sr_err("Failed to allocate buffer for '%s'.", name);
                sr_resource_close(ctx, &res);
                return NULL;
        }
 
-       n_read = sr_resource_read(ctx, &res, buf, res.size);
+       n_read = sr_resource_read(ctx, &res, buf, res_size);
        sr_resource_close(ctx, &res);
 
-       if (n_read < 0 || (size_t)n_read != res.size) {
+       if (n_read < 0 || (size_t)n_read != res_size) {
                if (n_read >= 0)
                        sr_err("Failed to read '%s': premature end of file.",
                                name);
@@ -370,8 +407,6 @@ SR_PRIV void *sr_resource_load(struct sr_context *ctx,
                return NULL;
        }
 
-       *size = res.size;
+       *size = res_size;
        return buf;
 }
-
-/** @} */