Merge branch 'master' into svn_merge
[framework/uifw/elementary.git] / src / lib / elm_module.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3
4 /* what are moodules in elementary for? for modularising behavior and features
5  * so they can be plugged in and out where you dont want the core source to
6  * always behave like that or do it that way. plug it at runtime!
7  *
8  * they have module names (in config) and "slots" to plug that module into
9  * to server a purpose. eg you plug plugin "xx" into the "entry-copy-paste"
10  * slot so it would provide replacement copy & paste ui functionality and
11  * specific symbols
12  *
13  * config is something like:
14  *
15  * export ELM_MODULES="xx>slot1:yy>slot2"
16  *
17  * where a module named xx is plugged into slot1 & yy is plugged into slot2
18  *
19  * real examples:
20  *
21  * export ELM_MODULES="my_module>entry/api"
22  *
23  * this loads the module called "my_module" into the slot "entry/api" which
24  * is an api slot for entry modules to modify behavior and hook to
25  * creation/deletion of the entry as well as replace the longpress behavior.
26  */
27
28 #ifdef HAVE_CONFIG_H
29 # include "elementary_config.h"
30 #endif
31
32 #include <dlfcn.h>      /* dlopen,dlclose,etc */
33
34 static Eina_Hash *modules = NULL;
35 static Eina_Hash *modules_as = NULL;
36
37 void
38 _elm_module_init(void)
39 {
40    modules = eina_hash_string_small_new(NULL);
41    modules_as = eina_hash_string_small_new(NULL);
42 }
43
44 void
45 _elm_module_shutdown(void)
46 {
47    // FIXME: unload all modules
48    if (modules) eina_hash_free(modules);
49    modules = NULL;
50    if (modules_as) eina_hash_free(modules_as);
51    modules_as = NULL;
52 }
53
54 void
55 _elm_module_parse(const char *s)
56 {
57    const char *p, *pe;
58
59    p = s;
60    pe = p;
61    for (;;)
62      {
63         if ((*pe == ':') || (!*pe))
64           { // p -> pe == 'name:'
65              if (pe > p)
66                {
67                   char *n = malloc(pe - p + 1);
68                   if (n)
69                     {
70                        char *nn;
71
72                        strncpy(n, p, pe - p);
73                        n[pe - p] = 0;
74                        nn = strchr(n, '>');
75                        if (nn)
76                          {
77                             *nn = 0;
78                             nn++;
79                             _elm_module_add(n, nn);
80                          }
81                        free(n);
82                     }
83                }
84              if (!*pe) break;
85              p = pe + 1;
86              pe = p;
87           }
88         else
89           pe++;
90      }
91 }
92
93 Elm_Module *
94 _elm_module_find_as(const char *as)
95 {
96    Elm_Module *m;
97
98    m = eina_hash_find(modules_as, as);
99    if (!m) return NULL;
100
101    if (!_elm_module_load(m))
102      {
103         _elm_module_del(m);
104         return NULL;
105      }
106    return m;
107 }
108
109 Eina_Bool
110 _elm_module_load(Elm_Module *m)
111 {
112    const char *home;
113    char buf[PATH_MAX];
114
115    if (m->handle) return EINA_TRUE;
116
117    home = getenv("HOME");
118    if (home)
119      {
120         snprintf(buf, sizeof(buf), "%s/.elementary/modules/%s/%s/module" EFL_SHARED_EXTENSION, home, m->name, MODULE_ARCH);
121         m->handle = dlopen(buf, RTLD_NOW | RTLD_GLOBAL);
122         if (m->handle)
123           {
124              m->init_func = dlsym(m->handle, "elm_modapi_init");
125              if (m->init_func)
126                {
127                   m->shutdown_func = dlsym(m->handle, "elm_modapi_shutdown");
128                   m->so_path = eina_stringshare_add(buf);
129                   snprintf(buf, sizeof(buf), "%s/.elementary/modules/%s/%s", home, m->name, MODULE_ARCH);
130                   m->bin_dir = eina_stringshare_add(buf);
131                   snprintf(buf, sizeof(buf), "%s/.elementary/modules/%s", home, m->name);
132                   m->data_dir = eina_stringshare_add(buf);
133                }
134              else
135                {
136                   if (m->handle)
137                     {
138                        dlclose(m->handle);
139                        m->handle = NULL;
140                     }
141                   return EINA_FALSE;
142                }
143           }
144      }
145
146    if (!m->handle)
147      {
148         snprintf(buf, sizeof(buf), "%s/elementary/modules/%s/%s/module" EFL_SHARED_EXTENSION, _elm_lib_dir, m->name, MODULE_ARCH);
149         m->handle = dlopen(buf, RTLD_NOW | RTLD_GLOBAL);
150         if (m->handle)
151           {
152              m->init_func = dlsym(m->handle, "elm_modapi_init");
153              if (m->init_func)
154                {
155                   m->shutdown_func = dlsym(m->handle, "elm_modapi_shutdown");
156                   m->so_path = eina_stringshare_add(buf);
157                   snprintf(buf, sizeof(buf), "%s/elementary/modules/%s/%s", _elm_lib_dir, m->name, MODULE_ARCH);
158                   m->bin_dir = eina_stringshare_add(buf);
159                   snprintf(buf, sizeof(buf), "%s/elementary/modules/%s", _elm_lib_dir, m->name);
160                   m->data_dir = eina_stringshare_add(buf);
161                }
162              else
163                {
164                   if (m->handle)
165                     {
166                        dlclose(m->handle);
167                        m->handle = NULL;
168                     }
169                   return EINA_FALSE;
170                }
171           }
172      }
173
174    if (!m->handle) return EINA_FALSE;
175    return EINA_TRUE;
176 }
177
178 void
179 _elm_module_unload(Elm_Module *m)
180 {
181    eina_stringshare_del(m->so_path);
182    eina_stringshare_del(m->data_dir);
183    eina_stringshare_del(m->bin_dir);
184    if (m->api)
185      {
186         free(m->api);
187         m->api = NULL;
188      }
189    if (m->handle)
190      {
191         if (m->shutdown_func) m->shutdown_func(m);
192         dlclose(m->handle);
193         m->handle = NULL;
194      }
195    m->shutdown_func = NULL;
196    m->init_func = NULL;
197 }
198
199 Elm_Module *
200 _elm_module_add(const char *name, const char *as)
201 {
202    Elm_Module *m;
203
204    if (name[0] == '/') return NULL;
205
206    m = eina_hash_find(modules, name);
207    if (m)
208      {
209         m->references++;
210         return m;
211      }
212    m = calloc(1, sizeof(Elm_Module));
213    if (!m) return NULL;
214    m->version = 1;
215    m->name = eina_stringshare_add(name);
216    m->references = 1;
217    eina_hash_direct_add(modules, m->name, m);
218    m->as = eina_stringshare_add(as);
219    eina_hash_direct_add(modules_as, m->as, m);
220    return m;
221 }
222
223 void
224 _elm_module_del(Elm_Module *m)
225 {
226    m->references--;
227    if (m->references > 0) return;
228    _elm_module_unload(m);
229    eina_hash_del(modules, m->name, m);
230    eina_hash_del(modules_as, m->as, m);
231    eina_stringshare_del(m->name);
232    eina_stringshare_del(m->as);
233    free(m);
234 }
235
236 const void *
237 _elm_module_symbol_get(Elm_Module *m, const char *name)
238 {
239    return dlsym(m->handle, name);
240 }