Line | Branch | Exec | Source |
---|---|---|---|
1 | #ifndef BUILD_ON_WINDOWS | ||
2 | #include <glob.h> | ||
3 | #include <dlfcn.h> | ||
4 | #include <limits.h> | ||
5 | #endif | ||
6 | |||
7 | #include "gwion_util.h" | ||
8 | #include "gwion_ast.h" | ||
9 | #include "gwion_env.h" | ||
10 | #include "vm.h" | ||
11 | #include "gwion.h" | ||
12 | #include "operator.h" | ||
13 | #include "instr.h" | ||
14 | #include "object.h" | ||
15 | #include "import.h" | ||
16 | #include "gwi.h" | ||
17 | |||
18 | struct PlugHandle { | ||
19 | MemPool mp; | ||
20 | Map map; | ||
21 | size_t len; | ||
22 | }; | ||
23 | |||
24 | 47 | ANN static struct Plug_ *new_dl_plug(MemPool p, void *dl, const char *name) { | |
25 | 47 | Plug plug = new_plug(p); | |
26 | 47 | plug->dl = dl; | |
27 | 47 | char s[256] = { [0] = 'g', [1] = 'w', [8] = '_' }; | |
28 | 47 | strcpy(s + 9, name); | |
29 | 47 | memcpy(s + 2, "import", 6); | |
30 | 47 | plug->plugin = DLSYM(plug->dl, gwplugin_t, s); | |
31 | 47 | memcpy(s + 2, "modini", 6); | |
32 | 47 | plug->modini = DLSYM(plug->dl, gwmodini_t, s); | |
33 | 47 | memcpy(s + 2, "modend", 6); | |
34 | 47 | plug->modend = DLSYM(plug->dl, gwmodend_t, s); | |
35 | 47 | memcpy(s + 2, "driver", 6); | |
36 | 47 | plug->driver = DLSYM(plug->dl, gwdriver_t, s); | |
37 | 47 | memcpy(s + 2, "depend", 6); | |
38 | 47 | plug->depend = DLSYM(plug->dl, gwdepend_t, s); | |
39 | 47 | return plug; | |
40 | } | ||
41 | |||
42 | 48 | ANN static void plug_get(struct PlugHandle *h, const m_str c) { | |
43 | 48 | void * dl = DLOPEN(c, RTLD_LAZY | RTLD_GLOBAL); | |
44 | 48 | const m_str pname = c + h->len + 1; | |
45 | 48 | const size_t sz = strlen(pname) - 3; | |
46 | char name[PATH_MAX]; | ||
47 | 48 | memcpy(name, pname, sz); | |
48 | 48 | name[sz] = '\0'; | |
49 |
2/2✓ Branch 0 taken 47 times.
✓ Branch 1 taken 1 times.
|
48 | if (dl) { |
50 | 47 | Plug plug = new_dl_plug(h->mp, dl, name); | |
51 | 47 | map_set(h->map, (vtype)strdup(name), (vtype)plug); | |
52 | } else | ||
53 | 1 | gw_err(_("{+R}error{0} in {/+}%s{0}."), DLERROR()); | |
54 | 48 | } | |
55 | |||
56 | 756 | ANN static void plug_get_all(struct PlugHandle *h, const m_str name) { | |
57 | #ifndef BUILD_ON_WINDOWS | ||
58 | glob_t results; | ||
59 |
2/2✓ Branch 1 taken 709 times.
✓ Branch 2 taken 47 times.
|
756 | if (glob(name, 0, NULL, &results)) return; |
60 |
2/2✓ Branch 0 taken 48 times.
✓ Branch 1 taken 47 times.
|
95 | for (m_uint i = 0; i < results.gl_pathc; i++) |
61 | 48 | plug_get(h, results.gl_pathv[i]); | |
62 | 47 | globfree(&results); | |
63 | #else | ||
64 | WIN32_FIND_DATA filedata; | ||
65 | HANDLE file = FindFirstFile(name, &filedata); | ||
66 | if (file == INVALID_HANDLE_VALUE) return; | ||
67 | do { | ||
68 | char c[PATH_MAX]; | ||
69 | strcpy(c, name); | ||
70 | strcpy(c + strlen(name) - 4, filedata.cFileName); | ||
71 | plug_get(h, c); | ||
72 | } while (FindNextFile(file, &filedata)); | ||
73 | FindClose(file); | ||
74 | #endif | ||
75 | } | ||
76 | |||
77 | 707 | ANN m_bool plug_ini(const struct Gwion_ *gwion, const Vector list) { | |
78 | 707 | gwion->data->plugs = mp_calloc2(gwion->mp, sizeof(Plugs)); | |
79 | 707 | const Map map = &gwion->data->plugs->map; | |
80 | 707 | map_init(map); | |
81 | 707 | vector_init(&gwion->data->plugs->vec); | |
82 | 707 | struct PlugHandle h = {.mp = gwion->mp, .map = map}; | |
83 |
2/2✓ Branch 1 taken 756 times.
✓ Branch 2 taken 707 times.
|
1463 | for (m_uint i = vector_size(list) + 1 ; --i;) { |
84 | 756 | const m_str dir = (m_str)vector_at(list, i - 1); | |
85 | 756 | h.len = strlen(dir); | |
86 | char name[PATH_MAX]; | ||
87 | 756 | sprintf(name, "%s/*.so", dir); | |
88 | 756 | plug_get_all(&h, name); | |
89 | } | ||
90 | 707 | return GW_OK; | |
91 | } | ||
92 | |||
93 | 707 | void free_plug(const Gwion gwion) { | |
94 | 707 | const Vector vec = &gwion->data->plugs->vec; | |
95 |
2/2✓ Branch 1 taken 680 times.
✓ Branch 2 taken 707 times.
|
1387 | for (m_uint i = vector_size(vec) + 1; --i;) { |
96 | 680 | const Nspc nspc = (Nspc)vector_at(vec, i-1); | |
97 | 680 | nspc_remref(nspc, gwion); | |
98 | } | ||
99 | 707 | vector_release(&gwion->data->plugs->vec); | |
100 | 707 | const Map map = &gwion->data->plugs->map; | |
101 |
2/2✓ Branch 1 taken 47 times.
✓ Branch 2 taken 707 times.
|
754 | for (m_uint i = 0; i < map_size(map); ++i) { |
102 | 47 | const Plug plug = (Plug)VVAL(map, i); | |
103 | 47 | const gwmodend_t end = plug->modend; | |
104 |
3/4✓ Branch 0 taken 1 times.
✓ Branch 1 taken 46 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
|
47 | if (end && plug->self) end(gwion, plug->self); |
105 | 47 | free((m_str)VKEY(map, i)); | |
106 |
1/2✓ Branch 0 taken 47 times.
✗ Branch 1 not taken.
|
47 | if(plug->dl) DLCLOSE(plug->dl); |
107 | } | ||
108 | 707 | map_release(map); | |
109 | 707 | mp_free2(gwion->mp, sizeof(Plugs), gwion->data->plugs); | |
110 | 707 | } | |
111 | |||
112 | ✗ | ANN static void plug_free_arg(MemPool p, const Vector v) { | |
113 | ✗ | for (m_uint i = 0; i < vector_size(v); ++i) | |
114 | ✗ | free_mstr(p, (m_str)vector_at(v, i)); | |
115 | ✗ | free_vector(p, v); | |
116 | } | ||
117 | |||
118 | ✗ | ANN m_bool set_module(const struct Gwion_ *gwion, const m_str name, | |
119 | void *const ptr) { | ||
120 | ✗ | const Map map = &gwion->data->plugs->map; | |
121 | ✗ | for (m_uint j = 0; j < map_size(map); ++j) { | |
122 | ✗ | if (!strcmp(name, (m_str)VKEY(map, j))) { | |
123 | ✗ | Plug plug = (Plug)VVAL(map, j); | |
124 | ✗ | plug->self = ptr; | |
125 | ✗ | return GW_OK; | |
126 | } | ||
127 | } | ||
128 | ✗ | gw_err("module %s not found\n", name); | |
129 | ✗ | return GW_ERROR; | |
130 | } | ||
131 | |||
132 | 638 | ANN m_bool plug_run(const struct Gwion_ *gwion, const Map mod) { | |
133 | 638 | const Map map = &gwion->data->plugs->map; | |
134 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 638 times.
|
638 | for (m_uint i = 0; i < map_size(mod); ++i) { |
135 | ✗ | const m_str name = (m_str)VKEY(mod, i); | |
136 | ✗ | const m_str opt = (m_str)VVAL(mod, i); | |
137 | m_uint j; | ||
138 | ✗ | for (j = 0; j < map_size(map); ++j) { | |
139 | ✗ | if (!strcmp(name, (m_str)VKEY(map, j))) { | |
140 | ✗ | Plug plug = (Plug)VVAL(map, j); | |
141 | ✗ | const Vector arg = opt ? split_args(gwion->mp, opt) : NULL; | |
142 | ✗ | if(!plug->modini) continue; | |
143 | ✗ | plug->self = plug->modini(gwion, arg); | |
144 | ✗ | if (arg) plug_free_arg(gwion->mp, arg); | |
145 | ✗ | break; | |
146 | } | ||
147 | } | ||
148 | ✗ | if(j == map_size(map)) { | |
149 | ✗ | gw_err("{+R}[module]{0} {C}%s{0} not found\n", name); | |
150 | ✗ | return GW_ERROR; | |
151 | } | ||
152 | } | ||
153 | 638 | return GW_OK; | |
154 | } | ||
155 | |||
156 | 43 | ANN static m_bool dependencies(struct Gwion_ *gwion, const Plug plug, const loc_t loc) { | |
157 | 43 | const gwdepend_t dep = plug->depend; | |
158 | 43 | bool ret = true; | |
159 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 42 times.
|
43 | if (dep) { |
160 | 1 | m_str *const base = dep(); | |
161 | 1 | m_str * deps = base; | |
162 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | while (*deps) { |
163 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | if(plugin_ini(gwion, *deps, loc) < 0) { |
164 | 1 | gw_err("{-}[{0}{R+}missing plugin dependency{0}{-}]{0} missing {Y-}%s{0} plugin\n", *deps); | |
165 | 1 | ret = false; | |
166 | } | ||
167 | 1 | ++deps; | |
168 | } | ||
169 | } | ||
170 |
2/2✓ Branch 0 taken 42 times.
✓ Branch 1 taken 1 times.
|
43 | return ret ? GW_OK : GW_ERROR; |
171 | } | ||
172 | |||
173 | 44 | ANN static void plug_name(m_str name, const m_str iname, const m_uint size) { | |
174 | 44 | strcpy(name, iname); | |
175 |
2/2✓ Branch 0 taken 526 times.
✓ Branch 1 taken 44 times.
|
570 | for (size_t j = 0; j < size; j++) |
176 |
3/6✓ Branch 0 taken 526 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 526 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 526 times.
|
526 | if (name[j] == ':' || name[j] == '[' || name[j] == ']') name[j] = '_'; |
177 | 44 | } | |
178 | |||
179 | 42 | ANN static void set_parent(const Nspc nspc, const Gwion gwion ) { | |
180 | 42 | const Nspc user = (Nspc)vector_at(&gwion->env->scope->nspc_stack, 1); | |
181 | 42 | nspc->parent = user->parent; | |
182 | 42 | user->parent = nspc; | |
183 | 42 | } | |
184 | |||
185 | 43 | ANN static m_bool start(const Plug plug, const Gwion gwion, const m_str iname, const loc_t loc) { | |
186 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 43 times.
|
43 | if(!plug->plugin) return GW_ERROR; |
187 | 43 | const bool cdoc = gwion->data->cdoc; | |
188 | 43 | gwion->data->cdoc = 0; // check cdoc | |
189 |
2/2✓ Branch 1 taken 1 times.
✓ Branch 2 taken 42 times.
|
43 | CHECK_BB(dependencies(gwion, plug, loc)); |
190 | 42 | gwion->data->cdoc = cdoc; | |
191 | 42 | plug->nspc = new_nspc(gwion->mp, iname); | |
192 | 42 | vector_add(&gwion->data->plugs->vec, (m_uint)plug->nspc); | |
193 | 42 | set_parent(plug->nspc, gwion); | |
194 | 42 | const m_uint scope = env_push(gwion->env, NULL, plug->nspc); | |
195 | 42 | const m_str name = gwion->env->name; | |
196 | 42 | gwion->env->name = iname; | |
197 | 42 | const m_bool ret = gwi_run(gwion, plug->plugin); | |
198 | 42 | gwion->env->name = name; | |
199 | 42 | env_pop(gwion->env, scope); | |
200 | 42 | return ret; | |
201 | } | ||
202 | |||
203 | ✗ | ANN static m_bool started(const Plug plug, const Gwion gwion, const m_str iname) { | |
204 | ✗ | Nspc nspc = gwion->env->global_nspc->parent; | |
205 | ✗ | do if(!strcmp(nspc->name, iname)) | |
206 | ✗ | return GW_OK; | |
207 | ✗ | while((nspc = nspc->parent)); | |
208 | ✗ | set_parent(plug->nspc, gwion); | |
209 | ✗ | return GW_OK; | |
210 | } | ||
211 | |||
212 | 44 | ANN static m_bool _plugin_ini(struct Gwion_ *gwion, const m_str iname, const loc_t loc) { | |
213 | 44 | const Map map = &gwion->data->plugs->map; | |
214 |
2/2✓ Branch 1 taken 44 times.
✓ Branch 2 taken 1 times.
|
45 | for (m_uint i = 0; i < map_size(map); ++i) { |
215 | 44 | const Plug plug = (Plug)VVAL(map, i); | |
216 | 44 | const m_str base = (m_str)VKEY(map, i); | |
217 | 44 | const size_t size = strlen(iname); | |
218 | 44 | char name[size + 1]; | |
219 | 44 | plug_name(name, iname, size); | |
220 |
2/2✓ Branch 0 taken 43 times.
✓ Branch 1 taken 1 times.
|
44 | if (!strcmp(name, base)) { |
221 |
1/2✓ Branch 0 taken 43 times.
✗ Branch 1 not taken.
|
43 | if (!plug->nspc) return start(plug, gwion, iname, loc); |
222 | ✗ | else return started(plug, gwion, iname); | |
223 | } | ||
224 | } | ||
225 | 1 | return GW_ERROR; | |
226 | } | ||
227 | |||
228 | 44 | ANN m_bool plugin_ini(struct Gwion_ *gwion, const m_str iname, const loc_t loc) { | |
229 | 44 | const Env env = gwion->env; | |
230 |
1/2✓ Branch 1 taken 44 times.
✗ Branch 2 not taken.
|
44 | if(_plugin_ini(gwion, iname, loc) < 0) { |
231 |
3/4✓ Branch 0 taken 44 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 41 times.
|
44 | if(gwion->env->context && !gwion->env->context->error) |
232 | 3 | env_err(env, loc, "no such plugin\n"); | |
233 | 44 | return GW_ERROR; | |
234 | } | ||
235 | ✗ | return GW_OK; | |
236 | } | ||
237 | |||
238 | 69 | ANN m_bool driver_ini(const struct Gwion_ *gwion) { | |
239 | 69 | const Map map = &gwion->data->plugs->map; | |
240 | 69 | m_str dname = gwion->vm->bbq->si->arg; | |
241 | 69 | m_str opt = strchr(dname, '='); | |
242 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 67 times.
|
69 | const char c = opt ? *opt : '\0'; |
243 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 67 times.
|
69 | if (opt) *opt = '\0'; |
244 |
2/2✓ Branch 1 taken 47 times.
✓ Branch 2 taken 67 times.
|
114 | for (m_uint i = 0; i < map_size(map); ++i) { |
245 | 47 | const m_str name = (m_str)VKEY(map, i); | |
246 | 47 | printf("%s %s\n", name, dname); | |
247 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 45 times.
|
47 | if (!strcmp(name, dname)) { |
248 | 2 | puts("hey"); | |
249 | 2 | const Plug plug = (Plug)VVAL(map, i); | |
250 | 2 | const gwdriver_t drv = plug->driver; | |
251 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | if (!drv) break; |
252 | ✗ | gwion->vm->bbq->func = drv; | |
253 | ✗ | if (opt) *opt = c; | |
254 | ✗ | return GW_OK; | |
255 | } | ||
256 | } | ||
257 | 69 | gw_err("can't find driver '%s'\n", dname); | |
258 | 69 | return GW_ERROR; | |
259 | } | ||
260 | |||
261 | ✗ | ANN void *get_module(const struct Gwion_ *gwion, const m_str name) { | |
262 | ✗ | const Map map = &gwion->data->plugs->map; | |
263 | ✗ | for (m_uint i = 0; i < map_size(map); ++i) { | |
264 | ✗ | if (!strcmp(name, (m_str)VKEY(map, i))) { | |
265 | ✗ | const Plug plug = (Plug)VVAL(map, i); | |
266 | ✗ | return plug->self; | |
267 | } | ||
268 | } | ||
269 | ✗ | return NULL; | |
270 | } | ||
271 |