efl/legacy/evas/src/lib/file/evas_module.c

495 lines
11 KiB
C
Raw Normal View History

#ifdef __GNUC__
# ifndef __USE_GNU
# define __USE_GNU
# endif
# ifndef _GNU_SOURCE
# define _GNU_SOURCE
# endif
# ifndef _BSD_SOURCE
# define _BSD_SOURCE
# endif
#endif
#include <dirent.h> /* DIR, dirent */
#ifdef _WIN32
# include <windows.h>
# include <stdlib.h>
# include <stdio.h>
#else
# include <dlfcn.h> /* dlopen,dlclose,etc */
#endif
#include <evas_common.h>
#include <evas_private.h>
/* FIXME: that hack is a temporary one. That code will be in MinGW soon */
#ifdef _WIN32
# define RTLD_LAZY 1 /* lazy function call binding */
# define RTLD_NOW 2 /* immediate function call binding */
# define RTLD_GLOBAL 4 /* symbols in this dlopen'ed obj are visible
to other dlopen'ed objs */
static char *dlerr_ptr;
static char dlerr_data[80];
void *dlopen (const char *file, int mode)
{
HMODULE hmodule;
hmodule = LoadLibrary(file);
if (hmodule == NULL) {
int error;
error = GetLastError();
sprintf(dlerr_data, "LoadLibraryEx returned %d.", error);
dlerr_ptr = dlerr_data;
}
return hmodule;
}
int dlclose (void *handle)
{
if (FreeLibrary(handle)) {
return 0;
}
else {
int error;
error = GetLastError();
sprintf(dlerr_data, "FreeLibrary returned %d.", error);
dlerr_ptr = dlerr_data;
return -1;
}
}
void *dlsym (void *handle, const char *name)
{
FARPROC fp;
fp = GetProcAddress(handle, name);
if (fp == NULL) {
int error;
error = GetLastError();
sprintf(dlerr_data, "GetProcAddress returned %d.", error);
dlerr_ptr = dlerr_data;
}
return fp;
}
char *dlerror (void)
{
if (dlerr_ptr != NULL) {
dlerr_ptr = NULL;
return dlerr_data;
}
else {
return NULL;
}
}
#endif /* _WIN32 */
Evas_List *evas_modules = NULL;
static Evas_List *evas_module_paths = NULL;
static void
_evas_module_path_append(Evas_Module_Type type, char *path, const char *subdir)
{
Evas_Module_Path *mp;
char *buf;
buf = evas_file_path_join(path, subdir);
if (!buf) return;
if (evas_file_path_exists(buf))
{
mp = malloc(sizeof(Evas_Module_Path));
mp->type = type;
mp->path = buf;
evas_module_paths = evas_list_append(evas_module_paths, mp);
}
else
free(buf);
}
/* this will alloc a list of paths to search for the modules */
/* by now these are: */
/* 1. ~/.evas/modules/ */
/* 2. PREFIX/evas/modules/ */
/* 3. dladdr/evas/modules/ */
void
evas_module_paths_init(void)
{
char *prefix;
char *path;
Evas_List *paths = NULL;
/* 1. ~/.evas/modules/ */
prefix = getenv("HOME");
if (prefix)
{
path = malloc(strlen(prefix) + 1 + strlen("/.evas/modules"));
if (path)
{
path[0] = 0;
strcpy(path, prefix);
strcat(path, "/.evas/modules");
if (evas_file_path_exists(path))
paths = evas_list_append(paths, path);
else
free(path);
}
}
#ifdef HAVE_DLADDR
{
Dl_info evas_dl;
/* 3. libevas.so/../evas/modules/ */
if (dladdr(evas_module_paths_init, &evas_dl))
{
int length;
if (strrchr(evas_dl.dli_fname, '/'))
{
length = strlen(strrchr(evas_dl.dli_fname, '/'));
path = malloc(strlen(evas_dl.dli_fname) - length +
strlen("/evas/modules") + 1);
if (path)
{
strncpy(path, evas_dl.dli_fname,
strlen(evas_dl.dli_fname) - length);
path[strlen(evas_dl.dli_fname) - length] = 0;
strcat(path, "/evas/modules");
if (evas_file_path_exists(path))
paths = evas_list_append(paths, path);
else
free(path);
}
}
}
}
#else
/* 3. PREFIX/evas/modules/ */
prefix = PACKAGE_LIB_DIR;
path = malloc(strlen(prefix) + 1 + strlen("/evas/modules"));
if (path)
{
strcpy(path, prefix);
strcat(path, "/evas/modules");
if (evas_file_path_exists(path))
paths = evas_list_append(paths, path);
else
free(path);
}
#endif
/* append all the module types subdirs */
while (paths)
{
/* here must be added all the types of modules and their subdirectory */
/* do this on a separate function */
/* 1. engines */
_evas_module_path_append(EVAS_MODULE_TYPE_ENGINE, paths->data, "engines");
_evas_module_path_append(EVAS_MODULE_TYPE_IMAGE_LOADER, paths->data, "loaders");
_evas_module_path_append(EVAS_MODULE_TYPE_IMAGE_SAVER, paths->data, "savers");
_evas_module_path_append(EVAS_MODULE_TYPE_OBJECT, paths->data, "objects");
free(paths->data);
paths = evas_list_remove_list(paths, paths);
}
}
/* this will alloc an Evas_Module struct for each module
* it finds on the paths */
void
evas_module_init(void)
{
Evas_List *l;
int new_id_engine = 1;
/* printf("[init modules]\n"); */
evas_module_paths_init();
for (l = evas_module_paths; l; l = l->next)
{
Evas_Module_Path *mp;
DIR *dir;
struct dirent *de;
mp = l->data;
if (!(dir = opendir(mp->path))) break;
/* printf("[evas module] searching modules on %s\n", mp->path); */
while ((de = readdir(dir)))
{
char *buf;
if ((!strcmp(de->d_name, ".")) || (!strcmp(de->d_name, "..")))
continue;
buf = malloc(strlen(mp->path) + 1 + strlen(de->d_name) + 1);
sprintf(buf, "%s/%s", mp->path, de->d_name);
if (evas_file_path_is_dir(buf))
{
Evas_Module *em;
em = calloc(1, sizeof(Evas_Module));
if (!em) continue;
em->name = strdup(de->d_name);
em->path = strdup(mp->path);
em->type = mp->type;
em->handle = NULL;
em->data = NULL;
em->loaded = 0;
if (em->type == EVAS_MODULE_TYPE_ENGINE)
{
Evas_Module_Engine *eme;
eme = malloc(sizeof(Evas_Module_Engine));
if (eme)
{
eme->id = new_id_engine;
em->data = eme;
new_id_engine++;
}
}
else if (em->type == EVAS_MODULE_TYPE_IMAGE_LOADER)
{
}
else if (em->type == EVAS_MODULE_TYPE_IMAGE_SAVER)
{
}
/* printf("[evas module] including module path %s/%s of type %d\n",em->path, em->name, em->type); */
evas_modules = evas_list_append(evas_modules, em);
}
free(buf);
}
closedir(dir);
}
}
Evas_Module *
evas_module_find_type(Evas_Module_Type type, const char *name)
{
Evas_List *l;
for (l = evas_modules; l; l = l->next)
{
Evas_Module *em;
em = (Evas_Module*)l->data;
if ((type == em->type) && (!strcmp(name,em->name)))
{
if (evas_modules != l)
{
evas_modules = evas_list_promote_list(evas_modules, l);
}
return em;
}
}
return NULL;
}
int
evas_module_load(Evas_Module *em)
{
char buf[4096];
void *handle;
if (em->loaded) return 1;
/* printf("LOAD %s\n", em->name); */
#ifdef _WIN32
snprintf(buf, sizeof(buf), "%s/%s/%s/module.dll", em->path, em->name, MODULE_ARCH);
#else
snprintf(buf, sizeof(buf), "%s/%s/%s/module.so", em->path, em->name, MODULE_ARCH);
#endif
if (!evas_file_path_exists(buf))
{
printf("[evas module] error loading the module %s. It doesnt exists\n", buf);
return 0;
}
handle = dlopen(buf, RTLD_LAZY);
if (handle)
{
em->handle = handle;
em->func.open = dlsym(em->handle, "module_open");
em->func.close = dlsym(em->handle, "module_close");
em->api = dlsym(em->handle, "evas_modapi");
if ((!em->func.open) || (!em->api) || (!em->func.close))
goto error_dl;
/* check the api */
if (em->api->version != EVAS_MODULE_API_VERSION)
{
printf("[evas module] error loading the modules %s. The version doesnt match\n", buf);
goto error_dl;
}
em->func.open(em);
em->loaded = 1;
return 1;
}
error_dl:
{
const char *err;
err = dlerror();
printf("[evas module] error loading the module %s. %s\n", buf, err);
if (handle)
dlclose(handle);
em->handle = NULL;
em->func.open = NULL;
em->func.close = NULL;
em->api = NULL;
}
return 0;
}
void
evas_module_unload(Evas_Module *em)
{
if (!em->loaded)
return;
if (em->handle)
{
em->func.close(em);
dlclose(em->handle);
}
em->handle = NULL;
em->func.open = NULL;
em->func.close = NULL;
em->api = NULL;
em->loaded = 0;
}
void
evas_module_ref(Evas_Module *em)
{
em->ref++;
/* printf("M: %s ref++ = %i\n", em->name, em->ref); */
}
void
evas_module_unref(Evas_Module *em)
{
em->ref--;
/* printf("M: %s ref-- = %i\n", em->name, em->ref); */
}
static int use_count = 0;
void
evas_module_use(Evas_Module *em)
{
em->last_used = use_count;
}
void
evas_module_clean(void)
{
static int call_count = 0;
int ago;
int noclean = -1;
Evas_List *l;
Evas_Module *em;
/* only clean modules every 256 calls */
call_count++;
if (call_count <= 256) return;
call_count = 0;
if (noclean == -1)
{
if (getenv("EVAS_NOCLEAN"))
{
noclean = 1;
}
noclean = 0;
}
if (noclean == 1) return;
/* disable module cleaning for now - may cause instability with some modules */
return;
/* incriment use counter = 28bits */
use_count++;
if (use_count > 0x0fffffff) use_count = 0;
/* printf("CLEAN!\n"); */
/* go through all modules */
for (l = evas_modules; l; l = l->next)
{
em = l->data;
/* printf("M %s %i %i\n", em->name, em->ref, em->loaded); */
/* if the module is refernced - skip */
if ((em->ref > 0) || (!em->loaded)) continue;
/* how many clean cycles ago was this module last used */
ago = use_count - em->last_used;
if (em->last_used > use_count) ago += 0x10000000;
/* if it was used last more than N clean cycles ago - unload */
if (ago > 5)
{
/* printf(" UNLOAD %s\n", em->name); */
evas_module_unload(em);
}
}
}
2006-01-14 07:43:05 -08:00
/* will dlclose all the modules loaded and free all the structs */
void
evas_module_shutdown(void)
{
Evas_Module *em;
/* printf("[shutdown modules]\n"); */
while (evas_modules)
{
em = (Evas_Module *)evas_modules->data;
evas_module_unload(em);
if (em->name) free(em->name);
if (em->path) free(em->path);
if (em->type == EVAS_MODULE_TYPE_ENGINE)
{
if (em->data) free(em->data);
}
else if (em->type == EVAS_MODULE_TYPE_IMAGE_LOADER)
{
}
else if (em->type == EVAS_MODULE_TYPE_IMAGE_SAVER)
{
}
free(evas_modules->data);
evas_modules = evas_list_remove_list(evas_modules, evas_modules);
}
while (evas_module_paths)
{
Evas_Module_Path *mp;
mp = evas_module_paths->data;
evas_module_paths = evas_list_remove_list(evas_module_paths, evas_module_paths);
free(mp->path);
free(mp);
}
}
EAPI int
_evas_module_engine_inherit(Evas_Func *funcs, char *name)
{
Evas_Module *em;
em = evas_module_find_type(EVAS_MODULE_TYPE_ENGINE, name);
if (em)
{
if (evas_module_load(em))
{
/* FIXME: no way to unref */
evas_module_ref(em);
evas_module_use(em);
*funcs = *((Evas_Func *)(em->functions));
return 1;
}
}
return 0;
}