Audacious  $Id:Doxyfile42802007-03-2104:39:00Znenolod$
pluginenum.c
Go to the documentation of this file.
1 /*
2  * pluginenum.c
3  * Copyright 2007-2011 William Pitcock and John Lindgren
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  * this list of conditions, and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright notice,
12  * this list of conditions, and the following disclaimer in the documentation
13  * provided with the distribution.
14  *
15  * This software is provided "as is" and without any warranty, express or
16  * implied. In no event shall the authors be liable for any damages arising from
17  * the use of this software.
18  */
19 
20 #include <assert.h>
21 #include <errno.h>
22 #include <glib.h>
23 #include <gmodule.h>
24 #include <pthread.h>
25 #include <string.h>
26 #include <sys/stat.h>
27 
28 #include <libaudcore/audstrings.h>
29 #include <libaudgui/init.h>
30 
31 #include "debug.h"
32 #include "plugin.h"
33 #include "util.h"
34 
35 #define AUD_API_DECLARE
36 #include "drct.h"
37 #include "misc.h"
38 #include "playlist.h"
39 #include "plugins.h"
40 #undef AUD_API_DECLARE
41 
42 static const char * plugin_dir_list[] = {PLUGINSUBS, NULL};
43 
44 char verbose = 0;
45 
47  .drct_api = & drct_api,
48  .misc_api = & misc_api,
49  .playlist_api = & playlist_api,
50  .plugins_api = & plugins_api,
51  .verbose = & verbose};
52 
53 typedef struct {
54  Plugin * header;
55  GModule * module;
56 } LoadedModule;
57 
58 static GList * loaded_modules = NULL;
59 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
60 
61 Plugin * plugin_load (const char * filename)
62 {
63  AUDDBG ("Loading plugin: %s.\n", filename);
64 
65  GModule * module = g_module_open (filename, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
66  if (! module)
67  {
68  fprintf (stderr, " *** ERROR: %s could not be loaded: %s\n", filename,
69  g_module_error ());
70  return NULL;
71  }
72 
73  Plugin * (* func) (AudAPITable * table);
74  Plugin * header;
75 
76  if (! g_module_symbol (module, "get_plugin_info", (void *) & func) ||
77  ! (header = func (& api_table)) || header->magic != _AUD_PLUGIN_MAGIC)
78  {
79  fprintf (stderr, " *** ERROR: %s is not a valid Audacious plugin.\n", filename);
80  g_module_close (module);
81  return NULL;
82  }
83 
84  if (header->version < _AUD_PLUGIN_VERSION_MIN ||
85  header->version > _AUD_PLUGIN_VERSION)
86  {
87  fprintf (stderr, " *** ERROR: %s is not compatible with this version "
88  "of Audacious.\n", filename);
89  g_module_close (module);
90  return NULL;
91  }
92 
93  if (header->type == PLUGIN_TYPE_TRANSPORT ||
94  header->type == PLUGIN_TYPE_PLAYLIST ||
95  header->type == PLUGIN_TYPE_INPUT ||
96  header->type == PLUGIN_TYPE_EFFECT)
97  {
98  if (PLUGIN_HAS_FUNC (header, init) && ! header->init ())
99  {
100  fprintf (stderr, " *** ERROR: %s failed to initialize.\n", filename);
101  g_module_close (module);
102  return NULL;
103  }
104  }
105 
106  pthread_mutex_lock (& mutex);
107  LoadedModule * loaded = g_slice_new (LoadedModule);
108  loaded->header = header;
109  loaded->module = module;
110  loaded_modules = g_list_prepend (loaded_modules, loaded);
111  pthread_mutex_unlock (& mutex);
112 
113  return header;
114 }
115 
117 {
118  Plugin * header = loaded->header;
119 
120  switch (header->type)
121  {
124  case PLUGIN_TYPE_INPUT:
125  case PLUGIN_TYPE_EFFECT:
126  if (PLUGIN_HAS_FUNC (header, cleanup))
127  header->cleanup ();
128  break;
129  }
130 
131  pthread_mutex_lock (& mutex);
132  g_module_close (loaded->module);
133  g_slice_free (LoadedModule, loaded);
134  pthread_mutex_unlock (& mutex);
135 }
136 
137 /******************************************************************/
138 
139 static bool_t scan_plugin_func(const char * path, const char * basename, void * data)
140 {
141  if (!str_has_suffix_nocase(basename, PLUGIN_SUFFIX))
142  return FALSE;
143 
144  struct stat st;
145  if (stat (path, & st))
146  {
147  fprintf (stderr, "Unable to stat %s: %s\n", path, strerror (errno));
148  return FALSE;
149  }
150 
151  if (S_ISREG (st.st_mode))
152  plugin_register (path, st.st_mtime);
153 
154  return FALSE;
155 }
156 
157 static void scan_plugins(const char * path)
158 {
160 }
161 
163 {
164  assert (g_module_supported ());
165 
166  char *dir;
167  int dirsel = 0;
168 
169  audgui_init (& api_table);
170 
172 
173 #ifndef DISABLE_USER_PLUGIN_DIR
175  /*
176  * This is in a separate loop so if the user puts them in the
177  * wrong dir we'll still get them in the right order (home dir
178  * first) - Zinx
179  */
180  while (plugin_dir_list[dirsel])
181  {
182  dir = g_build_filename (get_path (AUD_PATH_USER_PLUGIN_DIR),
183  plugin_dir_list[dirsel ++], NULL);
184  scan_plugins(dir);
185  g_free(dir);
186  }
187  dirsel = 0;
188 #endif
189 
190  while (plugin_dir_list[dirsel])
191  {
192  dir = g_build_filename (get_path (AUD_PATH_PLUGIN_DIR),
193  plugin_dir_list[dirsel ++], NULL);
194  scan_plugins(dir);
195  g_free(dir);
196  }
197 
199 }
200 
202 {
204 
205  for (GList * node = loaded_modules; node != NULL; node = node->next)
206  plugin2_unload (node->data);
207 
208  g_list_free (loaded_modules);
210 
211  audgui_cleanup ();
212 }