plugin.c

Go to the documentation of this file.
00001 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
00002 /*
00003  *  plugin.c
00004  *  heraia - an hexadecimal file editor and analyser based on ghex
00005  *
00006  *  (C) Copyright 2007 - 2011 Olivier Delhomme
00007  *  e-mail : heraia@delhomme.org
00008  *  URL    : http://heraia.tuxfamily.org
00009  *
00010  *  This program is free software; you can redistribute it and/or modify
00011  *  it under the terms of the GNU General Public License as published by
00012  *  the Free Software Foundation; either version 2, or  (at your option)
00013  *  any later version.
00014  *
00015  *  This program is distributed in the hope that it will be useful,
00016  *  but WITHOUT ANY WARRANTY;  without even the implied warranty of
00017  *  MERCHANTABILITY  or  FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  *  GNU General Public License for more details.
00019  *
00020  *  You should have received a copy of the GNU General Public License
00021  *  along with this program; if not, write to the Free Software
00022  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00023  */
00024 /**
00025  * @file plugin.c
00026  * This file contains all the stuff that is dedicated to plugins (loading,
00027  * instanciating, initializing and so on)
00028  */
00029 #include <libheraia.h>
00030 
00031 static heraia_plugin_t *get_plugin_handle(heraia_struct_t *main_struct, heraia_plugin_t *plugin,
00032                                           const gchar *full_filename, const gchar *filename);
00033 static heraia_plugin_t *get_plugin_init_symbol(heraia_struct_t *main_struct, heraia_plugin_t *plugin);
00034 static void init_plugin(heraia_struct_t *main_struct, heraia_plugin_t *plugin, const gchar *filename, guint plugins_nb);
00035 static void load_one_plugin(heraia_struct_t *main_struct, const gchar *filename, guint plugins_nb);
00036 
00037 
00038 /**
00039  * @fn gboolean plugin_capable(void)
00040  * Says whether the system can handle plugins (or not)
00041  * @return Returns TRUE if the system is able to handle plugins, FALSE otherwise
00042  */
00043 gboolean plugin_capable(void)
00044 {
00045     return g_module_supported();
00046 }
00047 
00048 
00049 /**
00050  * @fn new_plugin(void)
00051  *  Creates a new empty plugin
00052  *  it may be initialised by
00053  *  the plugin itself !
00054  * @return Returns a newly created heraia_plugin_t plugin structure
00055  */
00056 heraia_plugin_t *new_plugin(void)
00057 {
00058     heraia_plugin_t *new = NULL;
00059 
00060     new = (heraia_plugin_t *) g_malloc0(sizeof(heraia_plugin_t));
00061 
00062     new->state = PLUGIN_STATE_NEW; /* The plugin state         */
00063     new->handle = NULL;            /* The module handle        */
00064     new->path = NULL;              /* The path to the plugin   */
00065     new->filename = NULL;
00066     new->info = (plugin_info_t *) g_malloc0(sizeof(plugin_info_t));       /* The plugin information   */
00067     new->filter = (plugin_filter_t *) g_malloc0(sizeof(plugin_filter_t)); /* The plugin filter        */
00068     new->error = NULL;
00069     new->extra = NULL;      /* Plugin-specific data     */
00070 
00071     /* Called when the application initialy starts up */
00072     new->init_proc = NULL;
00073     /* Called when the application exits */
00074     new->quit_proc = NULL;
00075     /* Called to run a miscellaneous thing everytime the plugin is called */
00076     new->run_proc = NULL;
00077 
00078     return new;
00079 
00080 }
00081 
00082 
00083 /**
00084  * @fn free_plugin(heraia_plugin_t *plugin)
00085  *  free an unused plugin use with caution
00086  * @param plugin : A created a malloc'ed plugin
00087  */
00088 void free_plugin(heraia_plugin_t *plugin)
00089 {
00090     if (plugin != NULL)
00091         {
00092             if (plugin->handle != NULL)
00093                 {
00094                     g_module_close(plugin->handle);
00095                 }
00096 
00097             if (plugin->info != NULL)
00098                 {
00099                     g_free(plugin->info->name);
00100                     g_free(plugin->info->version);
00101                     g_free(plugin->info->summary);
00102                     g_free(plugin->info->description);
00103                     g_free(plugin->info->author);
00104                     g_free(plugin->info->homepage);
00105                     g_free(plugin->info);
00106                 }
00107 
00108             if (plugin->filter != NULL)
00109                 {
00110                     g_free(plugin->filter->extensions);
00111                     g_free(plugin->filter);
00112                 }
00113 
00114             g_free(plugin->path);
00115             g_free(plugin->filename);
00116             g_free(plugin->error);
00117             g_free(plugin->extra);
00118 
00119             g_free(plugin);
00120         }
00121 }
00122 
00123 
00124 /**
00125  * @fn heraia_plugin_t *get_plugin_handle(heraia_struct_t *main_struct, heraia_plugin_t *plugin, const gchar *full_filename, const gchar *filename)
00126  *  Here we try to get a handle for the Gmodule referenced by full_filename
00127  * @param main_struct : main structure
00128  * @param plugin : the plugin we try to get a handle for
00129  * @param full_filename : the full filename (includes path) to the compiled
00130  *                        plugin
00131  * @param filename : the filename (without the path -> used for fancy log
00132  *                                 reporting)
00133  * @return Returns the modified plugin structure eventually with a handle !
00134  */
00135 static heraia_plugin_t *get_plugin_handle(heraia_struct_t *main_struct, heraia_plugin_t *plugin,
00136                                           const gchar *full_filename, const gchar *filename)
00137 {
00138     if (plugin != NULL)
00139         {
00140 
00141             plugin->handle = g_module_open(full_filename, G_MODULE_BIND_MASK);
00142 
00143             if (plugin->handle == NULL)
00144                 {
00145                     log_message(main_struct, G_LOG_LEVEL_WARNING, Q_("Could not open plugin %s - %s"), filename, g_module_error());
00146                 }
00147         }
00148 
00149     return plugin;
00150 }
00151 
00152 
00153 /**
00154  * @fn heraia_plugin_t *get_plugin_init_symbol(heraia_struct_t *main_struct, heraia_plugin_t *plugin)
00155  *  If the handle is ok, we want to have the heraia_plugin_init function (to call it)
00156  *  in order to init the plugin (by itself)
00157  * @param main_struct : main structure
00158  * @param plugin : the plugin to look for its init function
00159  */
00160 static heraia_plugin_t *get_plugin_init_symbol(heraia_struct_t *main_struct, heraia_plugin_t *plugin)
00161 {
00162     heraia_plugin_t *(*heraia_plugin_init)(heraia_plugin_t *);
00163     gboolean get_symbol = FALSE;
00164 
00165     if (plugin != NULL && plugin->handle != NULL)
00166         {
00167             get_symbol = g_module_symbol(plugin->handle, "heraia_plugin_init", (gpointer *)(&heraia_plugin_init));
00168 
00169             if (get_symbol == FALSE)
00170                 {
00171                     log_message(main_struct, G_LOG_LEVEL_WARNING, "%s", g_module_error());
00172                     free_plugin(plugin);
00173                     return NULL;
00174                 }
00175             else
00176                 {
00177                     /* the plugins inits itself here */
00178                     plugin = heraia_plugin_init(plugin);
00179                     return plugin;
00180                 }
00181         }
00182     else
00183         {
00184             free_plugin(plugin);
00185             return NULL;
00186         }
00187 }
00188 
00189 
00190 /**
00191  * @fn void init_plugin(heraia_struct_t *main_struct, heraia_plugin_t *plugin, const gchar *filename, guint plugins_nb)
00192  *  finalising initialisation : if everything went fine, the plugin is added to the
00193  *  plugin list and a menu entry is created in the Plugins menu
00194  * @param main_struct : main structure
00195  * @param plugin : the plugin that was initialized
00196  * @param filename : filename of the plugin itself
00197  * @param plugins_nb : a number that will become the id of that plugin
00198  */
00199 static void init_plugin(heraia_struct_t *main_struct, heraia_plugin_t *plugin, const gchar *filename, guint plugins_nb)
00200 {
00201     if (plugin != NULL)
00202         {
00203             plugin->info->id = plugins_nb;
00204             main_struct->plugins_list = g_list_append(main_struct->plugins_list, plugin);
00205             log_message(main_struct, G_LOG_LEVEL_INFO, Q_("plugin %s loaded."), filename);
00206 
00207             plugin->init_proc(main_struct);
00208 
00209             if (plugin->info->type == HERAIA_PLUGIN_ACTION)
00210                 {
00211                     add_entry_to_plugins_menu(main_struct, plugin);
00212                 }
00213 
00214         }
00215  }
00216 
00217 
00218 /**
00219  * @fn void load_one_plugin(heraia_struct_t *main_struct, const gchar *filename, guint plugins_nb)
00220  *  Here we manage to load one plugin at a time (and this is really enough !)
00221  * @param main_struct : main structure
00222  * @param filename : filename of the plugin that we want to load
00223  * @param plugins_nb : a number that will be the id of that plugin
00224  */
00225 static void load_one_plugin(heraia_struct_t *main_struct, const gchar *filename, guint plugins_nb)
00226 {
00227     const gchar *full_filename = NULL;
00228     heraia_plugin_t *plugin = NULL;
00229     gchar *ext = g_strdup_printf(".%s", G_MODULE_SUFFIX); /* system dependent suffix */
00230 
00231     full_filename = g_build_filename(PLUGINS_DIR, filename, NULL);
00232 
00233     log_message(main_struct, G_LOG_LEVEL_DEBUG, "full_filename = %s ; ext = %s ; filename = %s", full_filename, ext, filename);
00234 
00235     /* Make sure we do load the module named .so, .dll or .sl depending on the OS type */
00236     if ( (g_file_test(full_filename, G_FILE_TEST_IS_DIR) == FALSE) &&
00237          (strcmp(strrchr(filename, '.'), ext) == 0)
00238          )
00239         {
00240             plugin = new_plugin();
00241             plugin->path = g_strdup_printf("%s", PLUGINS_DIR);
00242             plugin->filename = g_strdup_printf("%s", filename);
00243 
00244             plugin = get_plugin_handle(main_struct, plugin, full_filename, filename);
00245             plugin = get_plugin_init_symbol(main_struct, plugin);
00246 
00247             init_plugin(main_struct, plugin, filename, plugins_nb);
00248         }
00249 }
00250 
00251 
00252 /**
00253  * @fn load_plugins(heraia_struct_t *main_struct)
00254  *  looks at the plugins dir(s) and loads
00255  *  the needed plugins (all ;-) (one at a time !!)
00256  * @param main_struct : main structure
00257  */
00258 void load_plugins(heraia_struct_t *main_struct)
00259 {
00260     GDir *plugins_dir = NULL;
00261     GError *error = NULL;
00262     const gchar *filename = NULL;
00263     unsigned int plugins_nb = 0;
00264 
00265     /**
00266      * @todo Register all shared plugins (plugins_dir) (-DPLUGINS_DIR)
00267      * This may be a config file option later ...                      */
00268     plugins_dir = g_dir_open(PLUGINS_DIR, 0, &error);
00269 
00270     if (plugins_dir == NULL) /* error while openning the plugins directory */
00271         {
00272             log_message(main_struct, G_LOG_LEVEL_WARNING, "%s", error->message);
00273             g_error_free(error);
00274         }
00275     else
00276         {
00277             while ((filename = g_dir_read_name(plugins_dir)) != NULL)
00278                 {
00279                     if (g_str_has_prefix(filename, "libheraia") == FALSE)
00280                     {
00281                         load_one_plugin(main_struct, filename, ++plugins_nb);
00282                     }
00283                 }
00284             g_dir_close(plugins_dir);
00285         }
00286 }
00287 
00288 
00289 /**
00290  * @fn add_entry_to_plugins_menu(heraia_struct_t *main_struct, heraia_plugin_t *plugin)
00291  *  adds a menu entry to the plugin menu
00292  *  adds a signal handler when the menu is toggled
00293  * @param main_struct : main structure
00294  * @param plugin : a plugin to add to the plugin's menu
00295  */
00296 void add_entry_to_plugins_menu(heraia_struct_t *main_struct, heraia_plugin_t *plugin)
00297 {
00298     if (plugin != NULL && plugin->info != NULL && plugin->info->name != NULL)
00299         {
00300             /* Creates the menu entry (a GtkCheckMenuItem) */
00301             plugin->cmi_entry = GTK_CHECK_MENU_ITEM(gtk_check_menu_item_new_with_label(plugin->info->name));
00302 
00303             /* Append this menu entry to the menu */
00304             gtk_menu_shell_append(GTK_MENU_SHELL(heraia_get_widget(main_struct->xmls->main, "plugins_menu")), GTK_WIDGET(plugin->cmi_entry));
00305 
00306             /* Connect the menu entry toggled signal to the run_proc function of the plugin */
00307             g_signal_connect(G_OBJECT(plugin->cmi_entry), "toggled", G_CALLBACK(plugin->run_proc), main_struct);
00308 
00309             /* Shows the menu entry (so we may toggle it!) */
00310             gtk_widget_show(GTK_WIDGET(plugin->cmi_entry));
00311         }
00312 }
00313 
00314 
00315 /**
00316  * @fn heraia_plugin_t *find_plugin_by_name(GList *plugins_list, gchar *name)
00317  *  Finds the desired plugin by its name and return the plugin structure or NULL
00318  * @param plugins_list : list of all available plugins
00319  * @param name : plugin's name we're looking for
00320  * @return Returns a heraia_plugin_t that correspond to the plugin or NULL if
00321  *         no plugin was found with that name
00322  */
00323 heraia_plugin_t *find_plugin_by_name(GList *plugins_list, gchar *name)
00324 {
00325     GList *list = g_list_first(plugins_list);
00326     heraia_plugin_t *plugin = NULL;
00327     gboolean stop = FALSE;
00328 
00329     while (list != NULL && stop != TRUE)
00330         {
00331             plugin = (heraia_plugin_t *) list->data;
00332             if (plugin != NULL && plugin->info != NULL)
00333                 {
00334                     if (strcmp(plugin->info->name, name) == 0)
00335                         stop = TRUE;
00336                 }
00337             list = list->next;
00338         }
00339 
00340     if (stop == TRUE)
00341         return plugin;
00342     else
00343         return NULL;
00344 }
00345 
00346 
00347 /**
00348  * @fn load_plugin_xml(heraia_struct_t *main_struct, heraia_plugin_t *plugin)
00349  *  Loads the xml's definition file that describes the plugin (.gtkbuilder suffix)
00350  *  tries the paths found in the location_list
00351  * @param main_struct : main structure
00352  * @param plugin : plugin for whom we want to load it's GtkBuilder XML definition
00353  *        file
00354  * @return Returns TRUE if everything went ok, FALSE otherwise
00355  */
00356 gboolean load_plugin_xml(heraia_struct_t *main_struct, heraia_plugin_t *plugin)
00357 {
00358     gchar *filename = NULL;
00359 
00360     filename = g_strdup_printf("%s.gtkbuilder", plugin->info->name);
00361 
00362     plugin->xml = load_xml_file(main_struct->location_list, filename);
00363 
00364     g_free(filename);
00365 
00366     if (plugin->xml == NULL)
00367         return FALSE;
00368     else
00369         return TRUE;
00370 }
00371 
00372 
00373 /**
00374  * @fn refresh_all_plugins(heraia_struct_t *main_struct)
00375  *  To help the main program to send events to the plugins
00376  * @param main_struct : main structure
00377  */
00378 void refresh_all_plugins(heraia_struct_t *main_struct)
00379 {
00380 
00381     GList *list = g_list_first(main_struct->plugins_list);
00382     heraia_plugin_t *plugin = NULL;
00383 
00384     while (list != NULL)
00385         {
00386             plugin = (heraia_plugin_t *) list->data;
00387 
00388             if (plugin != NULL && plugin->refresh_proc != NULL)
00389                 { /* Beware : here a tricky thing that works ! */
00390                     plugin->refresh_proc(main_struct, list->data);
00391                 }
00392 
00393             list = list->next;
00394         }
00395 }
Generated on Mon May 2 21:04:49 2011 for Heraia by  doxygen 1.6.3