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 *****************************************************************************/
26 #include <vlc_common.h>
27 #include <vlc_plugin.h>
36 #include "modules/modules.h"
37 #include "config/configuration.h"
40 module_t
*vlc_module_create(vlc_plugin_t
*plugin
)
42 module_t
*module
= malloc (sizeof (*module
));
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
;
54 plugin
->module
= module
;
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
;
82 void vlc_module_destroy (module_t
*module
)
84 while (module
!= NULL
)
86 module_t
*next
= module
->next
;
88 free(module
->pp_shortcuts
);
94 vlc_plugin_t
*vlc_plugin_create(void)
96 vlc_plugin_t
*plugin
= malloc(sizeof (*plugin
));
97 if (unlikely(plugin
== 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
;
113 plugin
->module
= NULL
;
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);
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
);
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
));
152 plugin
->conf
.items
= tab
;
155 memset (tab
+ confsize
, 0, sizeof (tab
[confsize
]));
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
;
171 if (CONFIG_ITEM(type
))
173 plugin
->conf
.count
++;
174 if (type
== CONFIG_ITEM_BOOL
)
175 plugin
->conf
.booleans
++;
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
;
196 va_start (ap
, 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
))
209 *(va_arg (ap
, module_t
**)) = submodule
;
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
;
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
))
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
))
254 module
->pp_shortcuts
= pp
;
255 module
->i_shortcuts
= index
+ i_shortcuts
;
257 for (unsigned i
= 0; i
< i_shortcuts
; i
++)
262 case VLC_MODULE_CAPABILITY
:
263 module
->psz_capability
= va_arg (ap
, const char *);
266 case VLC_MODULE_SCORE
:
267 module
->i_score
= va_arg (ap
, int);
270 case VLC_MODULE_CB_OPEN
:
271 module
->activate_name
= va_arg(ap
, const char *);
272 module
->pf_activate
= va_arg (ap
, void *);
275 case VLC_MODULE_CB_CLOSE
:
276 module
->deactivate_name
= va_arg(ap
, const char *);
277 module
->pf_deactivate
= va_arg (ap
, void *);
280 case VLC_MODULE_NO_UNLOAD
:
281 #ifdef HAVE_DYNAMIC_PLUGINS
282 plugin
->unloadable
= false;
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
;
300 case VLC_MODULE_SHORTNAME
:
301 module
->psz_shortname
= va_arg (ap
, const char *);
304 case VLC_MODULE_DESCRIPTION
:
305 // TODO: do not set this in VLC_MODULE_NAME
306 module
->psz_longname
= va_arg (ap
, const char *);
309 case VLC_MODULE_HELP
:
310 module
->psz_help
= va_arg (ap
, const char *);
313 case VLC_MODULE_TEXTDOMAIN
:
314 plugin
->textdomain
= va_arg(ap
, const char *);
317 case VLC_CONFIG_NAME
:
319 const char *name
= va_arg (ap
, const char *);
321 assert (name
!= NULL
);
322 item
->psz_name
= name
;
326 case VLC_CONFIG_VALUE
:
328 if (IsConfigIntegerType (item
->i_type
)
329 || !CONFIG_ITEM(item
->i_type
))
332 item
->value
.i
= va_arg (ap
, int64_t);
335 if (IsConfigFloatType (item
->i_type
))
338 item
->value
.f
= va_arg (ap
, double);
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
;
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);
359 item
->min
.i
= va_arg (ap
, int64_t);
360 item
->max
.i
= va_arg (ap
, int64_t);
365 case VLC_CONFIG_VOLATILE
:
366 item
->b_unsaveable
= true;
369 case VLC_CONFIG_PRIVATE
:
370 item
->b_internal
= true;
373 case VLC_CONFIG_REMOVED
:
374 item
->b_removed
= true;
377 case VLC_CONFIG_CAPABILITY
:
378 item
->psz_type
= va_arg (ap
, const char *);
381 case VLC_CONFIG_SHORTCUT
:
382 item
->i_short
= va_arg (ap
, int);
385 case VLC_CONFIG_SAFE
:
389 case VLC_CONFIG_DESC
:
390 item
->psz_text
= va_arg (ap
, const char *);
391 item
->psz_longtext
= va_arg (ap
, const char *);
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
);
401 break; /* nothing to do */
403 if (IsConfigIntegerType (item
->i_type
))
404 item
->list
.i
= va_arg(ap
, const int *);
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
;
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
;
428 case VLC_CONFIG_LIST_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
;
438 if (IsConfigStringType (item
->i_type
))
439 item
->list
.psz_cb
= cb
;
446 fprintf (stderr
, "LibVLC: unknown module property %d\n", propid
);
447 fprintf (stderr
, "LibVLC: too old to use this module?\n");
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
))
467 if (entry(vlc_plugin_desc_cb
, plugin
) != 0)
469 vlc_plugin_destroy(plugin
); /* partially initialized plug-in... */
475 struct vlc_plugin_symbol
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
494 static int vlc_plugin_gpa_cb(void *ctx
, void *tgt
, int propid
, ...)
504 case VLC_MODULE_CB_OPEN
:
505 case VLC_MODULE_CB_CLOSE
:
506 case VLC_CONFIG_LIST_CB
:
510 va_start(ap
, propid
);
511 name
= va_arg(ap
, const char *);
512 addr
= va_arg(ap
, void *);
520 struct vlc_plugin_symbol
*sym
= malloc(sizeof (*sym
));
525 struct vlc_plugin_symbol
**symp
= tsearch(sym
, rootp
,
526 vlc_plugin_symbol_compare
);
527 if (unlikely(symp
== NULL
))
534 { /* Duplicate symbol */
535 assert((*symp
)->addr
== sym
->addr
);
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
)
555 if (entry(vlc_plugin_gpa_cb
, &root
))
557 tdestroy(root
, free
);
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
)
573 { /* TODO: use this; do not define "NULL" as a name for NULL? */
578 const struct vlc_plugin_symbol
**symp
= tfind(&name
, &root
,
579 vlc_plugin_symbol_compare
);
584 *addrp
= (*symp
)->addr
;
588 int vlc_plugin_resolve(vlc_plugin_t
*plugin
, vlc_plugin_cb entry
)
590 void *syms
= vlc_plugin_get_symbols(entry
);
593 /* Resolve modules activate/deactivate callbacks */
594 for (module_t
*module
= plugin
->module
;
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
))
605 /* Resolve configuration callbacks */
606 for (size_t i
= 0; i
< plugin
->conf
.size
; i
++)
608 module_config_t
*item
= plugin
->conf
.items
+ i
;
611 if (item
->list_cb_name
== NULL
)
613 if (vlc_plugin_get_symbol(syms
, item
->list_cb_name
, &cb
))
616 if (IsConfigIntegerType (item
->i_type
))
617 item
->list
.i_cb
= cb
;
619 if (IsConfigStringType (item
->i_type
))
620 item
->list
.psz_cb
= cb
;
625 vlc_plugin_free_symbols(syms
);