chiark / gitweb /
now builds on linux
[disorder] / lib / plugin.c
CommitLineData
460b9539 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
42struct plugin {
43 struct plugin *next;
44 void *dlhandle;
45 const char *name;
46};
47
48static struct plugin *plugins;
49
50const 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
82function_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
93const 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
106typedef long tracklength_fn(const char *track, const char *path);
107
108long 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
118typedef void scan_fn(const char *root);
119
120void scan(const char *module, const char *root) {
121 ((scan_fn *)get_plugin_function(open_plugin(module, PLUGIN_FATAL),
122 "disorder_scan"))(root);
123}
124
125typedef int check_fn(const char *root, const char *path);
126
127
128int 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
133typedef void notify_play_fn(const char *track, const char *submitter);
134
135void 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
146typedef void notify_scratch_fn(const char *track,
147 const char *submitter,
148 const char *scratcher,
149 int seconds);
150
151void 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
164typedef void notify_not_scratched_fn(const char *track,
165 const char *submitter);
166
167void 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
179typedef void notify_queue_fn(const char *track,
180 const char *submitter);
181
182void 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
193void 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
204void 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
215void 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
225void 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
239unsigned 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
245typedef void *prefork_fn(const char *track);
246
247void *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
255typedef void play_track_fn(const char *const *parameters,
256 int nparameters,
257 const char *path,
258 const char *track);
259
260void 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
274typedef void cleanup_fn(void *data);
275
276void play_cleanup(const struct plugin *pl, void *data) {
277 ((cleanup_fn *)get_plugin_function(pl, "disorder_play_cleanup"))(data);
278}
279
280/* pause */
281
282typedef int pause_fn(long *playedp, void *data);
283
284int 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
291typedef void resume_fn(void *data);
292
293void play_resume(const struct plugin *pl, void *data) {
294 (((resume_fn *)get_plugin_function(pl, "disorder_resume_track"))
295 (data));
296}
297
298/*
299Local Variables:
300c-basic-offset:2
301comment-column:40
302End:
303*/