Added missing launcher
[mupen64plus-pandora.git] / source / front-end / src / plugin.c
1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2  *   Mupen64plus-ui-console - plugin.c                                     *
3  *   Mupen64Plus homepage: http://code.google.com/p/mupen64plus/           *
4  *   Copyright (C) 2009 Richard42                                          *
5  *                                                                         *
6  *   This program is free software; you can redistribute it and/or modify  *
7  *   it under the terms of the GNU General Public License as published by  *
8  *   the Free Software Foundation; either version 2 of the License, or     *
9  *   (at your option) any later version.                                   *
10  *                                                                         *
11  *   This program is distributed in the hope that it will be useful,       *
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
14  *   GNU General Public License for more details.                          *
15  *                                                                         *
16  *   You should have received a copy of the GNU General Public License     *
17  *   along with this program; if not, write to the                         *
18  *   Free Software Foundation, Inc.,                                       *
19  *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.          *
20  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
21
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25
26 #include "m64p_types.h"
27 #include "m64p_common.h"
28 #include "core_interface.h"
29 #include "osal_dynamiclib.h"
30 #include "osal_files.h"
31 #include "plugin.h"
32 #include "main.h"  /* for the debug callback function */
33 #include "version.h"
34
35 /* global variables */
36 const char *g_PluginDir = NULL;
37 const char *g_GfxPlugin = NULL;        // pointer to graphics plugin specified at commandline (if any)
38 const char *g_AudioPlugin = NULL;      // pointer to audio plugin specified at commandline (if any)
39 const char *g_InputPlugin = NULL;      // pointer to input plugin specified at commandline (if any)
40 const char *g_RspPlugin = NULL;        // pointer to rsp plugin specified at commandline (if any)
41
42 plugin_map_node g_PluginMap[] = {{M64PLUGIN_GFX,   "Video", NULL, "", NULL, 0 },
43                                  {M64PLUGIN_AUDIO, "Audio", NULL, "", NULL, 0 },
44                                  {M64PLUGIN_INPUT, "Input", NULL, "", NULL, 0 },
45                                  {M64PLUGIN_RSP,   "RSP",   NULL, "", NULL, 0 } };
46
47 /* local functions */
48 static m64p_error PluginLoadTry(const char *filepath, int MapIndex)
49 {
50     /* try to open a shared library at the given filepath */
51     m64p_dynlib_handle handle;
52     m64p_error rval = osal_dynlib_open(&handle, filepath);
53     if (rval != M64ERR_SUCCESS)
54         return rval;
55
56     /* call the GetVersion function for the plugin and check compatibility */
57     ptr_PluginGetVersion PluginGetVersion = (ptr_PluginGetVersion) osal_dynlib_getproc(handle, "PluginGetVersion");
58     if (PluginGetVersion == NULL)
59     {
60         if (g_Verbose)
61             DebugMessage(M64MSG_ERROR, "library '%s' is not a Mupen64Plus library.", filepath);
62         osal_dynlib_close(handle);
63         return M64ERR_INCOMPATIBLE;
64     }
65     m64p_plugin_type PluginType = (m64p_plugin_type) 0;
66     int PluginVersion = 0;
67     const char *PluginName = NULL;
68     (*PluginGetVersion)(&PluginType, &PluginVersion, NULL, &PluginName, NULL);
69     if (PluginType != g_PluginMap[MapIndex].type)
70     {
71         /* the type of this plugin doesn't match with the type that was requested by the caller */
72         osal_dynlib_close(handle);
73         return M64ERR_INCOMPATIBLE;
74     }
75     /* the front-end doesn't talk to the plugins, so we don't care about the plugin version or api version */
76
77     /* call the plugin's initialization function and make sure it starts okay */
78     ptr_PluginStartup PluginStartup = (ptr_PluginStartup) osal_dynlib_getproc(handle, "PluginStartup");
79     if (PluginStartup == NULL)
80     {
81         DebugMessage(M64MSG_ERROR, "library '%s' broken.  No PluginStartup() function found.", filepath);
82         osal_dynlib_close(handle);
83         return M64ERR_INCOMPATIBLE;
84     }
85     rval = (*PluginStartup)(CoreHandle, g_PluginMap[MapIndex].name, DebugCallback);  /* DebugCallback is in main.c */
86     if (rval != M64ERR_SUCCESS)
87     {
88         DebugMessage(M64MSG_ERROR, "Error: %s plugin library '%s' failed to start.", g_PluginMap[MapIndex].name, filepath);
89         osal_dynlib_close(handle);
90         return rval;
91     }
92
93     /* plugin loaded successfully, so set the plugin map's members */
94     g_PluginMap[MapIndex].handle = handle;
95     strcpy(g_PluginMap[MapIndex].filename, filepath);
96     g_PluginMap[MapIndex].libname = PluginName;
97     g_PluginMap[MapIndex].libversion = PluginVersion;
98
99     return M64ERR_SUCCESS;
100 }
101
102 /* global functions */
103 m64p_error PluginSearchLoad(m64p_handle ConfigUI)
104 {
105     osal_lib_search *lib_filelist = NULL;
106     int i;
107
108     /* start by checking the directory given on the command line */
109     if (g_PluginDir != NULL)
110     {
111         lib_filelist = osal_library_search(g_PluginDir);
112         if (lib_filelist == NULL)
113         {
114             DebugMessage(M64MSG_ERROR, "No plugins found in --plugindir path: %s", g_PluginDir);
115             return M64ERR_INPUT_NOT_FOUND;
116         }
117     }
118
119     /* if no plugins found, search the PluginDir in the UI-console section of the config file */
120     if (lib_filelist == NULL)
121     {
122         const char *plugindir = (*ConfigGetParamString)(ConfigUI, "PluginDir");
123         lib_filelist = osal_library_search(plugindir);
124     }
125
126     /* if still no plugins found, search some common system folders */
127     if (lib_filelist == NULL)
128     {
129         for (i = 0; i < osal_libsearchdirs; i++)
130         {
131             lib_filelist = osal_library_search(osal_libsearchpath[i]);
132             if (lib_filelist != NULL)
133                 break;
134         }
135     }
136
137     /* try to load one of each type of plugin */
138     for (i = 0; i < 4; i++)
139     {
140         m64p_plugin_type type = g_PluginMap[i].type;
141         const char      *cmdline_path = NULL;
142         const char      *config_var = NULL;
143         int              use_dummy = 0;
144         switch (type)
145         {
146             case M64PLUGIN_RSP:    cmdline_path = g_RspPlugin;    config_var = "RspPlugin";   break;
147             case M64PLUGIN_GFX:    cmdline_path = g_GfxPlugin;    config_var = "VideoPlugin"; break;
148             case M64PLUGIN_AUDIO:  cmdline_path = g_AudioPlugin;  config_var = "AudioPlugin"; break;
149             case M64PLUGIN_INPUT:  cmdline_path = g_InputPlugin;  config_var = "InputPlugin"; break;
150             default:               cmdline_path = NULL;           config_var = "";
151         }
152         /* first search for a plugin matching what was given on the command line */
153         if (cmdline_path != NULL)
154         {
155             /* if full path was given, try loading exactly this file */
156             if (strchr(cmdline_path, OSAL_DIR_SEPARATOR) != NULL)
157             {
158                 PluginLoadTry(cmdline_path, i);
159             }
160             else if (strcmp(cmdline_path, "dummy") == 0)
161             {
162                 use_dummy = 1;
163             }
164             else /* otherwise search through the plugin directory to find a match with this name */
165             {
166                 osal_lib_search *curr = lib_filelist;
167                 while (curr != NULL && g_PluginMap[i].handle == NULL)
168                 {
169                     if (strncmp(curr->filename, cmdline_path, strlen(cmdline_path)) == 0)
170                         PluginLoadTry(curr->filepath, i);
171                     curr = curr->next;
172                 }
173             }
174             /* exit with error if we couldn't find the specified plugin */
175             if (!use_dummy && g_PluginMap[i].handle == NULL)
176             {
177                 DebugMessage(M64MSG_ERROR, "Specified %s plugin not found: %s", g_PluginMap[i].name, cmdline_path);
178                 osal_free_lib_list(lib_filelist);
179                 return M64ERR_INPUT_NOT_FOUND;
180             }
181         }
182         else /* otherwise search for a plugin specified in the config file */
183         {
184             const char *config_path = (*ConfigGetParamString)(ConfigUI, config_var);
185             if (config_path != NULL && strlen(config_path) > 0)
186             {
187                 /* if full path was given, try loading exactly this file */
188                 if (strchr(config_path, OSAL_DIR_SEPARATOR) != NULL)
189                 {
190                     PluginLoadTry(config_path, i);
191                 }
192                 else if (strcmp(config_path, "dummy") == 0)
193                 {
194                     use_dummy = 1;
195                 }
196                 else /* otherwise search through the plugin directory to find a match with this name */
197                 {
198                     osal_lib_search *curr = lib_filelist;
199                     while (curr != NULL && g_PluginMap[i].handle == NULL)
200                     {
201                         if (strncmp(curr->filename, config_path, strlen(config_path)) == 0)
202                             PluginLoadTry(curr->filepath, i);
203                         curr = curr->next;
204                     }
205                 }
206             }
207         }
208         /* As a last resort, search for any appropriate plugin in search directory */
209         if (!use_dummy && g_PluginMap[i].handle == NULL)
210         {
211             osal_lib_search *curr = lib_filelist;
212             while (curr != NULL && g_PluginMap[i].handle == NULL)
213             {
214                 PluginLoadTry(curr->filepath, i);
215                 curr = curr->next;
216             }
217         }
218         /* print out the particular plugin used */
219         if (g_PluginMap[i].handle == NULL)
220         {
221             DebugMessage(M64MSG_INFO, "using %s plugin: <dummy>", g_PluginMap[i].name);
222         }
223         else
224         {
225             DebugMessage(M64MSG_INFO, "using %s plugin: '%s' v%i.%i.%i", g_PluginMap[i].name,
226                    g_PluginMap[i].libname, VERSION_PRINTF_SPLIT(g_PluginMap[i].libversion));
227             DebugMessage(M64MSG_VERBOSE, "%s plugin library: %s", g_PluginMap[i].name, g_PluginMap[i].filename);
228         }
229     }
230
231     /* free up the list of library files in the plugin search directory */
232     osal_free_lib_list(lib_filelist);
233     return M64ERR_SUCCESS;
234 }
235
236 m64p_error PluginUnload(void)
237 {
238     typedef m64p_error (*ptr_PluginShutdown)(void);
239     ptr_PluginShutdown PluginShutdown;
240     int i;
241
242     /* shutdown each type of plugin */
243     for (i = 0; i < 4; i++)
244     {
245         if (g_PluginMap[i].handle == NULL)
246             continue;
247         /* call the destructor function for the plugin and release the library */
248         PluginShutdown = (ptr_PluginShutdown) osal_dynlib_getproc(g_PluginMap[i].handle, "PluginShutdown");
249         if (PluginShutdown != NULL)
250             (*PluginShutdown)();
251         osal_dynlib_close(g_PluginMap[i].handle);
252         /* clear out the plugin map's members */
253         g_PluginMap[i].handle = NULL;
254         g_PluginMap[i].filename[0] = 0;
255         g_PluginMap[i].libname = NULL;
256         g_PluginMap[i].libversion = 0;
257     }
258
259     return M64ERR_SUCCESS;
260 }
261