2 #include <glib/gstdio.h>
8 static gint
ext_native_init(int* argc
, char** argv
[], char** env
[]);
9 static void ext_native_term(void);
10 static gboolean
ext_native_check_file(const gchar
* plugin_filename
);
11 static GHashTable
* ext_native_read_plugin_metadata(const gchar
* plugin_filepath
);
12 static gint
ext_native_load_plugin(const gchar
* plugin_filepath
);
13 static void ext_native_unload_plugin(const gchar
* plugin_filepath
);
14 static void ext_native_execute_action(const gchar
* plugin_filepath
);
15 static void ext_native_call_hook(const gchar
* hook_id
, GList
* args
);
17 static gchar
* _read_data_for_keyword(const gchar
* keyword
, const gchar
* bytes
, gsize len
);
20 static GHashTable
* _loaded_plugins
= NULL
;
23 static gint
ext_native_init(int* argc
, char** argv
[], char** env
[])
25 if (!_loaded_plugins
) {
26 _loaded_plugins
= g_hash_table_new_full(g_str_hash
, g_str_equal
, g_free
, (GDestroyNotify
)g_module_close
);
31 static void ext_native_term(void)
33 if (_loaded_plugins
) {
34 ext_native_call_hook("unload", NULL
);
35 g_hash_table_unref(_loaded_plugins
);
36 _loaded_plugins
= NULL
;
40 static gboolean
ext_native_check_file(const gchar
* plugin_filename
)
42 if (g_str_has_suffix(plugin_filename
, "."G_MODULE_SUFFIX
)) {
45 if (g_str_has_suffix(plugin_filename
, ".la")) {
46 // allow a .la file only if no actual native plugin is found
47 gboolean check
= FALSE
;
48 gchar
* copy
= g_strdup(plugin_filename
);
49 gchar
* ext
= g_strrstr(copy
, ".la");
52 gchar
* native_filename
= g_strconcat(copy
, "."G_MODULE_SUFFIX
, NULL
);
53 gchar
* native_filepath
= ext_find_plugin(native_filename
);
54 check
= !native_filepath
;
55 g_free(native_filepath
);
56 g_free(native_filename
);
64 static GHashTable
* ext_native_read_plugin_metadata(const gchar
* plugin_filepath
)
66 GMappedFile
* file
= g_mapped_file_new(plugin_filepath
, FALSE
, NULL
);
68 g_printerr("mapping plugin file at %s failed\n", plugin_filepath
);
72 gchar
* bytes
= g_mapped_file_get_contents(file
);
73 gsize len
= g_mapped_file_get_length(file
);
74 if (len
== 0 || !bytes
) {
75 g_mapped_file_unref(file
);
76 g_printerr("no data in plugin file at %s failed\n", plugin_filepath
);
80 GHashTable
* table
= g_hash_table_new_full(g_str_hash
, g_str_equal
, g_free
, g_free
);
82 const gchar
* keywords
[] = { "name", "version", "abstract", "author", "website", NULL
};
84 for (it
= keywords
; *it
; ++it
) {
85 gchar
* value
= _read_data_for_keyword(*it
, bytes
, len
);
86 g_hash_table_insert(table
, g_strdup(*it
), value
);
89 g_mapped_file_unref(file
);
94 static gint
ext_native_load_plugin(const gchar
* plugin_filepath
)
96 if (g_hash_table_contains(_loaded_plugins
, plugin_filepath
)) {
100 GModule
* module = g_module_open(plugin_filepath
, G_MODULE_BIND_LAZY
| G_MODULE_BIND_LOCAL
);
102 g_printerr("Could not load native plugin: %s\n", g_module_error());
106 g_hash_table_insert(_loaded_plugins
, g_strdup(plugin_filepath
), module);
109 if (g_module_symbol(module, "load", (gpointer
)&symbol
)) {
116 static void ext_native_unload_plugin(const gchar
* plugin_filepath
)
118 GModule
* module = g_hash_table_lookup(_loaded_plugins
, plugin_filepath
);
121 if (g_module_symbol(module, "unload", (gpointer
)&symbol
)) {
126 g_hash_table_remove(_loaded_plugins
, plugin_filepath
);
129 static void ext_native_execute_action(const gchar
* plugin_filepath
)
131 GModule
* module = g_hash_table_lookup(_loaded_plugins
, plugin_filepath
);
134 if (g_module_symbol(module, "execute", (gpointer
)&symbol
)) {
140 static void ext_native_call_hook(const gchar
* hook_id
, GList
* args
)
142 gchar
* symbol_name
= g_strconcat("on_", hook_id
, NULL
);
143 void (*symbol
)(GList
*);
146 g_hash_table_iter_init(&it
, _loaded_plugins
);
149 while (g_hash_table_iter_next(&it
, NULL
, (gpointer
*)&module)) {
150 if (g_module_symbol(module, symbol_name
, (gpointer
)&symbol
)) {
159 static gchar
* _read_data_for_keyword(const gchar
* keyword
, const gchar
* bytes
, gsize len
)
163 gchar
* pattern
= g_strdup_printf("[\\x00\\t\\n ]%s\\s*[=:]\\s*([^\\x00]+)", keyword
);
164 GRegex
* r
= g_regex_new(pattern
, G_REGEX_CASELESS
, 0, NULL
);
167 GMatchInfo
* match
= NULL
;
168 if (g_regex_match_full(r
, bytes
, len
, 0, 0, &match
, NULL
)) {
169 value
= g_match_info_fetch(match
, 1);
172 g_match_info_free(match
);
179 static void _register(void) __attribute__((constructor
));
180 static void _register()
182 ext_register("native",
185 ext_native_check_file
,
186 ext_native_read_plugin_metadata
,
187 ext_native_load_plugin
,
188 ext_native_unload_plugin
,
189 ext_native_execute_action
,
190 ext_native_call_hook
);