chiark / gitweb /
help menu can now pop up the man page
[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 #include "types.h"
23
24 #include <dlfcn.h>
25 #include <unistd.h>
26 #include <string.h>
27 #include <stdio.h>
28
29 #include "plugin.h"
30 #include "configuration.h"
31 #include "log.h"
32 #include "mem.h"
33 #include "defs.h"
34 #include "disorder.h"
35 #include "printf.h"
36
37 /* generic plugin support *****************************************************/
38
39 #ifndef SOSUFFIX
40 # define SOSUFFIX ".so"
41 #endif
42
43 struct plugin {
44   struct plugin *next;
45   void *dlhandle;
46   const char *name;
47 };
48
49 static struct plugin *plugins;
50
51 const struct plugin *open_plugin(const char *name,
52                                  unsigned flags) {
53   void *h = 0;
54   char *p;
55   int n;
56   struct plugin *pl;
57
58   for(pl = plugins; pl && strcmp(pl->name, name); pl = pl->next)
59     ;
60   if(pl) return pl;
61   for(n = 0; n <= config->plugins.n; ++n) {
62     byte_xasprintf(&p, "%s/%s" SOSUFFIX,
63                    n == config->plugins.n ? pkglibdir : config->plugins.s[n],
64                    name);
65     if(access(p, R_OK) == 0) {
66       h = dlopen(p, RTLD_NOW);
67       if(!h) {
68         error(0, "error opening %s: %s", p, dlerror());
69         continue;
70       }
71       pl = xmalloc(sizeof *pl);
72       pl->dlhandle = h;
73       pl->name = xstrdup(name);
74       pl->next = plugins;
75       plugins = pl;
76       return pl;
77     }
78   }
79   (flags & PLUGIN_FATAL ? fatal : error)(0, "cannot find plugin '%s'", name);
80   return 0;
81 }
82
83 function_t *get_plugin_function(const struct plugin *pl,
84                                 const char *symbol) {
85   function_t *f;
86   const char *e;
87
88   f = (function_t *)dlsym(pl->dlhandle, symbol);
89   if((e = dlerror()))
90     fatal(0, "error looking up function '%s' in '%s': %s",symbol, pl->name, e);
91   return f;
92 }
93
94 const void *get_plugin_object(const struct plugin *pl,
95                               const char *symbol) {
96   void *o;
97   const char *e;
98
99   o = dlsym(pl->dlhandle, symbol);
100   if((e = dlerror()))
101     fatal(0, "error looking up object '%s' in '%s': %s", symbol, pl->name, e);
102   return o;
103 }
104
105 /* specific plugin interfaces *************************************************/
106
107 typedef long tracklength_fn(const char *track, const char *path);
108
109 long tracklength(const char *track, const char *path) {
110   static tracklength_fn *f = 0;
111
112   if(!f)
113     f = (tracklength_fn *)get_plugin_function(open_plugin("tracklength",
114                                                           PLUGIN_FATAL),
115                                               "disorder_tracklength");
116   return (*f)(track, path);
117 }
118
119 typedef void scan_fn(const char *root);
120
121 void scan(const char *module, const char *root) {
122   ((scan_fn *)get_plugin_function(open_plugin(module, PLUGIN_FATAL),
123                                   "disorder_scan"))(root);
124 }
125
126 typedef int check_fn(const char *root, const char *path);
127
128
129 int check(const char *module, const char *root, const char *path) {
130   return ((check_fn *)get_plugin_function(open_plugin(module, PLUGIN_FATAL),
131                                           "disorder_check"))(root, path);
132 }
133
134 typedef void notify_play_fn(const char *track, const char *submitter);
135
136 void notify_play(const char *track,
137                  const char *submitter) {
138   static notify_play_fn *f;
139
140   if(!f)
141     f = (notify_play_fn *)get_plugin_function(open_plugin("notify",
142                                                           PLUGIN_FATAL),
143                                               "disorder_notify_play");
144   (*f)(track, submitter);
145 }
146
147 typedef void notify_scratch_fn(const char *track,
148                                const char *submitter,
149                                const char *scratcher,
150                                int seconds);
151
152 void notify_scratch(const char *track,
153                     const char *submitter,
154                     const char *scratcher,
155                     int seconds) {
156   static notify_scratch_fn *f;
157
158   if(!f)
159     f = (notify_scratch_fn *)get_plugin_function(open_plugin("notify",
160                                                              PLUGIN_FATAL),
161                                                  "disorder_notify_scratch");
162   (*f)(track, submitter, scratcher, seconds);
163 }
164
165 typedef void notify_not_scratched_fn(const char *track,
166                                      const char *submitter);
167
168 void notify_not_scratched(const char *track,
169                           const char *submitter) {
170   static notify_not_scratched_fn *f;
171
172   if(!f)
173     f = (notify_not_scratched_fn *)get_plugin_function
174       (open_plugin("notify",
175                    PLUGIN_FATAL),
176        "disorder_notify_not_scratched");
177   (*f)(track, submitter);
178 }
179
180 typedef void notify_queue_fn(const char *track,
181                              const char *submitter);
182
183 void notify_queue(const char *track,
184                   const char *submitter) {
185   static notify_queue_fn *f;
186
187   if(!f)
188     f = (notify_queue_fn *)get_plugin_function(open_plugin("notify",
189                                                            PLUGIN_FATAL),
190                                                "disorder_notify_queue");
191   (*f)(track, submitter);
192 }
193
194 void notify_queue_remove(const char *track,
195                          const char *remover) {
196   static notify_queue_fn *f;
197   
198   if(!f)
199     f = (notify_queue_fn *)get_plugin_function(open_plugin("notify",
200                                                            PLUGIN_FATAL),
201                                                "disorder_notify_queue_remove");
202   (*f)(track, remover);
203 }
204
205 void notify_queue_move(const char *track,
206                        const char *mover) {
207   static notify_queue_fn *f;
208   
209   if(!f)
210     f = (notify_queue_fn *)get_plugin_function(open_plugin("notify",
211                                                            PLUGIN_FATAL),
212                                                "disorder_notify_queue_move");
213   (*f)(track, mover);
214 }
215
216 void notify_pause(const char *track, const char *who) {
217   static notify_queue_fn *f;
218   
219   if(!f)
220     f = (notify_queue_fn *)get_plugin_function(open_plugin("notify",
221                                                            PLUGIN_FATAL),
222                                                "disorder_notify_pause");
223   (*f)(track, who);
224 }
225
226 void notify_resume(const char *track, const char *who) {
227   static notify_queue_fn *f;
228   
229   if(!f)
230     f = (notify_queue_fn *)get_plugin_function(open_plugin("notify",
231                                                            PLUGIN_FATAL),
232                                                "disorder_notify_resume");
233   (*f)(track, who);
234 }
235
236 /* player plugin interfaces ***************************************************/
237
238 /* get type */
239
240 unsigned long play_get_type(const struct plugin *pl) {
241   return *(const unsigned long *)get_plugin_object(pl, "disorder_player_type");
242 }
243
244 /* prefork */
245
246 typedef void *prefork_fn(const char *track);
247
248 void *play_prefork(const struct plugin *pl,
249                    const char *track) {
250   return ((prefork_fn *)get_plugin_function(pl,
251                                             "disorder_play_prefork"))(track);
252 }
253
254 /* play */
255
256 typedef void play_track_fn(const char *const *parameters,
257                            int nparameters,
258                            const char *path,
259                            const char *track);
260
261 void play_track(const struct plugin *pl,
262                 const char *const *parameters,
263                 int nparameters,
264                 const char *path,
265                 const char *track) {
266   ((play_track_fn *)get_plugin_function(pl,
267                                         "disorder_play_track"))(parameters,
268                                                                 nparameters,
269                                                                 path,
270                                                                 track);
271 }
272
273 /* cleanup */
274
275 typedef void cleanup_fn(void *data);
276
277 void play_cleanup(const struct plugin *pl, void *data) {
278   ((cleanup_fn *)get_plugin_function(pl, "disorder_play_cleanup"))(data);
279 }
280
281 /* pause */
282
283 typedef int pause_fn(long *playedp, void *data);
284
285 int play_pause(const struct plugin *pl, long *playedp, void *data) {
286   return (((pause_fn *)get_plugin_function(pl, "disorder_pause_track"))
287           (playedp, data));
288 }
289
290 /* resume */
291
292 typedef void resume_fn(void *data);
293
294 void play_resume(const struct plugin *pl, void *data) {
295   (((resume_fn *)get_plugin_function(pl, "disorder_resume_track"))
296    (data));
297 }
298
299 /*
300 Local Variables:
301 c-basic-offset:2
302 comment-column:40
303 End:
304 */