Heraia  0.1.8
plugin.c
Go to the documentation of this file.
1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2 /*
3  * plugin.c
4  * heraia - an hexadecimal file editor and analyser based on ghex
5  *
6  * (C) Copyright 2007 - 2011 Olivier Delhomme
7  * e-mail : heraia@delhomme.org
8  * URL : http://heraia.tuxfamily.org
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2, or (at your option)
13  * any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23  */
24 /**
25  * @file plugin.c
26  * This file contains all the stuff that is dedicated to plugins (loading,
27  * instanciating, initializing and so on)
28  */
29 #include <libheraia.h>
30 
32  const gchar *full_filename, const gchar *filename);
34 static void init_plugin(heraia_struct_t *main_struct, heraia_plugin_t *plugin, const gchar *filename, guint plugins_nb);
35 static void load_one_plugin(heraia_struct_t *main_struct, const gchar *filename, guint plugins_nb);
36 
37 
38 /**
39  * @fn gboolean plugin_capable(void)
40  * Says whether the system can handle plugins (or not)
41  * @return Returns TRUE if the system is able to handle plugins, FALSE otherwise
42  */
43 gboolean plugin_capable(void)
44 {
45  return g_module_supported();
46 }
47 
48 
49 /**
50  * @fn new_plugin(void)
51  * Creates a new empty plugin
52  * it may be initialised by
53  * the plugin itself !
54  * @return Returns a newly created heraia_plugin_t plugin structure
55  */
57 {
58  heraia_plugin_t *new = NULL;
59 
60  new = (heraia_plugin_t *) g_malloc0(sizeof(heraia_plugin_t));
61 
62  new->state = PLUGIN_STATE_NEW; /* The plugin state */
63  new->handle = NULL; /* The module handle */
64  new->path = NULL; /* The path to the plugin */
65  new->filename = NULL;
66  new->info = (plugin_info_t *) g_malloc0(sizeof(plugin_info_t)); /* The plugin information */
67  new->filter = (plugin_filter_t *) g_malloc0(sizeof(plugin_filter_t)); /* The plugin filter */
68  new->error = NULL;
69  new->extra = NULL; /* Plugin-specific data */
70 
71  /* Called when the application initialy starts up */
72  new->init_proc = NULL;
73  /* Called when the application exits */
74  new->quit_proc = NULL;
75  /* Called to run a miscellaneous thing everytime the plugin is called */
76  new->run_proc = NULL;
77 
78  return new;
79 
80 }
81 
82 
83 /**
84  * @fn free_plugin(heraia_plugin_t *plugin)
85  * free an unused plugin use with caution
86  * @param plugin : A created a malloc'ed plugin
87  */
89 {
90  if (plugin != NULL)
91  {
92  if (plugin->handle != NULL)
93  {
94  g_module_close(plugin->handle);
95  }
96 
97  if (plugin->info != NULL)
98  {
99  g_free(plugin->info->name);
100  g_free(plugin->info->version);
101  g_free(plugin->info->summary);
102  g_free(plugin->info->description);
103  g_free(plugin->info->author);
104  g_free(plugin->info->homepage);
105  g_free(plugin->info);
106  }
107 
108  if (plugin->filter != NULL)
109  {
110  g_free(plugin->filter->extensions);
111  g_free(plugin->filter);
112  }
113 
114  g_free(plugin->path);
115  g_free(plugin->filename);
116  g_free(plugin->error);
117  g_free(plugin->extra);
118 
119  g_free(plugin);
120  }
121 }
122 
123 
124 /**
125  * @fn heraia_plugin_t *get_plugin_handle(heraia_struct_t *main_struct, heraia_plugin_t *plugin, const gchar *full_filename, const gchar *filename)
126  * Here we try to get a handle for the Gmodule referenced by full_filename
127  * @param main_struct : main structure
128  * @param plugin : the plugin we try to get a handle for
129  * @param full_filename : the full filename (includes path) to the compiled
130  * plugin
131  * @param filename : the filename (without the path -> used for fancy log
132  * reporting)
133  * @return Returns the modified plugin structure eventually with a handle !
134  */
136  const gchar *full_filename, const gchar *filename)
137 {
138  if (plugin != NULL)
139  {
140 
141  plugin->handle = g_module_open(full_filename, G_MODULE_BIND_MASK);
142 
143  if (plugin->handle == NULL)
144  {
145  log_message(main_struct, G_LOG_LEVEL_WARNING, Q_("Could not open plugin %s - %s"), filename, g_module_error());
146  }
147  }
148 
149  return plugin;
150 }
151 
152 
153 /**
154  * @fn heraia_plugin_t *get_plugin_init_symbol(heraia_struct_t *main_struct, heraia_plugin_t *plugin)
155  * If the handle is ok, we want to have the heraia_plugin_init function (to call it)
156  * in order to init the plugin (by itself)
157  * @param main_struct : main structure
158  * @param plugin : the plugin to look for its init function
159  */
161 {
162  heraia_plugin_t *(*heraia_plugin_init)(heraia_plugin_t *);
163  gboolean get_symbol = FALSE;
164 
165  if (plugin != NULL && plugin->handle != NULL)
166  {
167  get_symbol = g_module_symbol(plugin->handle, "heraia_plugin_init", (gpointer *)(&heraia_plugin_init));
168 
169  if (get_symbol == FALSE)
170  {
171  log_message(main_struct, G_LOG_LEVEL_WARNING, "%s", g_module_error());
172  free_plugin(plugin);
173  return NULL;
174  }
175  else
176  {
177  /* the plugins inits itself here */
178  plugin = heraia_plugin_init(plugin);
179  return plugin;
180  }
181  }
182  else
183  {
184  free_plugin(plugin);
185  return NULL;
186  }
187 }
188 
189 
190 /**
191  * @fn void init_plugin(heraia_struct_t *main_struct, heraia_plugin_t *plugin, const gchar *filename, guint plugins_nb)
192  * finalising initialisation : if everything went fine, the plugin is added to the
193  * plugin list and a menu entry is created in the Plugins menu
194  * @param main_struct : main structure
195  * @param plugin : the plugin that was initialized
196  * @param filename : filename of the plugin itself
197  * @param plugins_nb : a number that will become the id of that plugin
198  */
199 static void init_plugin(heraia_struct_t *main_struct, heraia_plugin_t *plugin, const gchar *filename, guint plugins_nb)
200 {
201  if (plugin != NULL)
202  {
203  plugin->info->id = plugins_nb;
204  main_struct->plugins_list = g_list_append(main_struct->plugins_list, plugin);
205  log_message(main_struct, G_LOG_LEVEL_INFO, Q_("plugin %s loaded."), filename);
206 
207  plugin->init_proc(main_struct);
208 
209  if (plugin->info->type == HERAIA_PLUGIN_ACTION)
210  {
211  add_entry_to_plugins_menu(main_struct, plugin);
212  }
213 
214  }
215  }
216 
217 
218 /**
219  * @fn void load_one_plugin(heraia_struct_t *main_struct, const gchar *filename, guint plugins_nb)
220  * Here we manage to load one plugin at a time (and this is really enough !)
221  * @param main_struct : main structure
222  * @param filename : filename of the plugin that we want to load
223  * @param plugins_nb : a number that will be the id of that plugin
224  */
225 static void load_one_plugin(heraia_struct_t *main_struct, const gchar *filename, guint plugins_nb)
226 {
227  const gchar *full_filename = NULL;
228  heraia_plugin_t *plugin = NULL;
229  gchar *ext = g_strdup_printf(".%s", G_MODULE_SUFFIX); /* system dependent suffix */
230 
231  full_filename = g_build_filename(PLUGINS_DIR, filename, NULL);
232 
233  log_message(main_struct, G_LOG_LEVEL_DEBUG, "full_filename = %s ; ext = %s ; filename = %s", full_filename, ext, filename);
234 
235  /* Make sure we do load the module named .so, .dll or .sl depending on the OS type */
236  if ( (g_file_test(full_filename, G_FILE_TEST_IS_DIR) == FALSE) &&
237  (strcmp(strrchr(filename, '.'), ext) == 0)
238  )
239  {
240  plugin = new_plugin();
241  plugin->path = g_strdup_printf("%s", PLUGINS_DIR);
242  plugin->filename = g_strdup_printf("%s", filename);
243 
244  plugin = get_plugin_handle(main_struct, plugin, full_filename, filename);
245  plugin = get_plugin_init_symbol(main_struct, plugin);
246 
247  init_plugin(main_struct, plugin, filename, plugins_nb);
248  }
249 }
250 
251 
252 /**
253  * @fn load_plugins(heraia_struct_t *main_struct)
254  * looks at the plugins dir(s) and loads
255  * the needed plugins (all ;-) (one at a time !!)
256  * @param main_struct : main structure
257  */
258 void load_plugins(heraia_struct_t *main_struct)
259 {
260  GDir *plugins_dir = NULL;
261  GError *error = NULL;
262  const gchar *filename = NULL;
263  unsigned int plugins_nb = 0;
264 
265  /**
266  * @todo Register all shared plugins (plugins_dir) (-DPLUGINS_DIR)
267  * This may be a config file option later ... */
268  plugins_dir = g_dir_open(PLUGINS_DIR, 0, &error);
269 
270  if (plugins_dir == NULL) /* error while openning the plugins directory */
271  {
272  log_message(main_struct, G_LOG_LEVEL_WARNING, "%s", error->message);
273  g_error_free(error);
274  }
275  else
276  {
277  while ((filename = g_dir_read_name(plugins_dir)) != NULL)
278  {
279  if (g_str_has_prefix(filename, "libheraia") == FALSE)
280  {
281  load_one_plugin(main_struct, filename, ++plugins_nb);
282  }
283  }
284  g_dir_close(plugins_dir);
285  }
286 }
287 
288 
289 /**
290  * @fn add_entry_to_plugins_menu(heraia_struct_t *main_struct, heraia_plugin_t *plugin)
291  * adds a menu entry to the plugin menu
292  * adds a signal handler when the menu is toggled
293  * @param main_struct : main structure
294  * @param plugin : a plugin to add to the plugin's menu
295  */
297 {
298  if (plugin != NULL && plugin->info != NULL && plugin->info->name != NULL)
299  {
300  /* Creates the menu entry (a GtkCheckMenuItem) */
301  plugin->cmi_entry = GTK_CHECK_MENU_ITEM(gtk_check_menu_item_new_with_label(plugin->info->name));
302 
303  /* Append this menu entry to the menu */
304  gtk_menu_shell_append(GTK_MENU_SHELL(heraia_get_widget(main_struct->xmls->main, "plugins_menu")), GTK_WIDGET(plugin->cmi_entry));
305 
306  /* Connect the menu entry toggled signal to the run_proc function of the plugin */
307  g_signal_connect(G_OBJECT(plugin->cmi_entry), "toggled", G_CALLBACK(plugin->run_proc), main_struct);
308 
309  /* Shows the menu entry (so we may toggle it!) */
310  gtk_widget_show(GTK_WIDGET(plugin->cmi_entry));
311  }
312 }
313 
314 
315 /**
316  * @fn heraia_plugin_t *find_plugin_by_name(GList *plugins_list, gchar *name)
317  * Finds the desired plugin by its name and return the plugin structure or NULL
318  * @param plugins_list : list of all available plugins
319  * @param name : plugin's name we're looking for
320  * @return Returns a heraia_plugin_t that correspond to the plugin or NULL if
321  * no plugin was found with that name
322  */
323 heraia_plugin_t *find_plugin_by_name(GList *plugins_list, gchar *name)
324 {
325  GList *list = g_list_first(plugins_list);
326  heraia_plugin_t *plugin = NULL;
327  gboolean stop = FALSE;
328 
329  while (list != NULL && stop != TRUE)
330  {
331  plugin = (heraia_plugin_t *) list->data;
332  if (plugin != NULL && plugin->info != NULL)
333  {
334  if (strcmp(plugin->info->name, name) == 0)
335  stop = TRUE;
336  }
337  list = list->next;
338  }
339 
340  if (stop == TRUE)
341  return plugin;
342  else
343  return NULL;
344 }
345 
346 
347 /**
348  * @fn load_plugin_xml(heraia_struct_t *main_struct, heraia_plugin_t *plugin)
349  * Loads the xml's definition file that describes the plugin (.gtkbuilder suffix)
350  * tries the paths found in the location_list
351  * @param main_struct : main structure
352  * @param plugin : plugin for whom we want to load it's GtkBuilder XML definition
353  * file
354  * @return Returns TRUE if everything went ok, FALSE otherwise
355  */
356 gboolean load_plugin_xml(heraia_struct_t *main_struct, heraia_plugin_t *plugin)
357 {
358  gchar *filename = NULL;
359 
360  filename = g_strdup_printf("%s.gtkbuilder", plugin->info->name);
361 
362  plugin->xml = load_xml_file(main_struct->location_list, filename);
363 
364  g_free(filename);
365 
366  if (plugin->xml == NULL)
367  return FALSE;
368  else
369  return TRUE;
370 }
371 
372 
373 /**
374  * @fn refresh_all_plugins(heraia_struct_t *main_struct)
375  * To help the main program to send events to the plugins
376  * @param main_struct : main structure
377  */
379 {
380 
381  GList *list = g_list_first(main_struct->plugins_list);
382  heraia_plugin_t *plugin = NULL;
383 
384  while (list != NULL)
385  {
386  plugin = (heraia_plugin_t *) list->data;
387 
388  if (plugin != NULL && plugin->refresh_proc != NULL)
389  { /* Beware : here a tricky thing that works ! */
390  plugin->refresh_proc(main_struct, list->data);
391  }
392 
393  list = list->next;
394  }
395 }
This is the main structure.
Definition: libheraia.h:332
RefreshProc refresh_proc
Called when the cursor changes it's position.
Definition: plugin.h:155
void load_plugins(heraia_struct_t *main_struct)
looks at the plugins dir(s) and loads the needed plugins (all ;-) (one at a time !!) ...
Definition: plugin.c:258
gboolean load_plugin_xml(heraia_struct_t *main_struct, heraia_plugin_t *plugin)
Loads the xml's definition file that describes the plugin (.gtkbuilder suffix) tries the paths found ...
Definition: plugin.c:356
void refresh_all_plugins(heraia_struct_t *main_struct)
To help the main program to send events to the plugins.
Definition: plugin.c:378
void log_message(heraia_struct_t *main_struct, GLogLevelFlags log_level, const char *format,...)
A function that helps logging a message a the specified level.
Definition: log.c:195
heraia_plugin_t * new_plugin(void)
Creates a new empty plugin it may be initialised by the plugin itself !
Definition: plugin.c:56
GtkBuilder * load_xml_file(GList *location_list, gchar *filename)
loads the GtkBuilder xml file ('filename') that describes an interface, tries all the paths defined i...
Definition: heraia_io.c:145
GtkBuilder * xml
Eventually the plugin's GtkBuilder XML interface.
Definition: plugin.h:158
static heraia_plugin_t * get_plugin_init_symbol(heraia_struct_t *main_struct, heraia_plugin_t *plugin)
If the handle is ok, we want to have the heraia_plugin_init function (to call it) in order to init th...
Definition: plugin.c:160
InitProc init_proc
Called when the application initialy starts up.
Definition: plugin.h:152
plugin_info_t * info
The plugin information.
Definition: plugin.h:147
static void load_one_plugin(heraia_struct_t *main_struct, const gchar *filename, guint plugins_nb)
Here we manage to load one plugin at a time (and this is really enough !)
Definition: plugin.c:225
RunProc run_proc
Called to run an interface everytime the plugin is called.
Definition: plugin.h:154
xml_t * xmls
All the xmls used in the program, loaded at running time.
Definition: libheraia.h:337
char * version
Definition: plugin.h:128
gboolean plugin_capable(void)
Says whether the system can handle plugins (or not)
Definition: plugin.c:43
heraia_plugin_t * find_plugin_by_name(GList *plugins_list, gchar *name)
Finds the desired plugin by its name and return the plugin structure or NULL.
Definition: plugin.c:323
GModule * handle
The module handle.
Definition: plugin.h:144
char * description
Definition: plugin.h:130
void * extra
Plugin-specific data.
Definition: plugin.h:150
char * extensions
Definition: plugin.h:109
char * summary
Definition: plugin.h:129
PluginType type
Definition: plugin.h:123
heraia_plugin_t * heraia_plugin_init(heraia_plugin_t *plugin)
Initialisation plugin function called when the plugin is loaded (some sort of pre-init) ...
Definition: stat.c:64
static void init_plugin(heraia_struct_t *main_struct, heraia_plugin_t *plugin, const gchar *filename, guint plugins_nb)
finalising initialisation : if everything went fine, the plugin is added to the plugin list and a men...
Definition: plugin.c:199
char * name
Definition: plugin.h:127
GtkBuilder * main
the main interface xml description
Definition: libheraia.h:222
PluginState state
The state of the plugin.
Definition: plugin.h:143
char * author
Definition: plugin.h:131
Complete plugin structure.
Definition: plugin.h:141
GList * plugins_list
A list of plugins.
Definition: libheraia.h:340
This file contains all the definitions and includes all other .h files.
Detailed information about a plugin.
Definition: plugin.h:120
GtkWidget * heraia_get_widget(GtkBuilder *xml, gchar *widget_name)
This is a wrapper to the GtkBuilder xml get widget.
Definition: heraia_ui.c:2184
char * homepage
Definition: plugin.h:132
unsigned int id
Definition: plugin.h:125
char * error
last error message
Definition: plugin.h:149
Action plugin.
Definition: plugin.h:47
static heraia_plugin_t * get_plugin_handle(heraia_struct_t *main_struct, heraia_plugin_t *plugin, const gchar *full_filename, const gchar *filename)
Here we try to get a handle for the Gmodule referenced by full_filename.
Definition: plugin.c:135
plugin_filter_t * filter
The plugin filter.
Definition: plugin.h:148
void free_plugin(heraia_plugin_t *plugin)
free an unused plugin use with caution
Definition: plugin.c:88
char * filename
Filename of the plugin.
Definition: plugin.h:146
char * path
The path to the plugin.
Definition: plugin.h:145
GtkCheckMenuItem * cmi_entry
The CheckMenuItem that may be created in the heraia interface.
Definition: plugin.h:157
GList * location_list
this is the location list where we store some paths
Definition: libheraia.h:339
void add_entry_to_plugins_menu(heraia_struct_t *main_struct, heraia_plugin_t *plugin)
adds a menu entry to the plugin menu adds a signal handler when the menu is toggled ...
Definition: plugin.c:296