Hi all,
Often programs need to use secondary resources such as images, theme,
configuration files and so on. Finding them proves to be a major pain,
particularly when you want it to be relocatable or you want your
development version to take precedence over installed.
Find attached an initial implementation of ecore_resource_pool (could
be eina as well) and ecore_app_resource/ecore_sys_resource that
pre-defines some paths based on ecore_app_args_set().
tst-ecore-resource.c is a test program that plays the role of an
application using command line parameters, then queries system's
"passwd" from category "etc" and then simulates being ecore creating
its own private resource pool (ie: elementary could use to find its
themes).
There are extension ideas such as environment variables, we just need
to figure out what is required and then add them to ecore_app.c
Comments, suggestions?
--
Gustavo Sverzut Barbieri
http://profusion.mobi embedded systems
--------------------------------------
MSN: [email protected]
Skype: gsbarbieri
Mobile: +55 (19) 9225-2202
Index: src/lib/ecore/Ecore.h
===================================================================
--- src/lib/ecore/Ecore.h (revision 52865)
+++ src/lib/ecore/Ecore.h (working copy)
@@ -332,6 +332,32 @@
EAPI void ecore_app_args_get(int *argc, char ***argv);
EAPI void ecore_app_restart(void);
+ EAPI void ecore_app_resource_namespace_set(const char *namespace);
+ EAPI const char *ecore_app_resource_namespace_get(void);
+ EAPI void ecore_app_resource_dir_append(const char *dir);
+ EAPI void ecore_app_resource_dir_prepend(const char *dir);
+ EAPI void ecore_app_resource_dir_del(const char *dir);
+ EAPI const char *ecore_app_resource_get(const char *category, const char *filename);
+ EAPI Eina_List *ecore_app_resource_get_all(const char *category, const char *filename);
+ EAPI const char *ecore_sys_resource_get(const char *category, const char *filename);
+ EAPI Eina_List *ecore_sys_resource_get_all(const char *category, const char *filename);
+
+ typedef struct _Ecore_Resource_Pool Ecore_Resource_Pool;
+ EAPI Ecore_Resource_Pool *ecore_resource_pool_new(const char *name);
+ EAPI void ecore_resource_pool_free(Ecore_Resource_Pool *pool);
+ EAPI void ecore_resource_pool_namespace_set(Ecore_Resource_Pool *pool, const char *namespace);
+ EAPI const char *ecore_resource_pool_namespace_get(const Ecore_Resource_Pool *pool);
+ EAPI void ecore_resource_pool_dir_append(Ecore_Resource_Pool *pool, const char *dir);
+ EAPI void ecore_resource_pool_dir_prepend(Ecore_Resource_Pool *pool, const char *dir);
+ EAPI void ecore_resource_pool_dir_del(Ecore_Resource_Pool *pool, const char *dir);
+ EAPI void ecore_resource_pool_dirs_populate_from_app(Ecore_Resource_Pool *pool, const char *argv0);
+ EAPI void ecore_resource_pool_dirs_populate_from_libaddr(Ecore_Resource_Pool *pool, const void *addr);
+ EAPI const char *ecore_resource_pool_resource_get(const Ecore_Resource_Pool *pool, const char *category, const char *filename);
+ EAPI Eina_List *ecore_resource_pool_resource_get_all(const Ecore_Resource_Pool *pool, const char *category, const char *filename);
+
+ EAPI void ecore_resource_list_free(Eina_List *list);
+
+
EAPI Ecore_Event_Handler *ecore_event_handler_add(int type, Ecore_Event_Handler_Cb func, const void *data);
EAPI void *ecore_event_handler_del(Ecore_Event_Handler *event_handler);
EAPI Ecore_Event *ecore_event_add(int type, void *ev, Ecore_End_Cb func_free, void *data);
Index: src/lib/ecore/Makefile.am
===================================================================
--- src/lib/ecore/Makefile.am (revision 52865)
+++ src/lib/ecore/Makefile.am (working copy)
@@ -10,6 +10,7 @@
includesdir = $(includedir)/eco...@vmaj@
libecore_la_SOURCES = \
+ecore_resource_pool.c \
ecore.c \
ecore_anim.c \
ecore_app.c \
Index: src/lib/ecore/ecore_private.h
===================================================================
--- src/lib/ecore/ecore_private.h (revision 52865)
+++ src/lib/ecore/ecore_private.h (working copy)
@@ -201,6 +201,12 @@
void _ecore_main_loop_init(void);
void _ecore_main_loop_shutdown(void);
+void _ecore_app_init(void);
+void _ecore_app_shutdown(void);
+
+void _ecore_resource_pool_init(void);
+void _ecore_resource_pool_shutdown(void);
+
extern int _ecore_fps_debug;
extern double _ecore_time_loop_time;
extern Eina_Bool _ecore_glib_always_integrate;
Index: src/lib/ecore/ecore_app.c
===================================================================
--- src/lib/ecore/ecore_app.c (revision 52865)
+++ src/lib/ecore/ecore_app.c (working copy)
@@ -16,10 +16,70 @@
#include "Ecore.h"
#include "ecore_private.h"
+#include <errno.h>
static int app_argc = 0;
static char **app_argv = NULL;
+static const char *app_argv0_short = NULL;
+static Eina_Bool app_resource_namespace_auto = EINA_TRUE;
+static Ecore_Resource_Pool *sys_resource_pool = NULL;
+static Ecore_Resource_Pool *app_resource_pool = NULL;
+
+static void
+_ecore_sys_resource_init(void)
+{
+ sys_resource_pool = ecore_resource_pool_new("__ecore_system");
+#ifndef _WIN32
+ /* TODO: also add ${prefix} from autoconf? */
+ ecore_resource_pool_dir_append(sys_resource_pool, "/");
+ ecore_resource_pool_dir_append(sys_resource_pool, "/usr");
+ ecore_resource_pool_dir_append(sys_resource_pool, "/usr/local");
+#endif
+}
+
+static void
+_ecore_app_resource_init(void)
+{
+ char buf[PATH_MAX];
+ char data[PATH_MAX];
+
+ app_resource_pool = ecore_resource_pool_new("__ecore_app");
+
+ if ((getcwd(buf, sizeof(buf))) && (access(buf, R_OK) == 0))
+ ecore_resource_pool_dir_append(app_resource_pool, buf);
+
+ if ((snprintf(data, sizeof(data), "%s/data", buf) < (int)sizeof(data)) &&
+ (access(data, R_OK) == 0))
+ ecore_resource_pool_dir_append(app_resource_pool, data);
+
+ ecore_resource_pool_dirs_populate_from_app
+ (app_resource_pool, app_argv ? app_argv[0] : NULL);
+
+ if (app_resource_namespace_auto)
+ ecore_resource_pool_namespace_set(app_resource_pool, app_argv0_short);
+}
+
+void
+_ecore_app_init(void)
+{
+ app_argv0_short = program_invocation_short_name;
+
+ if (!sys_resource_pool) _ecore_sys_resource_init();
+ if (!app_resource_pool) _ecore_app_resource_init();
+
+ app_resource_namespace_auto = EINA_TRUE;
+}
+
+void
+_ecore_app_shutdown(void)
+{
+ ecore_resource_pool_free(app_resource_pool);
+ app_resource_pool = NULL;
+ ecore_resource_pool_free(sys_resource_pool);
+ sys_resource_pool = NULL;
+}
+
/**
* Set up the programs command-line arguments.
* @param argc The same as passed as argc to the programs main() function
@@ -31,10 +91,19 @@
EAPI void
ecore_app_args_set(int argc, const char **argv)
{
- if ((argc < 1) ||
- (!argv)) return;
+ if ((argc < 1) || (!argv)) return;
app_argc = argc;
app_argv = (char **)argv;
+
+ if (argv[0])
+ {
+ app_argv0_short = strrchr(argv[0], '/');
+ if (app_argv0_short) app_argv0_short++;
+ else app_argv0_short = argv[0];
+ }
+
+ if (app_resource_namespace_auto)
+ ecore_resource_pool_dir_append(app_resource_pool, app_argv0_short);
}
/**
@@ -75,3 +144,185 @@
args[i] = NULL;
execvp(app_argv[0], args);
}
+
+/**
+ * Set application resource namespace.
+ *
+ * By default the resource namespace is the binary file name, but one
+ * can set one specifically to share resources among packages or even
+ * to differentiate between two versions.
+ *
+ * Namespaced resources are always tried first and only if none is
+ * found the non-namespaced are tried.
+ *
+ * @note if using autoconf you likely want to use PACKAGE macro here.
+ *
+ * @param namespace string namespace to use. NULL disables its use.
+ *
+ * @see ecore_app_resource_dir_append()
+ */
+EAPI void
+ecore_app_resource_namespace_set(const char *namespace)
+{
+ app_resource_namespace_auto = EINA_FALSE;
+ ecore_resource_pool_namespace_set(app_resource_pool, namespace);
+}
+
+/**
+ * Get application resource namespace.
+ *
+ * @return NULL or string that should not be modified.
+ */
+EAPI const char *
+ecore_app_resource_namespace_get(void)
+{
+ return ecore_resource_pool_namespace_get(app_resource_pool);
+}
+
+/**
+ * Append search directory for application resources.
+ *
+ * @note if using automake you likely want to define PACKAGE_DATA_DIR
+ * macro and use it here, thus making ecore look at the
+ * installed location of such resources.
+ *
+ * @param dir directory path to lookup during resource discovery. It
+ * may be relative or absolute, the realpath() version will be
+ * used.
+ * @see ecore_app_resource_dir_prepend()
+ * @see ecore_app_resource_get()
+ */
+EAPI void
+ecore_app_resource_dir_append(const char *dir)
+{
+ ecore_resource_pool_dir_append(app_resource_pool, dir);
+}
+
+/**
+ * Prepend (higher priority) search directory for application resources.
+ *
+ * @param dir directory path to lookup during resource discovery. It
+ * may be relative or absolute, the realpath() version will be
+ * used.
+ * @see ecore_app_resource_dir_append()
+ * @see ecore_app_resource_get()
+ */
+EAPI void
+ecore_app_resource_dir_prepend(const char *dir)
+{
+ ecore_resource_pool_dir_prepend(app_resource_pool, dir);
+}
+
+/**
+ * Remove a directory from application resource lookup directory.
+ *
+ * This may be a explicitly added directory with
+ * ecore_app_resource_dir_append() or
+ * ecore_app_resource_dir_prepend(), or the implicitly added
+ * directories such as current working directory.
+ *
+ * @param dir directory to remove.
+ */
+EAPI void
+ecore_app_resource_dir_del(const char *dir)
+{
+ ecore_resource_pool_dir_del(app_resource_pool, dir);
+}
+
+/**
+ * Find an application resource given its category and filename.
+ *
+ * The resource lookup is based on directories explicitly added with
+ * ecore_app_resource_dir_append() and
+ * ecore_app_resource_dir_prepend() as well as implicitly directories
+ * such as current working directory ($CWD) and $CWD/data.
+ *
+ * Namespaces are given higher priority. Remember that by default the
+ * namespace is the basename(argv[0]).
+ *
+ * @param category NULL pointer for no category or some application
+ * defined name. Recommended names are "themes", "modules",
+ * "images".
+ * @param filename the file name to lookup.
+ *
+ * @return reference to buffer on success, NULL if resource was not
+ * found. Buffer is read-only and valid until the next call.
+ */
+EAPI const char *
+ecore_app_resource_get(const char *category, const char *filename)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(filename, NULL);
+ return ecore_resource_pool_resource_get
+ (app_resource_pool, category, filename);
+}
+
+/**
+ * Find all application resources given its category and filename.
+ *
+ * The resource lookup is based on directories explicitly added with
+ * ecore_app_resource_dir_append() and
+ * ecore_app_resource_dir_prepend() as well as implicitly directories
+ * such as current working directory ($CWD) and $CWD/data.
+ *
+ * Namespaces are given higher priority. Remember that by default the
+ * namespace is the basename(argv[0]).
+ *
+ * @param category NULL pointer for no category or some application
+ * defined name. Recommended names are "themes", "modules",
+ * "images".
+ * @param filename the file name to lookup.
+ *
+ * @return newly allocated list with all found resources. The list should be
+ * released with ecore_resource_list_free()
+ */
+EAPI Eina_List *
+ecore_app_resource_get_all(const char *category, const char *filename)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(filename, NULL);
+ return ecore_resource_pool_resource_get_all
+ (app_resource_pool, category, filename);
+}
+
+/**
+ * Find a system resource given its category and filename.
+ *
+ * The resource lookup is based on directories configured by ecore for
+ * your platform/system.
+ *
+ * @param category NULL pointer for no category or some syslication
+ * defined name. Recommended names are "etc", "share",
+ * "bin".
+ * @param filename the file name to lookup.
+ *
+ * @return reference to buffer on success, NULL if resource was not
+ * found. Buffer is read-only and valid until the next call.
+ */
+EAPI const char *
+ecore_sys_resource_get(const char *category, const char *filename)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(filename, NULL);
+ return ecore_resource_pool_resource_get
+ (sys_resource_pool, category, filename);
+}
+
+/**
+ * Find all system resources given its category and filename.
+ *
+ * The resource lookup is based on directories configured by ecore for
+ * your platform/system.
+ *
+ * @param category NULL pointer for no category or some syslication
+ * defined name. Recommended names are "etc", "share",
+ * "bin".
+ * @param filename the file name to lookup.
+ *
+ * @return newly allocated list with all found resources. The list should be
+ * released with ecore_resource_list_free()
+ */
+EAPI Eina_List *
+ecore_sys_resource_get_all(const char *category, const char *filename)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(filename, NULL);
+ return ecore_resource_pool_resource_get_all
+ (sys_resource_pool, category, filename);
+}
Index: src/lib/ecore/ecore.c
===================================================================
--- src/lib/ecore/ecore.c (revision 52865)
+++ src/lib/ecore/ecore.c (working copy)
@@ -111,6 +111,8 @@
}
if (getenv("ECORE_FPS_DEBUG")) _ecore_fps_debug = 1;
if (_ecore_fps_debug) _ecore_fps_debug_init();
+ _ecore_resource_pool_init();
+ _ecore_app_init();
_ecore_main_loop_init();
_ecore_signal_init();
_ecore_exe_init();
@@ -173,6 +175,8 @@
_ecore_main_shutdown();
_ecore_signal_shutdown();
_ecore_main_loop_shutdown();
+ _ecore_app_shutdown();
+ _ecore_resource_pool_shutdown();
#if HAVE_MALLINFO
if (getenv("ECORE_MEM_STAT"))
Index: src/lib/ecore/ecore_resource_pool.c
===================================================================
--- src/lib/ecore/ecore_resource_pool.c (revision 0)
+++ src/lib/ecore/ecore_resource_pool.c (revision 0)
@@ -0,0 +1,532 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifndef _MSC_VER
+# include <unistd.h>
+#else
+# include <process.h>
+#endif
+
+#ifdef HAVE_EVIL
+# include <Evil.h>
+#endif
+
+#include "Ecore.h"
+#include "ecore_private.h"
+
+#include <errno.h>
+#include <sys/stat.h>
+#include <dlfcn.h>
+
+struct _Ecore_Resource_Pool
+{
+ const char *name;
+ const char *namespace;
+ char last_result[PATH_MAX];
+ Eina_List *dirs;
+};
+
+static Eina_Hash *_pools = NULL;
+
+static void
+_ecore_resource_pool_free(void *data)
+{
+ Ecore_Resource_Pool *pool = data;
+ const char *s;
+ EINA_LIST_FREE(pool->dirs, s) eina_stringshare_del(s);
+ eina_stringshare_del(pool->name);
+ eina_stringshare_del(pool->namespace);
+ free(pool);
+}
+
+void
+_ecore_resource_pool_init(void)
+{
+ if (_pools) return;
+ _pools = eina_hash_string_small_new(_ecore_resource_pool_free);
+}
+
+void
+_ecore_resource_pool_shutdown(void)
+{
+ if (!_pools) return;
+ eina_hash_free(_pools);
+}
+
+EAPI Ecore_Resource_Pool *
+ecore_resource_pool_new(const char *name)
+{
+ Ecore_Resource_Pool *pool;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(name, NULL);
+ pool = calloc(1, sizeof(Ecore_Resource_Pool));
+ EINA_SAFETY_ON_NULL_RETURN_VAL(pool, NULL);
+
+ pool->name = eina_stringshare_add(name);
+ EINA_SAFETY_ON_NULL_GOTO(pool->name, error_name);
+
+ if (!eina_hash_direct_add(_pools, pool->name, pool))
+ {
+ ERR("Cannot add pool '%s' to hash", pool->name);
+ goto error_hash;
+ }
+
+ return pool;
+
+ error_hash:
+ eina_stringshare_del(pool->name);
+ error_name:
+ free(pool);
+ return NULL;
+}
+
+EAPI void
+ecore_resource_pool_free(Ecore_Resource_Pool *pool)
+{
+ EINA_SAFETY_ON_NULL_RETURN(pool);
+ eina_hash_del(_pools, pool->name, pool);
+}
+
+EAPI void
+ecore_resource_pool_namespace_set(Ecore_Resource_Pool *pool, const char *namespace)
+{
+ EINA_SAFETY_ON_NULL_RETURN(pool);
+ eina_stringshare_replace(&pool->namespace, namespace);
+}
+
+EAPI const char *
+ecore_resource_pool_namespace_get(const Ecore_Resource_Pool *pool)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(pool, NULL);
+ return pool->namespace;
+}
+
+static inline Eina_Bool
+_resource_dir_check(char *buf, const char *dir)
+{
+ struct stat st;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(dir, EINA_FALSE);
+
+ if (!realpath(dir, buf))
+ {
+ ERR("realpath(%s) failed: %s", dir, strerror(errno));
+ return EINA_FALSE;
+ }
+ if (stat(buf, &st) != 0)
+ {
+ ERR("stat(%s) failed: %s", buf, strerror(errno));
+ return EINA_FALSE;
+ }
+ if (!S_ISDIR(st.st_mode))
+ {
+ ERR("Not a directory: %s", buf);
+ return EINA_FALSE;
+ }
+
+ return EINA_TRUE;
+}
+
+EAPI void
+ecore_resource_pool_dir_append(Ecore_Resource_Pool *pool, const char *dir)
+{
+ const Eina_List *l;
+ const char *s;
+ char buf[PATH_MAX];
+
+ EINA_SAFETY_ON_NULL_RETURN(pool);
+
+ if (!_resource_dir_check(buf, dir)) return;
+
+ dir = eina_stringshare_add(buf);
+ EINA_LIST_FOREACH(pool->dirs, l, s)
+ if (s == dir)
+ {
+ DBG("already in pool with higher priority: %s. Ignored.", dir);
+ eina_stringshare_del(dir);
+ return;
+ }
+
+ INF("pool=%s, dir=%s", pool->name, dir);
+ pool->dirs = eina_list_append(pool->dirs, dir);
+}
+
+EAPI void
+ecore_resource_pool_dir_prepend(Ecore_Resource_Pool *pool, const char *dir)
+{
+ Eina_List *l;
+ const char *s;
+ char buf[PATH_MAX];
+
+ EINA_SAFETY_ON_NULL_RETURN(pool);
+
+ if (!_resource_dir_check(buf, dir)) return;
+
+ dir = eina_stringshare_add(buf);
+ EINA_LIST_FOREACH(pool->dirs, l, s)
+ if (s == dir)
+ {
+ DBG("already in pool: %s, Increase priority", dir);
+ pool->dirs = eina_list_remove_list(pool->dirs, l);
+ break;
+ }
+
+ INF("pool=%s, dir=%s", pool->name, dir);
+ pool->dirs = eina_list_prepend(pool->dirs, dir);
+}
+
+EAPI void
+ecore_resource_pool_dir_del(Ecore_Resource_Pool *pool, const char *dir)
+{
+ char buf[PATH_MAX];
+ Eina_List *l;
+ const char *s;
+
+ EINA_SAFETY_ON_NULL_RETURN(pool);
+ EINA_SAFETY_ON_NULL_RETURN(dir);
+
+ if (!realpath(dir, buf))
+ {
+ ERR("realpath(%s) failed: %s", dir, strerror(errno));
+ return;
+ }
+
+ EINA_LIST_FOREACH(pool->dirs, l, s)
+ {
+ if (strcmp(s, buf) == 0)
+ {
+ DBG("pool=%s, dir=%s", pool->name, dir);
+ eina_stringshare_del(s);
+ pool->dirs = eina_list_remove_list(pool->dirs, l);
+ return;
+ }
+ }
+}
+
+static void
+_pool_populate_from_dir(Ecore_Resource_Pool *pool, const char *dir, const char *name)
+{
+#ifndef _WIN32
+ const struct {
+ const char *d;
+ size_t sz;
+ } *itr, stddirs[] = {
+#define STDDIR(x) {x, sizeof(x) - 1}
+ STDDIR("/bin"),
+ STDDIR("/sbin"),
+ STDDIR("/share"),
+ STDDIR("/lib"),
+ STDDIR("/libexec"),
+ STDDIR("/etc"),
+ STDDIR("/var"),
+ STDDIR("/include"),
+ STDDIR("/info"),
+ STDDIR("/man"),
+#undef STDDIR
+ {NULL, 0}
+ };
+ size_t dir_len = strlen(dir);
+ size_t name_len = name ? strlen(name) : 0;
+
+ for (itr = stddirs; itr->d; itr++)
+ {
+ size_t prefix_len;
+ if (itr->sz >= dir_len) continue;
+ prefix_len = dir_len - itr->sz;
+ if (memcmp(dir + prefix_len, itr->d, itr->sz) == 0)
+ {
+ char buf[PATH_MAX];
+ memcpy(buf, dir, prefix_len);
+ buf[prefix_len] = '\0';
+ ecore_resource_pool_dir_append(pool, buf);
+
+ if ((name) && (prefix_len + name_len + 2 < sizeof(buf)))
+ {
+ buf[prefix_len] = '/';
+ memcpy(buf + prefix_len + 1, name, name_len + 1);
+ if (access(buf, R_OK) == 0)
+ ecore_resource_pool_dir_append(pool, buf);
+ }
+
+ break;
+ }
+ }
+
+#else
+ /* TODO: more OS here */
+#warning "Your OS does not have specific populate from dir!"
+#endif
+
+ /* always add the original directory */
+ ecore_resource_pool_dir_append(pool, dir);
+}
+
+EAPI void
+ecore_resource_pool_dirs_populate_from_app(Ecore_Resource_Pool *pool, const char *argv0)
+{
+ char dirn[PATH_MAX];
+ char basen[NAME_MAX];
+ const char *p;
+ char **PATH;
+
+ EINA_SAFETY_ON_NULL_RETURN(pool);
+
+ if (!argv0) argv0 = program_invocation_name;
+ EINA_SAFETY_ON_NULL_RETURN(argv0);
+
+ p = strrchr(argv0, '/');
+ if (!p)
+ {
+ if (eina_strlcpy(basen, argv0, sizeof(basen)) >= sizeof(basen))
+ return;
+ dirn[0] = '\0';
+ }
+ else
+ {
+ if (p[1] != '\0')
+ {
+ if (eina_strlcpy(basen, p + 1, sizeof(basen)) >= sizeof(basen))
+ return;
+ if (eina_strlcpy(dirn, argv0, sizeof(dirn)) >= sizeof(dirn))
+ return;
+ dirn[p - argv0] = '\0';
+ }
+ else
+ {
+ const char *start;
+ for (start = p - 1; start > argv0; start--)
+ {
+ if (*start == '/')
+ {
+ start++;
+ break;
+ }
+ }
+ if ((size_t)(p - start) >= sizeof(basen) - 1)
+ return;
+ memcpy(basen, start, p - start);
+ basen[p - start] = '\0';
+
+ if (start > argv0)
+ {
+ start--;
+ memcpy(dirn, argv0, start - argv0);
+ dirn[start - argv0] = '\0';
+ }
+ else dirn[0] = '\0';
+ }
+ }
+
+ if ((dirn[0] == '/') ||
+ ((dirn[0] == '.') && ((dirn[1] == '/') || (dirn[1] == '.'))))
+ {
+ char rp[PATH_MAX];
+ if (!realpath(dirn, rp))
+ WRN("realpath(%s): %s", dirn, strerror(errno));
+ else
+ {
+ INF("pool=%s, argv[0]=%s, directory=%s", pool->name, argv0, rp);
+ _pool_populate_from_dir(pool, rp, basen);
+ return;
+ }
+ }
+
+ PATH = eina_str_split(getenv("PATH"), ":", -1);
+ if (PATH)
+ {
+ char rp[PATH_MAX];
+ char **itr;
+ for (itr = PATH; *itr; itr++)
+ {
+ char *p;
+ int r = snprintf(dirn, sizeof(dirn), "%s/%s", *itr, basen);
+ if ((r <= 0) || ((size_t)r >= sizeof(dirn))) continue;
+ if (!realpath(dirn, rp)) continue;
+ if (access(rp, X_OK) != 0) continue;
+ p = strrchr(rp, '/');
+ if (!p) continue;
+ *p = '\0';
+ INF("pool=%s, argv[0]=%s, directory=%s", pool->name, argv0, rp);
+ _pool_populate_from_dir(pool, rp, basen);
+ }
+ free(PATH[0]);
+ free(PATH);
+ }
+}
+
+EAPI void
+ecore_resource_pool_dirs_populate_from_libaddr(Ecore_Resource_Pool *pool, const void *addr)
+{
+ char dirn[PATH_MAX], rp[PATH_MAX];
+ const char *s, *p;
+ Dl_info addrinfo;
+
+ EINA_SAFETY_ON_NULL_RETURN(pool);
+ EINA_SAFETY_ON_NULL_RETURN(addr);
+
+ if (!dladdr(addr, &addrinfo))
+ {
+ ERR("could not lookup information about dynamic library address %p",
+ addr);
+ return;
+ }
+
+ if (!addrinfo.dli_fname)
+ {
+ ERR("no filename for dynamic library address %p", addr);
+ return;
+ }
+
+ s = addrinfo.dli_fname;
+ p = strrchr(s, '/');
+ if ((!p) || (p[1] == '\0'))
+ {
+ ERR("invalid dynamic library path for address %p: %s", addr, s);
+ return;
+ }
+ if ((size_t)(p - s + 1) >= sizeof(dirn))
+ {
+ ERR("path is too long: %s", s);
+ return;
+ }
+ memcpy(dirn, s, p - s);
+ dirn[p - s] = '\0';
+
+ if (!realpath(dirn, rp))
+ {
+ ERR("realpath(%s): %s", dirn, strerror(errno));
+ return;
+ }
+
+ INF("pool=%s, addr=%p, directory=%s", pool->name, addr, rp);
+ _pool_populate_from_dir(pool, rp, NULL);
+}
+
+static inline Eina_Bool
+_resource_get(char *buf, size_t buf_len, const char *dir, const char *category, const char *filename)
+{
+ int r;
+
+ if (category)
+ r = snprintf(buf, buf_len, "%s/%s/%s", dir, category, filename);
+ else
+ r = snprintf(buf, buf_len, "%s/%s", dir, filename);
+
+ if ((r <= 0) || ((size_t)r >= buf_len)) return EINA_FALSE;
+
+ return access(buf, R_OK) == 0;
+}
+#define resource_get(buf, dir, category, filename) \
+ _resource_get(buf, sizeof(buf), dir, category, filename)
+
+EAPI const char *
+ecore_resource_pool_resource_get(const Ecore_Resource_Pool *pool, const char *category, const char *filename)
+{
+ const Eina_List *l;
+ const char *dir;
+ char *res;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(pool, NULL);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(filename, NULL);
+
+ res = ((Ecore_Resource_Pool *)pool)->last_result;
+
+ if ((!strcmp(category, "")) || (!strcmp(category, "."))) category = NULL;
+
+ DBG("pool=%s, namespace=%s, category=%s, filename=%s",
+ pool->name, pool->namespace ? pool->namespace : "",
+ category ? category : "", filename);
+
+ if (pool->namespace)
+ {
+ char buf[PATH_MAX];
+ const char *ns = pool->namespace;
+ EINA_LIST_FOREACH(pool->dirs, l, dir)
+ {
+ int r;
+
+ r = snprintf(buf, sizeof(buf), "%s/%s", dir, ns);
+ if ((r <= 0) || ((size_t)r >= sizeof(buf))) continue;
+ if (_resource_get(res, PATH_MAX, buf, category, filename))
+ return res;
+
+ if (category)
+ {
+ r = snprintf(buf, sizeof(buf), "%s/%s", category, ns);
+ if ((r <= 0) || ((size_t)r >= sizeof(buf))) continue;
+ if (_resource_get(res, PATH_MAX, dir, buf, filename))
+ return res;
+ }
+ }
+ }
+
+ EINA_LIST_FOREACH(pool->dirs, l, dir)
+ {
+ if (_resource_get(res, PATH_MAX, dir, category, filename))
+ return res;
+ }
+
+ return NULL;
+}
+
+EAPI Eina_List *
+ecore_resource_pool_resource_get_all(const Ecore_Resource_Pool *pool, const char *category, const char *filename)
+{
+ Eina_List *ret = NULL;
+ const Eina_List *l;
+ const char *dir;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(pool, NULL);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(filename, NULL);
+
+ if ((!strcmp(category, "")) || (!strcmp(category, "."))) category = NULL;
+ DBG("pool=%s, namespace=%s, category=%s, filename=%s",
+ pool->name, pool->namespace ? pool->namespace : "",
+ category ? category : "", filename);
+
+ if (pool->namespace)
+ {
+ char buf[PATH_MAX];
+ const char *ns = pool->namespace;
+ EINA_LIST_FOREACH(pool->dirs, l, dir)
+ {
+ char buf2[PATH_MAX];
+ int r;
+
+ r = snprintf(buf, sizeof(buf), "%s/%s", dir, ns);
+ if ((r <= 0) || ((size_t)r >= sizeof(buf))) continue;
+ if (resource_get(buf2, buf, category, filename))
+ ret = eina_list_append(ret, eina_stringshare_add(buf2));
+
+ if (category)
+ {
+ r = snprintf(buf, sizeof(buf), "%s/%s", category, ns);
+ if ((r <= 0) || ((size_t)r >= sizeof(buf))) continue;
+ if (resource_get(buf2, dir, buf, filename))
+ ret = eina_list_append(ret, eina_stringshare_add(buf2));
+ }
+ }
+ }
+
+ EINA_LIST_FOREACH(pool->dirs, l, dir)
+ {
+ char buf[PATH_MAX];
+ if (resource_get(buf, dir, category, filename))
+ ret = eina_list_append(ret, eina_stringshare_add(buf));
+ }
+
+ return ret;
+}
+
+/**
+ * Free the resource list returned by ecore_resource_pool_resource_get_all()
+ *
+ * @param list the list to be released.
+ */
+EAPI void
+ecore_resource_list_free(Eina_List *list)
+{
+ const char *s;
+ EINA_LIST_FREE(list, s) eina_stringshare_del(s);
+}
#define _GNU_SOURCE
#include <Ecore.h>
#include <stdio.h>
#include <dlfcn.h>
int main(int argc, char *argv[])
{
Ecore_Resource_Pool *ecore_rp;
Eina_List *lst, *itr;
const char *r;
ecore_init();
/* simulates access to application specific resources */
ecore_app_resource_namespace_set(argv[1]);
ecore_app_resource_dir_append(argv[2]);
printf("namespace: %s\n", argv[1]);
printf("extra dir: %s\n", argv[2]);
printf("category.: %s\n", argv[3]);
printf("filename.: %s\n", argv[4]);
printf("main resource: %s\n", ecore_app_resource_get(argv[3], argv[4]));
printf("all app resources:\n");
lst = ecore_app_resource_get_all(argv[3], argv[4]);
EINA_LIST_FOREACH(lst, itr, r)
printf(" app resource: %s\n", r);
ecore_resource_list_free(lst);
/* simulates access to system resources */
printf("system resource passwd: %s\n", ecore_sys_resource_get("etc", "passwd"));
printf("all sys resources:\n");
lst = ecore_sys_resource_get_all("etc", "passwd");
EINA_LIST_FOREACH(lst, itr, r)
printf(" sys resource: %s\n", r);
ecore_resource_list_free(lst);
/* simulates how a lib would use its own resources */
ecore_rp = ecore_resource_pool_new("test-ecore");
ecore_resource_pool_namespace_set(ecore_rp, "ecore-1");
void *h = dlopen("libecore.so", RTLD_LAZY);
printf("libecore.so: %p\n", h);
ecore_resource_pool_dirs_populate_from_libaddr(ecore_rp, dlsym(h, "ecore_init"));
printf("ecore-rp: %s\n", ecore_resource_pool_resource_get(ecore_rp, "include", "Ecore.h"));
ecore_resource_pool_free(ecore_rp);
ecore_shutdown();
return 0;
}
------------------------------------------------------------------------------
Start uncovering the many advantages of virtual appliances
and start using them to simplify application deployment and
accelerate your shift to cloud computing.
http://p.sf.net/sfu/novell-sfdev2dev
_______________________________________________
enlightenment-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/enlightenment-devel