Fortunes about QT and "hearing" video codecs
[vlc.git] / src / modules / entry.c
blobbce94285c600bd47b5cfa76d528e53b6ddef797b
1 /*****************************************************************************
2 * entry.c : Callbacks for module entry point
3 *****************************************************************************
4 * Copyright (C) 2007 VLC authors and VideoLAN
5 * Copyright © 2007-2008 Rémi Denis-Courmont
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as published by
9 * the Free Software Foundation; either version 2.1 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with this program; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
20 *****************************************************************************/
22 #ifdef HAVE_CONFIG_H
23 # include "config.h"
24 #endif
26 #include <vlc_common.h>
27 #include <vlc_plugin.h>
28 #include <assert.h>
29 #include <stdarg.h>
30 #include <limits.h>
31 #include <float.h>
32 #ifdef HAVE_SEARCH_H
33 # include <search.h>
34 #endif
36 #include "modules/modules.h"
37 #include "config/configuration.h"
38 #include "libvlc.h"
40 module_t *vlc_module_create(vlc_plugin_t *plugin)
42 module_t *module = malloc (sizeof (*module));
43 if (module == NULL)
44 return NULL;
46 /* NOTE XXX: For backward compatibility with preferences UIs, the first
47 * module must stay first. That defines under which module, the
48 * configuration items of the plugin belong. The order of the following
49 * entries is irrelevant. */
50 module_t *parent = plugin->module;
51 if (parent == NULL)
53 module->next = NULL;
54 plugin->module = module;
56 else
58 module->next = parent->next;
59 parent->next = module;
62 plugin->modules_count++;
63 module->plugin = plugin;
65 module->psz_shortname = NULL;
66 module->psz_longname = NULL;
67 module->psz_help = NULL;
68 module->pp_shortcuts = NULL;
69 module->i_shortcuts = 0;
70 module->psz_capability = NULL;
71 module->i_score = (parent != NULL) ? parent->i_score : 1;
72 module->activate_name = NULL;
73 module->deactivate_name = NULL;
74 module->pf_activate = NULL;
75 module->pf_deactivate = NULL;
76 return module;
79 /**
80 * Destroys a module.
82 void vlc_module_destroy (module_t *module)
84 while (module != NULL)
86 module_t *next = module->next;
88 free(module->pp_shortcuts);
89 free(module);
90 module = next;
94 vlc_plugin_t *vlc_plugin_create(void)
96 vlc_plugin_t *plugin = malloc(sizeof (*plugin));
97 if (unlikely(plugin == NULL))
98 return NULL;
100 plugin->modules_count = 0;
101 plugin->textdomain = NULL;
102 plugin->conf.items = NULL;
103 plugin->conf.size = 0;
104 plugin->conf.count = 0;
105 plugin->conf.booleans = 0;
106 #ifdef HAVE_DYNAMIC_PLUGINS
107 plugin->abspath = NULL;
108 plugin->unloadable = true;
109 atomic_init(&plugin->handle, 0);
110 plugin->abspath = NULL;
111 plugin->path = NULL;
112 #endif
113 plugin->module = NULL;
115 return plugin;
119 * Destroys a plug-in.
120 * @warning If the plug-in was dynamically loaded in memory, the library handle
121 * and associated memory mappings and linker resources will be leaked.
123 void vlc_plugin_destroy(vlc_plugin_t *plugin)
125 assert(plugin != NULL);
126 #ifdef HAVE_DYNAMIC_PLUGINS
127 assert(!plugin->unloadable || atomic_load(&plugin->handle) == 0);
128 #endif
130 if (plugin->module != NULL)
131 vlc_module_destroy(plugin->module);
133 config_Free(plugin->conf.items, plugin->conf.size);
134 #ifdef HAVE_DYNAMIC_PLUGINS
135 free(plugin->abspath);
136 free(plugin->path);
137 #endif
138 free(plugin);
141 static module_config_t *vlc_config_create(vlc_plugin_t *plugin, int type)
143 unsigned confsize = plugin->conf.size;
144 module_config_t *tab = plugin->conf.items;
146 if ((confsize & 0xf) == 0)
148 tab = realloc_or_free (tab, (confsize + 17) * sizeof (*tab));
149 if (tab == NULL)
150 return NULL;
152 plugin->conf.items = tab;
155 memset (tab + confsize, 0, sizeof (tab[confsize]));
156 tab += confsize;
157 tab->owner = plugin;
159 if (IsConfigIntegerType (type))
161 tab->max.i = INT64_MAX;
162 tab->min.i = INT64_MIN;
164 else if( IsConfigFloatType (type))
166 tab->max.f = FLT_MAX;
167 tab->min.f = -FLT_MAX;
169 tab->i_type = type;
171 if (CONFIG_ITEM(type))
173 plugin->conf.count++;
174 if (type == CONFIG_ITEM_BOOL)
175 plugin->conf.booleans++;
177 plugin->conf.size++;
179 return tab;
183 * Plug-in descriptor callback.
185 * This callback populates modules, configuration items and properties of a
186 * plug-in from the plug-in descriptor.
188 static int vlc_plugin_desc_cb(void *ctx, void *tgt, int propid, ...)
190 vlc_plugin_t *plugin = ctx;
191 module_t *module = tgt;
192 module_config_t *item = tgt;
193 va_list ap;
194 int ret = 0;
196 va_start (ap, propid);
197 switch (propid)
199 case VLC_MODULE_CREATE:
201 module_t *super = plugin->module;
202 module_t *submodule = vlc_module_create(plugin);
203 if (unlikely(submodule == NULL))
205 ret = -1;
206 break;
209 *(va_arg (ap, module_t **)) = submodule;
210 if (super == NULL)
211 break;
213 /* Inheritance. Ugly!! */
214 submodule->pp_shortcuts = xmalloc (sizeof ( *submodule->pp_shortcuts ));
215 submodule->pp_shortcuts[0] = super->pp_shortcuts[0];
216 submodule->i_shortcuts = 1; /* object name */
218 submodule->psz_shortname = super->psz_shortname;
219 submodule->psz_longname = super->psz_longname;
220 submodule->psz_capability = super->psz_capability;
221 break;
224 case VLC_CONFIG_CREATE:
226 int type = va_arg (ap, int);
227 module_config_t **pp = va_arg (ap, module_config_t **);
229 item = vlc_config_create(plugin, type);
230 if (unlikely(item == NULL))
232 ret = -1;
233 break;
235 *pp = item;
236 break;
239 case VLC_MODULE_SHORTCUT:
241 unsigned i_shortcuts = va_arg (ap, unsigned);
242 unsigned index = module->i_shortcuts;
243 /* The cache loader accept only a small number of shortcuts */
244 assert(i_shortcuts + index <= MODULE_SHORTCUT_MAX);
246 const char *const *tab = va_arg (ap, const char *const *);
247 const char **pp = realloc (module->pp_shortcuts,
248 sizeof (pp[0]) * (index + i_shortcuts));
249 if (unlikely(pp == NULL))
251 ret = -1;
252 break;
254 module->pp_shortcuts = pp;
255 module->i_shortcuts = index + i_shortcuts;
256 pp += index;
257 for (unsigned i = 0; i < i_shortcuts; i++)
258 pp[i] = tab[i];
259 break;
262 case VLC_MODULE_CAPABILITY:
263 module->psz_capability = va_arg (ap, const char *);
264 break;
266 case VLC_MODULE_SCORE:
267 module->i_score = va_arg (ap, int);
268 break;
270 case VLC_MODULE_CB_OPEN:
271 module->activate_name = va_arg(ap, const char *);
272 module->pf_activate = va_arg (ap, void *);
273 break;
275 case VLC_MODULE_CB_CLOSE:
276 module->deactivate_name = va_arg(ap, const char *);
277 module->pf_deactivate = va_arg (ap, void *);
278 break;
280 case VLC_MODULE_NO_UNLOAD:
281 #ifdef HAVE_DYNAMIC_PLUGINS
282 plugin->unloadable = false;
283 #endif
284 break;
286 case VLC_MODULE_NAME:
288 const char *value = va_arg (ap, const char *);
290 assert (module->i_shortcuts == 0);
291 module->pp_shortcuts = malloc( sizeof( *module->pp_shortcuts ) );
292 module->pp_shortcuts[0] = value;
293 module->i_shortcuts = 1;
295 assert (module->psz_longname == NULL);
296 module->psz_longname = value;
297 break;
300 case VLC_MODULE_SHORTNAME:
301 module->psz_shortname = va_arg (ap, const char *);
302 break;
304 case VLC_MODULE_DESCRIPTION:
305 // TODO: do not set this in VLC_MODULE_NAME
306 module->psz_longname = va_arg (ap, const char *);
307 break;
309 case VLC_MODULE_HELP:
310 module->psz_help = va_arg (ap, const char *);
311 break;
313 case VLC_MODULE_TEXTDOMAIN:
314 plugin->textdomain = va_arg(ap, const char *);
315 break;
317 case VLC_CONFIG_NAME:
319 const char *name = va_arg (ap, const char *);
321 assert (name != NULL);
322 item->psz_name = name;
323 break;
326 case VLC_CONFIG_VALUE:
328 if (IsConfigIntegerType (item->i_type)
329 || !CONFIG_ITEM(item->i_type))
331 item->orig.i =
332 item->value.i = va_arg (ap, int64_t);
334 else
335 if (IsConfigFloatType (item->i_type))
337 item->orig.f =
338 item->value.f = va_arg (ap, double);
340 else
341 if (IsConfigStringType (item->i_type))
343 const char *value = va_arg (ap, const char *);
344 item->value.psz = value ? strdup (value) : NULL;
345 item->orig.psz = (char *)value;
347 break;
350 case VLC_CONFIG_RANGE:
352 if (IsConfigFloatType (item->i_type))
354 item->min.f = va_arg (ap, double);
355 item->max.f = va_arg (ap, double);
357 else
359 item->min.i = va_arg (ap, int64_t);
360 item->max.i = va_arg (ap, int64_t);
362 break;
365 case VLC_CONFIG_VOLATILE:
366 item->b_unsaveable = true;
367 break;
369 case VLC_CONFIG_PRIVATE:
370 item->b_internal = true;
371 break;
373 case VLC_CONFIG_REMOVED:
374 item->b_removed = true;
375 break;
377 case VLC_CONFIG_CAPABILITY:
378 item->psz_type = va_arg (ap, const char *);
379 break;
381 case VLC_CONFIG_SHORTCUT:
382 item->i_short = va_arg (ap, int);
383 break;
385 case VLC_CONFIG_SAFE:
386 item->b_safe = true;
387 break;
389 case VLC_CONFIG_DESC:
390 item->psz_text = va_arg (ap, const char *);
391 item->psz_longtext = va_arg (ap, const char *);
392 break;
394 case VLC_CONFIG_LIST:
396 size_t len = va_arg (ap, size_t);
398 assert (item->list_count == 0); /* cannot replace choices */
399 assert (item->list.psz_cb == NULL);
400 if (len == 0)
401 break; /* nothing to do */
402 /* Copy values */
403 if (IsConfigIntegerType (item->i_type))
404 item->list.i = va_arg(ap, const int *);
405 else
406 if (IsConfigStringType (item->i_type))
408 const char *const *src = va_arg (ap, const char *const *);
409 const char **dst = xmalloc (sizeof (const char *) * len);
411 memcpy(dst, src, sizeof (const char *) * len);
412 item->list.psz = dst;
414 else
415 break;
417 /* Copy textual descriptions */
418 /* XXX: item->list_text[len + 1] is probably useless. */
419 const char *const *text = va_arg (ap, const char *const *);
420 const char **dtext = xmalloc (sizeof (const char *) * (len + 1));
422 memcpy(dtext, text, sizeof (const char *) * len);
423 item->list_text = dtext;
424 item->list_count = len;
425 break;
428 case VLC_CONFIG_LIST_CB:
430 void *cb;
432 item->list_cb_name = va_arg(ap, const char *);
433 cb = va_arg(ap, void *);
435 if (IsConfigIntegerType (item->i_type))
436 item->list.i_cb = cb;
437 else
438 if (IsConfigStringType (item->i_type))
439 item->list.psz_cb = cb;
440 else
441 break;
442 break;
445 default:
446 fprintf (stderr, "LibVLC: unknown module property %d\n", propid);
447 fprintf (stderr, "LibVLC: too old to use this module?\n");
448 ret = -1;
449 break;
452 va_end (ap);
453 return ret;
457 * Runs a plug-in descriptor.
459 * This loads the plug-in meta-data in memory.
461 vlc_plugin_t *vlc_plugin_describe(vlc_plugin_cb entry)
463 vlc_plugin_t *plugin = vlc_plugin_create();
464 if (unlikely(plugin == NULL))
465 return NULL;
467 if (entry(vlc_plugin_desc_cb, plugin) != 0)
469 vlc_plugin_destroy(plugin); /* partially initialized plug-in... */
470 plugin = NULL;
472 return plugin;
475 struct vlc_plugin_symbol
477 const char *name;
478 void *addr;
481 static int vlc_plugin_symbol_compare(const void *a, const void *b)
483 const struct vlc_plugin_symbol *sa = a , *sb = b;
485 return strcmp(sa->name, sb->name);
489 * Plug-in symbols callback.
491 * This callback generates a mapping of plugin symbol names to symbol
492 * addresses.
494 static int vlc_plugin_gpa_cb(void *ctx, void *tgt, int propid, ...)
496 void **rootp = ctx;
497 const char *name;
498 void *addr;
500 (void) tgt;
502 switch (propid)
504 case VLC_MODULE_CB_OPEN:
505 case VLC_MODULE_CB_CLOSE:
506 case VLC_CONFIG_LIST_CB:
508 va_list ap;
510 va_start(ap, propid);
511 name = va_arg(ap, const char *);
512 addr = va_arg(ap, void *);
513 va_end (ap);
514 break;
516 default:
517 return 0;
520 struct vlc_plugin_symbol *sym = malloc(sizeof (*sym));
522 sym->name = name;
523 sym->addr = addr;
525 struct vlc_plugin_symbol **symp = tsearch(sym, rootp,
526 vlc_plugin_symbol_compare);
527 if (unlikely(symp == NULL))
528 { /* Memory error */
529 free(sym);
530 return -1;
533 if (*symp != sym)
534 { /* Duplicate symbol */
535 assert((*symp)->addr == sym->addr);
536 free(sym);
538 return 0;
542 * Gets the symbols of a plugin.
544 * This function generates a list of symbol names and addresses for a given
545 * plugin descriptor. The result can be used with vlc_plugin_get_symbol()
546 * to resolve a symbol name to an address.
548 * The result must be freed with vlc_plugin_free_symbols(). The result is only
549 * meaningful until the plugin is unloaded.
551 static void *vlc_plugin_get_symbols(vlc_plugin_cb entry)
553 void *root = NULL;
555 if (entry(vlc_plugin_gpa_cb, &root))
557 tdestroy(root, free);
558 return NULL;
561 return root;
564 static void vlc_plugin_free_symbols(void *root)
566 tdestroy(root, free);
569 static int vlc_plugin_get_symbol(void *root, const char *name,
570 void **restrict addrp)
572 if (name == NULL)
573 { /* TODO: use this; do not define "NULL" as a name for NULL? */
574 *addrp = NULL;
575 return 0;
578 const struct vlc_plugin_symbol **symp = tfind(&name, &root,
579 vlc_plugin_symbol_compare);
581 if (symp == NULL)
582 return -1;
584 *addrp = (*symp)->addr;
585 return 0;
588 int vlc_plugin_resolve(vlc_plugin_t *plugin, vlc_plugin_cb entry)
590 void *syms = vlc_plugin_get_symbols(entry);
591 int ret = -1;
593 /* Resolve modules activate/deactivate callbacks */
594 for (module_t *module = plugin->module;
595 module != NULL;
596 module = module->next)
598 if (vlc_plugin_get_symbol(syms, module->activate_name,
599 &module->pf_activate)
600 || vlc_plugin_get_symbol(syms, module->deactivate_name,
601 &module->pf_deactivate))
602 goto error;
605 /* Resolve configuration callbacks */
606 for (size_t i = 0; i < plugin->conf.size; i++)
608 module_config_t *item = plugin->conf.items + i;
609 void *cb;
611 if (item->list_cb_name == NULL)
612 continue;
613 if (vlc_plugin_get_symbol(syms, item->list_cb_name, &cb))
614 goto error;
616 if (IsConfigIntegerType (item->i_type))
617 item->list.i_cb = cb;
618 else
619 if (IsConfigStringType (item->i_type))
620 item->list.psz_cb = cb;
623 ret = 0;
624 error:
625 vlc_plugin_free_symbols(syms);
626 return ret;