57496e64a9f0a10bdbbbdb5da85f5e17537c5623
[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 */