chiark / gitweb /
Merge from 3.0 fixes branch
[disorder] / lib / plugin.c
CommitLineData
460b9539 1/*
2 * This file is part of DisOrder.
5aff007d 3 * Copyright (C) 2004-2008 Richard Kettlewell
460b9539 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>
6d2d327c 22#include "types.h"
460b9539 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
43struct plugin {
44 struct plugin *next;
45 void *dlhandle;
46 const char *name;
47};
48
49static struct plugin *plugins;
50
51const 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;
62dc3748 61 /* Search the plugin path */
460b9539 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
84function_t *get_plugin_function(const struct plugin *pl,
85 const char *symbol) {
86 function_t *f;
460b9539 87
88 f = (function_t *)dlsym(pl->dlhandle, symbol);
f47f3637 89 if(!f)
90 fatal(0, "error looking up function '%s' in '%s': %s",
91 symbol, pl->name, dlerror());
460b9539 92 return f;
93}
94
95const void *get_plugin_object(const struct plugin *pl,
96 const char *symbol) {
97 void *o;
460b9539 98
99 o = dlsym(pl->dlhandle, symbol);
f47f3637 100 if(!o)
101 fatal(0, "error looking up object '%s' in '%s': %s",
102 symbol, pl->name, dlerror());
460b9539 103 return o;
104}
105
106/* specific plugin interfaces *************************************************/
107
108typedef long tracklength_fn(const char *track, const char *path);
109
62dc3748
RK
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 */
116long tracklength(const char *plugin, const char *track, const char *path) {
117 tracklength_fn *f = 0;
460b9539 118
62dc3748
RK
119 f = (tracklength_fn *)get_plugin_function(open_plugin(plugin,
120 PLUGIN_FATAL),
121 "disorder_tracklength");
460b9539 122 return (*f)(track, path);
123}
124
125typedef void scan_fn(const char *root);
126
127void scan(const char *module, const char *root) {
128 ((scan_fn *)get_plugin_function(open_plugin(module, PLUGIN_FATAL),
129 "disorder_scan"))(root);
130}
131
132typedef int check_fn(const char *root, const char *path);
133
134
135int 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
140typedef void notify_play_fn(const char *track, const char *submitter);
141
142void 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
153typedef void notify_scratch_fn(const char *track,
154 const char *submitter,
155 const char *scratcher,
156 int seconds);
157
158void 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
171typedef void notify_not_scratched_fn(const char *track,
172 const char *submitter);
173
174void 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
186typedef void notify_queue_fn(const char *track,
187 const char *submitter);
188
189void 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
200void 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
211void 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
222void 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
232void 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
246unsigned 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
252typedef void *prefork_fn(const char *track);
253
254void *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
262typedef void play_track_fn(const char *const *parameters,
263 int nparameters,
264 const char *path,
265 const char *track);
266
267void 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
281typedef void cleanup_fn(void *data);
282
283void play_cleanup(const struct plugin *pl, void *data) {
284 ((cleanup_fn *)get_plugin_function(pl, "disorder_play_cleanup"))(data);
285}
286
287/* pause */
288
289typedef int pause_fn(long *playedp, void *data);
290
291int 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
298typedef void resume_fn(void *data);
299
300void play_resume(const struct plugin *pl, void *data) {
301 (((resume_fn *)get_plugin_function(pl, "disorder_resume_track"))
302 (data));
303}
304
305/*
306Local Variables:
307c-basic-offset:2
308comment-column:40
309End:
310*/