Gwion coverage report


Directory: src/
File: src/plug.c
Date: 2023-01-30 18:32:28
Exec Total Coverage
Lines: 135 180 75.0%
Functions: 13 17 76.5%
Branches: 50 90 55.6%

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