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