qt: actions_manager: compareRenderers -> getMatchingRenderer
[vlc.git] / src / modules / entry.c
blob29044fa5d43bdff83d62f6f635c09f8bab66127b
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 <vlc_memory.h>
29 #include <assert.h>
30 #include <stdarg.h>
31 #include <limits.h>
32 #include <float.h>
33 #ifdef HAVE_SEARCH_H
34 # include <search.h>
35 #endif
37 #include "modules/modules.h"
38 #include "config/configuration.h"
39 #include "libvlc.h"
41 module_t *vlc_module_create(vlc_plugin_t *plugin)
43 module_t *module = malloc (sizeof (*module));
44 if (module == NULL)
45 return NULL;
47 /* NOTE XXX: For backward compatibility with preferences UIs, the first
48 * module must stay first. That defines under which module, the
49 * configuration items of the plugin belong. The order of the following
50 * entries is irrelevant. */
51 module_t *parent = plugin->module;
52 if (parent == NULL)
54 module->next = NULL;
55 plugin->module = module;
57 else
59 module->next = parent->next;
60 parent->next = module;
63 plugin->modules_count++;
64 module->plugin = plugin;
66 module->psz_shortname = NULL;
67 module->psz_longname = NULL;
68 module->psz_help = NULL;
69 module->pp_shortcuts = NULL;
70 module->i_shortcuts = 0;
71 module->psz_capability = NULL;
72 module->i_score = (parent != NULL) ? parent->i_score : 1;
73 module->activate_name = NULL;
74 module->deactivate_name = NULL;
75 module->pf_activate = NULL;
76 module->pf_deactivate = NULL;
77 return module;
80 /**
81 * Destroys a module.
83 void vlc_module_destroy (module_t *module)
85 while (module != NULL)
87 module_t *next = module->next;
89 free(module->pp_shortcuts);
90 free(module);
91 module = next;
95 vlc_plugin_t *vlc_plugin_create(void)
97 vlc_plugin_t *plugin = malloc(sizeof (*plugin));
98 if (unlikely(plugin == NULL))
99 return NULL;
101 plugin->modules_count = 0;
102 plugin->textdomain = NULL;
103 plugin->conf.items = NULL;
104 plugin->conf.size = 0;
105 plugin->conf.count = 0;
106 plugin->conf.booleans = 0;
107 #ifdef HAVE_DYNAMIC_PLUGINS
108 plugin->abspath = NULL;
109 atomic_init(&plugin->loaded, false);
110 plugin->unloadable = true;
111 plugin->handle = NULL;
112 plugin->abspath = NULL;
113 plugin->path = NULL;
114 #endif
115 plugin->module = NULL;
117 return plugin;
121 * Destroys a plug-in.
122 * @warning If the plug-in was dynamically loaded in memory, the library handle
123 * and associated memory mappings and linker resources will be leaked.
125 void vlc_plugin_destroy(vlc_plugin_t *plugin)
127 assert(plugin != NULL);
128 #ifdef HAVE_DYNAMIC_PLUGINS
129 assert(!plugin->unloadable || !atomic_load(&plugin->loaded));
130 #endif
132 if (plugin->module != NULL)
133 vlc_module_destroy(plugin->module);
135 config_Free(plugin->conf.items, plugin->conf.size);
136 #ifdef HAVE_DYNAMIC_PLUGINS
137 free(plugin->abspath);
138 free(plugin->path);
139 #endif
140 free(plugin);
143 static module_config_t *vlc_config_create(vlc_plugin_t *plugin, int type)
145 unsigned confsize = plugin->conf.size;
146 module_config_t *tab = plugin->conf.items;
148 if ((confsize & 0xf) == 0)
150 tab = realloc_or_free (tab, (confsize + 17) * sizeof (*tab));
151 if (tab == NULL)
152 return NULL;
154 plugin->conf.items = tab;
157 memset (tab + confsize, 0, sizeof (tab[confsize]));
158 tab += confsize;
159 tab->owner = plugin;
161 if (IsConfigIntegerType (type))
163 tab->max.i = INT64_MAX;
164 tab->min.i = INT64_MIN;
166 else if( IsConfigFloatType (type))
168 tab->max.f = FLT_MAX;
169 tab->min.f = -FLT_MAX;
171 tab->i_type = type;
173 if (CONFIG_ITEM(type))
175 plugin->conf.count++;
176 if (type == CONFIG_ITEM_BOOL)
177 plugin->conf.booleans++;
179 plugin->conf.size++;
181 return tab;
185 * Plug-in descriptor callback.
187 * This callback populates modules, configuration items and properties of a
188 * plug-in from the plug-in descriptor.
190 static int vlc_plugin_desc_cb(void *ctx, void *tgt, int propid, ...)
192 vlc_plugin_t *plugin = ctx;
193 module_t *module = tgt;
194 module_config_t *item = tgt;
195 va_list ap;
196 int ret = 0;
198 va_start (ap, propid);
199 switch (propid)
201 case VLC_MODULE_CREATE:
203 module_t *super = plugin->module;
204 module_t *submodule = vlc_module_create(plugin);
205 if (unlikely(submodule == NULL))
207 ret = -1;
208 break;
211 *(va_arg (ap, module_t **)) = submodule;
212 if (super == NULL)
213 break;
215 /* Inheritance. Ugly!! */
216 submodule->pp_shortcuts = xmalloc (sizeof ( *submodule->pp_shortcuts ));
217 submodule->pp_shortcuts[0] = super->pp_shortcuts[0];
218 submodule->i_shortcuts = 1; /* object name */
220 submodule->psz_shortname = super->psz_shortname;
221 submodule->psz_longname = super->psz_longname;
222 submodule->psz_capability = super->psz_capability;
223 break;
226 case VLC_CONFIG_CREATE:
228 int type = va_arg (ap, int);
229 module_config_t **pp = va_arg (ap, module_config_t **);
231 item = vlc_config_create(plugin, type);
232 if (unlikely(item == NULL))
234 ret = -1;
235 break;
237 *pp = item;
238 break;
241 case VLC_MODULE_SHORTCUT:
243 unsigned i_shortcuts = va_arg (ap, unsigned);
244 unsigned index = module->i_shortcuts;
245 /* The cache loader accept only a small number of shortcuts */
246 assert(i_shortcuts + index <= MODULE_SHORTCUT_MAX);
248 const char *const *tab = va_arg (ap, const char *const *);
249 const char **pp = realloc (module->pp_shortcuts,
250 sizeof (pp[0]) * (index + i_shortcuts));
251 if (unlikely(pp == NULL))
253 ret = -1;
254 break;
256 module->pp_shortcuts = pp;
257 module->i_shortcuts = index + i_shortcuts;
258 pp += index;
259 for (unsigned i = 0; i < i_shortcuts; i++)
260 pp[i] = tab[i];
261 break;
264 case VLC_MODULE_CAPABILITY:
265 module->psz_capability = va_arg (ap, const char *);
266 break;
268 case VLC_MODULE_SCORE:
269 module->i_score = va_arg (ap, int);
270 break;
272 case VLC_MODULE_CB_OPEN:
273 module->activate_name = va_arg(ap, const char *);
274 module->pf_activate = va_arg (ap, void *);
275 break;
277 case VLC_MODULE_CB_CLOSE:
278 module->deactivate_name = va_arg(ap, const char *);
279 module->pf_deactivate = va_arg (ap, void *);
280 break;
282 case VLC_MODULE_NO_UNLOAD:
283 #ifdef HAVE_DYNAMIC_PLUGINS
284 plugin->unloadable = false;
285 #endif
286 break;
288 case VLC_MODULE_NAME:
290 const char *value = va_arg (ap, const char *);
292 assert (module->i_shortcuts == 0);
293 module->pp_shortcuts = malloc( sizeof( *module->pp_shortcuts ) );
294 module->pp_shortcuts[0] = value;
295 module->i_shortcuts = 1;
297 assert (module->psz_longname == NULL);
298 module->psz_longname = value;
299 break;
302 case VLC_MODULE_SHORTNAME:
303 module->psz_shortname = va_arg (ap, const char *);
304 break;
306 case VLC_MODULE_DESCRIPTION:
307 // TODO: do not set this in VLC_MODULE_NAME
308 module->psz_longname = va_arg (ap, const char *);
309 break;
311 case VLC_MODULE_HELP:
312 module->psz_help = va_arg (ap, const char *);
313 break;
315 case VLC_MODULE_TEXTDOMAIN:
316 plugin->textdomain = va_arg(ap, const char *);
317 break;
319 case VLC_CONFIG_NAME:
321 const char *name = va_arg (ap, const char *);
323 assert (name != NULL);
324 item->psz_name = name;
325 break;
328 case VLC_CONFIG_VALUE:
330 if (IsConfigIntegerType (item->i_type)
331 || !CONFIG_ITEM(item->i_type))
333 item->orig.i =
334 item->value.i = va_arg (ap, int64_t);
336 else
337 if (IsConfigFloatType (item->i_type))
339 item->orig.f =
340 item->value.f = va_arg (ap, double);
342 else
343 if (IsConfigStringType (item->i_type))
345 const char *value = va_arg (ap, const char *);
346 item->value.psz = value ? strdup (value) : NULL;
347 item->orig.psz = (char *)value;
349 break;
352 case VLC_CONFIG_RANGE:
354 if (IsConfigFloatType (item->i_type))
356 item->min.f = va_arg (ap, double);
357 item->max.f = va_arg (ap, double);
359 else
361 item->min.i = va_arg (ap, int64_t);
362 item->max.i = va_arg (ap, int64_t);
364 break;
367 case VLC_CONFIG_ADVANCED:
368 item->b_advanced = true;
369 break;
371 case VLC_CONFIG_VOLATILE:
372 item->b_unsaveable = true;
373 break;
375 case VLC_CONFIG_PRIVATE:
376 item->b_internal = true;
377 break;
379 case VLC_CONFIG_REMOVED:
380 item->b_removed = true;
381 break;
383 case VLC_CONFIG_CAPABILITY:
384 item->psz_type = va_arg (ap, const char *);
385 break;
387 case VLC_CONFIG_SHORTCUT:
388 item->i_short = va_arg (ap, int);
389 break;
391 case VLC_CONFIG_SAFE:
392 item->b_safe = true;
393 break;
395 case VLC_CONFIG_DESC:
396 item->psz_text = va_arg (ap, const char *);
397 item->psz_longtext = va_arg (ap, const char *);
398 break;
400 case VLC_CONFIG_LIST:
402 size_t len = va_arg (ap, size_t);
404 assert (item->list_count == 0); /* cannot replace choices */
405 assert (item->list.psz_cb == NULL);
406 if (len == 0)
407 break; /* nothing to do */
408 /* Copy values */
409 if (IsConfigIntegerType (item->i_type))
410 item->list.i = va_arg(ap, const int *);
411 else
412 if (IsConfigStringType (item->i_type))
414 const char *const *src = va_arg (ap, const char *const *);
415 const char **dst = xmalloc (sizeof (const char *) * len);
417 memcpy(dst, src, sizeof (const char *) * len);
418 item->list.psz = dst;
420 else
421 break;
423 /* Copy textual descriptions */
424 /* XXX: item->list_text[len + 1] is probably useless. */
425 const char *const *text = va_arg (ap, const char *const *);
426 const char **dtext = xmalloc (sizeof (const char *) * (len + 1));
428 memcpy(dtext, text, sizeof (const char *) * len);
429 item->list_text = dtext;
430 item->list_count = len;
431 break;
434 case VLC_CONFIG_LIST_CB:
436 void *cb;
438 item->list_cb_name = va_arg(ap, const char *);
439 cb = va_arg(ap, void *);
441 if (IsConfigIntegerType (item->i_type))
442 item->list.i_cb = cb;
443 else
444 if (IsConfigStringType (item->i_type))
445 item->list.psz_cb = cb;
446 else
447 break;
448 break;
451 default:
452 fprintf (stderr, "LibVLC: unknown module property %d\n", propid);
453 fprintf (stderr, "LibVLC: too old to use this module?\n");
454 ret = -1;
455 break;
458 va_end (ap);
459 return ret;
463 * Runs a plug-in descriptor.
465 * This loads the plug-in meta-data in memory.
467 vlc_plugin_t *vlc_plugin_describe(vlc_plugin_cb entry)
469 vlc_plugin_t *plugin = vlc_plugin_create();
470 if (unlikely(plugin == NULL))
471 return NULL;
473 if (entry(vlc_plugin_desc_cb, plugin) != 0)
475 vlc_plugin_destroy(plugin); /* partially initialized plug-in... */
476 plugin = NULL;
478 return plugin;
481 struct vlc_plugin_symbol
483 const char *name;
484 void *addr;
487 static int vlc_plugin_symbol_compare(const void *a, const void *b)
489 const struct vlc_plugin_symbol *sa = a , *sb = b;
491 return strcmp(sa->name, sb->name);
495 * Plug-in symbols callback.
497 * This callback generates a mapping of plugin symbol names to symbol
498 * addresses.
500 static int vlc_plugin_gpa_cb(void *ctx, void *tgt, int propid, ...)
502 void **rootp = ctx;
503 const char *name;
504 void *addr;
506 (void) tgt;
508 switch (propid)
510 case VLC_MODULE_CB_OPEN:
511 case VLC_MODULE_CB_CLOSE:
512 case VLC_CONFIG_LIST_CB:
514 va_list ap;
516 va_start(ap, propid);
517 name = va_arg(ap, const char *);
518 addr = va_arg(ap, void *);
519 va_end (ap);
520 break;
522 default:
523 return 0;
526 struct vlc_plugin_symbol *sym = malloc(sizeof (*sym));
528 sym->name = name;
529 sym->addr = addr;
531 struct vlc_plugin_symbol **symp = tsearch(sym, rootp,
532 vlc_plugin_symbol_compare);
533 if (unlikely(symp == NULL))
534 { /* Memory error */
535 free(sym);
536 return -1;
539 if (*symp != sym)
540 { /* Duplicate symbol */
541 assert((*symp)->addr == sym->addr);
542 free(sym);
544 return 0;
548 * Gets the symbols of a plugin.
550 * This function generates a list of symbol names and addresses for a given
551 * plugin descriptor. The result can be used with vlc_plugin_get_symbol()
552 * to resolve a symbol name to an address.
554 * The result must be freed with vlc_plugin_free_symbols(). The result is only
555 * meaningful until the plugin is unloaded.
557 static void *vlc_plugin_get_symbols(vlc_plugin_cb entry)
559 void *root = NULL;
561 if (entry(vlc_plugin_gpa_cb, &root))
563 tdestroy(root, free);
564 return NULL;
567 return root;
570 static void vlc_plugin_free_symbols(void *root)
572 tdestroy(root, free);
575 static int vlc_plugin_get_symbol(void *root, const char *name,
576 void **restrict addrp)
578 if (name == NULL)
579 { /* TODO: use this; do not define "NULL" as a name for NULL? */
580 *addrp = NULL;
581 return 0;
584 const struct vlc_plugin_symbol **symp = tfind(&name, &root,
585 vlc_plugin_symbol_compare);
587 if (symp == NULL)
588 return -1;
590 *addrp = (*symp)->addr;
591 return 0;
594 int vlc_plugin_resolve(vlc_plugin_t *plugin, vlc_plugin_cb entry)
596 void *syms = vlc_plugin_get_symbols(entry);
597 int ret = -1;
599 /* Resolve modules activate/deactivate callbacks */
600 for (module_t *module = plugin->module;
601 module != NULL;
602 module = module->next)
604 if (vlc_plugin_get_symbol(syms, module->activate_name,
605 &module->pf_activate)
606 || vlc_plugin_get_symbol(syms, module->deactivate_name,
607 &module->pf_deactivate))
608 goto error;
611 /* Resolve configuration callbacks */
612 for (size_t i = 0; i < plugin->conf.size; i++)
614 module_config_t *item = plugin->conf.items + i;
615 void *cb;
617 if (item->list_cb_name == NULL)
618 continue;
619 if (vlc_plugin_get_symbol(syms, item->list_cb_name, &cb))
620 goto error;
622 if (IsConfigIntegerType (item->i_type))
623 item->list.i_cb = cb;
624 else
625 if (IsConfigStringType (item->i_type))
626 item->list.psz_cb = cb;
629 ret = 0;
630 error:
631 vlc_plugin_free_symbols(syms);
632 return ret;