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