GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/plug.c Lines: 113 113 100.0 %
Date: 2020-09-14 00:22:58 Branches: 41 42 97.6 %

Line Branch Exec Source
1
#ifndef BUILD_ON_WINDOWS
2
#include <glob.h>
3
#include <dlfcn.h>
4
#else
5
#include <windows.h>
6
#endif
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
17
typedef m_bool (*import)(Gwi);
18
typedef m_str  (*modstr)(void);
19
typedef void*  (*modini)(const struct Gwion_*, const Vector);
20
typedef void*  (*modrun)(const struct Gwion_*, void*);
21
typedef void*  (*modend)(const struct Gwion_*, void*);
22
23
struct Plug_ {
24
  m_str name;
25
  modini ini;
26
  modend end;
27
  void* self;
28
};
29
#define STR_EXPAND(tok) #tok
30
#define STR(tok) STR_EXPAND(tok)
31
#ifndef BUILD_ON_WINDOWS
32
#include <dlfcn.h>
33
#define DLOPEN(dl, b) dlopen(dl, b)
34
#define DLSYM(dl, t, a) (t)(intptr_t)dlsym(dl, STR(a));
35
#define DLCLOSE(dl) dlclose(dl);
36
#define DLERROR() dlerror()
37
#else
38
#include "windows.h"
39
#define DLOPEN(dl, b) LoadLibrary(dl)
40
#define DLSYM(dl, t, a) (t)(intptr_t)GetProcAddress(dl, STR(a));
41
#define DLCLOSE(dl) FreeLibrary(dl);
42
#define DLERROR() "plugin"
43
#endif
44
45
struct PlugHandle {
46
  MemPool mp;
47
  PlugInfo* pi;
48
  void *dl;
49
  m_str file;
50
  m_str name;
51
};
52
53
715
ANN static struct Plug_* new_plug(MemPool p, const modini ini) {
54
715
  struct Plug_ *plug = mp_calloc(p, Plug);
55
715
  plug->ini  = ini;
56
715
  return plug;
57
}
58
59
75
ANN static void plug_import(struct PlugHandle *h) {
60
75
  const import imp = DLSYM(h->dl, import, GWIMPORT_NAME);
61
75
  if(imp)
62
69
    vector_add(&h->pi->vec[GWPLUG_IMPORT], (vtype)imp);
63
75
}
64
65
75
ANN static void plug_module(struct PlugHandle *h) {
66
75
  const modini ini = DLSYM(h->dl, modini, GWMODINI_NAME);
67
75
  if(ini) {
68
4
    struct Plug_ *plug = new_plug(h->mp, ini);
69
4
    plug->name = h->name;
70
4
    plug->end  = DLSYM(h->dl, modend, GWMODEND_NAME);
71
4
    vector_add(&h->pi->vec[GWPLUG_MODULE], (vtype)plug);
72
  }
73
75
}
74
75
75
ANN static void plug_driver(struct PlugHandle *h) {
76
75
  const f_bbqset drv = DLSYM(h->dl, f_bbqset, GWDRIVER_NAME);
77
75
  if(drv)
78
6
    map_set(&h->pi->drv, (vtype)h->name, (vtype)drv);
79
75
}
80
81
75
ANN static inline m_str plug_name(struct PlugHandle *h) {
82
75
  const modstr str = DLSYM(h->dl, modstr, GWMODSTR_NAME);
83
75
  return str ? str() : NULL;
84
}
85
86
76
ANN static void plug_get(struct PlugHandle *h, const m_str c) {
87
76
  h->dl = DLOPEN(c, RTLD_LAZY | RTLD_GLOBAL);
88
76
  if(h->dl) {
89
75
    vector_add(&h->pi->vec[GWPLUG_DL], (vtype)h->dl);
90
75
    h->name = plug_name(h);
91
75
    plug_import(h);
92
75
    plug_module(h);
93
75
    plug_driver(h);
94
  } else
95
1
    gw_err(_("error in %s."), DLERROR());
96
76
}
97
98
789
ANN static void plug_get_all(struct PlugHandle *h, const m_str name) {
99
#ifndef BUILD_ON_WINDOWS
100
  glob_t results;
101
789
  if(glob(name, 0, NULL, &results))
102
713
    return;
103
152
  for(m_uint i = 0; i < results.gl_pathc; i++)
104
76
    plug_get(h, results.gl_pathv[i]);
105
76
  globfree(&results);
106
#else
107
  WIN32_FIND_DATA filedata;
108
  HANDLE file = FindFirstFile(name, &filedata);
109
  if(file == INVALID_HANDLE_VALUE)
110
    return;
111
  do {
112
    char c[PATH_MAX];
113
    strcpy(c, name);
114
    strcpy(c + strlen(name) - 4, filedata.cFileName);
115
    plug_get(h, c);
116
  } while(FindNextFile(file,&filedata));
117
  FindClose(file);
118
#endif
119
}
120
121
711
ANN2(1) static void* pp_ini(const struct Gwion_ *gwion, const Vector v) {
122
711
  pparg_run(gwion->ppa, v);
123
711
  return NULL;
124
}
125
126
711
ANN static void register_pp(const struct PlugHandle* h) {
127
711
  struct Plug_ *plug = new_plug(h->mp, pp_ini);
128
711
  plug->name = "pp";
129
711
  vector_add(&h->pi->vec[GWPLUG_MODULE], (vtype)plug);
130
711
}
131
132
711
ANN PlugInfo* new_pluginfo(MemPool p, const Vector list) {
133
711
  PlugInfo *pi = (PlugInfo*)mp_calloc(p, PlugInfo);
134
2844
  for(m_uint i = 0; i < GWPLUG_LAST; ++i)
135
2133
    vector_init(&pi->vec[i]);
136
711
  map_init(&pi->drv);
137
711
  struct PlugHandle h = { .mp=p, .pi=pi };
138
711
  register_pp(&h);
139
1500
  for(m_uint i = 0; i < vector_size(list); i++) {
140
789
    const m_str dir = (m_str)vector_at(list, i);
141
789
    char name[strlen(dir) + 6];
142
789
    sprintf(name, "%s/*.so", dir);
143
789
    plug_get_all(&h, name);
144
  }
145
711
  return pi;
146
}
147
148
710
ANN static void plug_free_module(const struct Gwion_* gwion, const Vector v) {
149
1424
  for(m_uint i = 0; i < vector_size(v); ++i) {
150
714
    struct Plug_ *plug = (struct Plug_*)vector_at(v, i);
151
714
    if(plug->end)
152
4
      plug->end(gwion, plug->self);
153
714
    mp_free(gwion->mp, Plug, plug);
154
  }
155
710
}
156
157
710
ANN static inline void plug_free_dls(const Vector v) {
158
785
  for(m_uint i = 0; i < vector_size(v); ++i)
159
75
    DLCLOSE((void*)vector_at(v, i));
160
710
}
161
162
710
void free_plug(const struct Gwion_ *gwion) {
163
710
  PlugInfo *p = gwion->data->plug;
164
710
  struct Vector_ * const v = p->vec;
165
710
  plug_free_module(gwion, &v[GWPLUG_MODULE]);
166
710
  plug_free_dls(&v[GWPLUG_DL]);
167
2840
  for(m_uint i = 0; i < GWPLUG_LAST; ++i)
168
2130
    vector_release(&v[i]);
169
710
  map_release(&p->drv);
170
710
  mp_free(gwion->mp, PlugInfo, p);
171
710
}
172
173
715
ANN static Vector get_arg(MemPool p, const m_str name, const Vector v) {
174
715
  const size_t len = strlen(name);
175
1509
  for(m_uint i = vector_size(v) + 1; --i;) {
176
81
    const m_str str = (m_str)vector_at(v, i - 1);
177
81
    if(!strncmp(name, str, len)) {
178
2
      vector_rem(v, i-1);
179
2
      const m_str arg = strchr(str, '=');
180
2
      return arg ? split_args(p, arg+1) : NULL;
181
    }
182
  }
183
713
  return NULL;
184
}
185
186
2
ANN static void plug_free_arg(MemPool p, const Vector v) {
187
7
  for(m_uint i = 0; i < vector_size(v); ++i)
188
5
    free_mstr(p, (m_str)vector_at(v, i));
189
2
  free_vector(p, v);
190
2
}
191
192
711
ANN void plug_run(const struct Gwion_ *gwion, const Vector args) {
193
711
  const Vector v = &gwion->data->plug->vec[GWPLUG_MODULE];
194
1426
  for(m_uint i = 0; i < vector_size(v); ++i) {
195
715
    struct Plug_ *plug = (struct Plug_*)vector_at(v, i);
196
715
    const Vector arg = get_arg(gwion->mp, plug->name, args);
197
715
    plug->self = plug->ini(gwion, arg);
198
715
    if(arg)
199
2
      plug_free_arg(gwion->mp, arg);
200
  }
201
711
}
202
203
2
ANN void* get_module(const struct Gwion_ *gwion, const m_str name) {
204
2
  const Vector v = &gwion->data->plug->vec[GWPLUG_MODULE];
205
5
  for(m_uint i = 0; i < vector_size(v); ++i) {
206
4
    struct Plug_ *plug = (struct Plug_*)vector_at(v, i);
207
4
    if(!strcmp(name, plug->name))
208
1
      return plug->self;
209
  }
210
1
  return NULL;
211
}