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