chiark / gitweb /
Merge from Mark's branch.
[disorder] / lib / plugin.c
1 /*
2  * This file is part of DisOrder.
3  * Copyright (C) 2004, 2005, 2006 Richard Kettlewell
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
18  * USA
19  */
20
21 #include <config.h>
22
23 #include <dlfcn.h>
24 #include <unistd.h>
25 #include <string.h>
26 #include <stdio.h>
27
28 #include "plugin.h"
29 #include "configuration.h"
30 #include "log.h"
31 #include "mem.h"
32 #include "defs.h"
33 #include "disorder.h"
34 #include "printf.h"
35
36 /* generic plugin support *****************************************************/
37
38 #ifndef SOSUFFIX
39 # define SOSUFFIX ".so"
40 #endif
41
42 struct plugin {
43   struct plugin *next;
44   void *dlhandle;
45   const char *name;
46 };
47
48 static struct plugin *plugins;
49
50 const struct plugin *open_plugin(const char *name,
51                                  unsigned flags) {
52   void *h = 0;
53   char *p;
54   int n;
55   struct plugin *pl;
56
57   for(pl = plugins; pl && strcmp(pl->name, name); pl = pl->next)
58     ;
59   if(pl) return pl;
60   for(n = 0; n <= config->plugins.n; ++n) {
61     byte_xasprintf(&p, "%s/%s" SOSUFFIX,
62                    n == config->plugins.n ? pkglibdir : config->plugins.s[n],
63                    name);
64     if(access(p, R_OK) == 0) {
65       h = dlopen(p, RTLD_NOW);
66       if(!h) {
67         error(0, "error opening %s: %s", p, dlerror());
68         continue;
69       }
70       pl = xmalloc(sizeof *pl);
71       pl->dlhandle = h;
72       pl->name = xstrdup(name);
73       pl->next = plugins;
74       plugins = pl;
75       return pl;
76     }
77   }
78   (flags & PLUGIN_FATAL ? fatal : error)(0, "cannot find plugin '%s'", name);
79   return 0;
80 }
81
82 function_t *get_plugin_function(const struct plugin *pl,
83                                 const char *symbol) {
84   function_t *f;
85   const char *e;
86
87   f = (function_t *)dlsym(pl->dlhandle, symbol);
88   if((e = dlerror()))
89     fatal(0, "error looking up function '%s' in '%s': %s",symbol, pl->name, e);
90   return f;
91 }
92
93 const void *get_plugin_object(const struct plugin *pl,
94                               const char *symbol) {
95   void *o;
96   const char *e;
97
98   o = dlsym(pl->dlhandle, symbol);
99   if((e = dlerror()))
100     fatal(0, "error looking up object '%s' in '%s': %s", symbol, pl->name, e);
101   return o;
102 }
103
104 /* specific plugin interfaces *************************************************/
105
106 typedef long tracklength_fn(const char *track, const char *path);
107
108 long tracklength(const char *track, const char *path) {
109   static tracklength_fn *f = 0;
110
111   if(!f)
112     f = (tracklength_fn *)get_plugin_function(open_plugin("tracklength",
113                                                           PLUGIN_FATAL),
114                                               "disorder_tracklength");
115   return (*f)(track, path);
116 }
117
118 typedef void scan_fn(const char *root);
119
120 void scan(const char *module, const char *root) {
121   ((scan_fn *)get_plugin_function(open_plugin(module, PLUGIN_FATAL),
122                                   "disorder_scan"))(root);
123 }
124
125 typedef int check_fn(const char *root, const char *path);
126
127
128 int check(const char *module, const char *root, const char *path) {
129   return ((check_fn *)get_plugin_function(open_plugin(module, PLUGIN_FATAL),
130                                           "disorder_check"))(root, path);
131 }
132
133 typedef void notify_play_fn(const char *track, const char *submitter);
134
135 void notify_play(const char *track,
136                  const char *submitter) {
137   static notify_play_fn *f;
138
139   if(!f)
140     f = (notify_play_fn *)get_plugin_function(open_plugin("notify",
141                                                           PLUGIN_FATAL),
142                                               "disorder_notify_play");
143   (*f)(track, submitter);
144 }
145
146 typedef void notify_scratch_fn(const char *track,
147                                const char *submitter,
148                                const char *scratcher,
149                                int seconds);
150
151 void notify_scratch(const char *track,
152                     const char *submitter,
153                     const char *scratcher,
154                     int seconds) {
155   static notify_scratch_fn *f;
156
157   if(!f)
158     f = (notify_scratch_fn *)get_plugin_function(open_plugin("notify",
159                                                              PLUGIN_FATAL),
160                                                  "disorder_notify_scratch");
161   (*f)(track, submitter, scratcher, seconds);
162 }
163
164 typedef void notify_not_scratched_fn(const char *track,
165                                      const char *submitter);
166
167 void notify_not_scratched(const char *track,
168                           const char *submitter) {
169   static notify_not_scratched_fn *f;
170
171   if(!f)
172     f = (notify_not_scratched_fn *)get_plugin_function
173       (open_plugin("notify",
174                    PLUGIN_FATAL),
175        "disorder_notify_not_scratched");
176   (*f)(track, submitter);
177 }
178
179 typedef void notify_queue_fn(const char *track,
180                              const char *submitter);
181
182 void notify_queue(const char *track,
183                   const char *submitter) {
184   static notify_queue_fn *f;
185
186   if(!f)
187     f = (notify_queue_fn *)get_plugin_function(open_plugin("notify",
188                                                            PLUGIN_FATAL),
189                                                "disorder_notify_queue");
190   (*f)(track, submitter);
191 }
192
193 void notify_queue_remove(const char *track,
194                          const char *remover) {
195   static notify_queue_fn *f;
196   
197   if(!f)
198     f = (notify_queue_fn *)get_plugin_function(open_plugin("notify",
199                                                            PLUGIN_FATAL),
200                                                "disorder_notify_queue_remove");
201   (*f)(track, remover);
202 }
203
204 void notify_queue_move(const char *track,
205                        const char *mover) {
206   static notify_queue_fn *f;
207   
208   if(!f)
209     f = (notify_queue_fn *)get_plugin_function(open_plugin("notify",
210                                                            PLUGIN_FATAL),
211                                                "disorder_notify_queue_move");
212   (*f)(track, mover);
213 }
214
215 void notify_pause(const char *track, const char *who) {
216   static notify_queue_fn *f;
217   
218   if(!f)
219     f = (notify_queue_fn *)get_plugin_function(open_plugin("notify",
220                                                            PLUGIN_FATAL),
221                                                "disorder_notify_pause");
222   (*f)(track, who);
223 }
224
225 void notify_resume(const char *track, const char *who) {
226   static notify_queue_fn *f;
227   
228   if(!f)
229     f = (notify_queue_fn *)get_plugin_function(open_plugin("notify",
230                                                            PLUGIN_FATAL),
231                                                "disorder_notify_resume");
232   (*f)(track, who);
233 }
234
235 /* player plugin interfaces ***************************************************/
236
237 /* get type */
238
239 unsigned long play_get_type(const struct plugin *pl) {
240   return *(const unsigned long *)get_plugin_object(pl, "disorder_player_type");
241 }
242
243 /* prefork */
244
245 typedef void *prefork_fn(const char *track);
246
247 void *play_prefork(const struct plugin *pl,
248                    const char *track) {
249   return ((prefork_fn *)get_plugin_function(pl,
250                                             "disorder_play_prefork"))(track);
251 }
252
253 /* play */
254
255 typedef void play_track_fn(const char *const *parameters,
256                            int nparameters,
257                            const char *path,
258                            const char *track);
259
260 void play_track(const struct plugin *pl,
261                 const char *const *parameters,
262                 int nparameters,
263                 const char *path,
264                 const char *track) {
265   ((play_track_fn *)get_plugin_function(pl,
266                                         "disorder_play_track"))(parameters,
267                                                                 nparameters,
268                                                                 path,
269                                                                 track);
270 }
271
272 /* cleanup */
273
274 typedef void cleanup_fn(void *data);
275
276 void play_cleanup(const struct plugin *pl, void *data) {
277   ((cleanup_fn *)get_plugin_function(pl, "disorder_play_cleanup"))(data);
278 }
279
280 /* pause */
281
282 typedef int pause_fn(long *playedp, void *data);
283
284 int play_pause(const struct plugin *pl, long *playedp, void *data) {
285   return (((pause_fn *)get_plugin_function(pl, "disorder_pause_track"))
286           (playedp, data));
287 }
288
289 /* resume */
290
291 typedef void resume_fn(void *data);
292
293 void play_resume(const struct plugin *pl, void *data) {
294   (((resume_fn *)get_plugin_function(pl, "disorder_resume_track"))
295    (data));
296 }
297
298 /*
299 Local Variables:
300 c-basic-offset:2
301 comment-column:40
302 End:
303 */