* 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));
+
+ env = g_getenv("SIGROK_FIRMWARE_PATH");
+ if (env) {
+ char **dir_list, **dir_iter, *dir_item;
+ dir_list = g_strsplit(env, G_SEARCHPATH_SEPARATOR_S, 0);
+ for (dir_iter = dir_list; *dir_iter; dir_iter++) {
+ dir_item = *dir_iter;
+ if (!dir_item || !*dir_item)
+ continue;
+ l = g_slist_append(l, g_strdup(dir_item));
+ }
+ g_strfreev(dir_list);
+ }
+ }
+
+ 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.
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)
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;
}
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;
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;
}
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;
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;
}
*
* @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);
* @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
*/
struct sr_resource res;
void *buf;
size_t res_size;
- ssize_t n_read;
+ gssize n_read;
if (sr_resource_open(ctx, &res, type, name) != SR_OK)
return NULL;
*size = res_size;
return buf;
}
-
-/** @} */