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>
28 #include <vlc_memory.h>
37 #include "modules/modules.h"
38 #include "config/configuration.h"
41 module_t
*vlc_module_create(vlc_plugin_t
*plugin
)
43 module_t
*module
= malloc (sizeof (*module
));
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
;
55 plugin
->module
= module
;
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
;
83 void vlc_module_destroy (module_t
*module
)
85 while (module
!= NULL
)
87 module_t
*next
= module
->next
;
89 free(module
->pp_shortcuts
);
95 vlc_plugin_t
*vlc_plugin_create(void)
97 vlc_plugin_t
*plugin
= malloc(sizeof (*plugin
));
98 if (unlikely(plugin
== 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
;
115 plugin
->module
= NULL
;
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
));
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
);
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
));
154 plugin
->conf
.items
= tab
;
157 memset (tab
+ confsize
, 0, sizeof (tab
[confsize
]));
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
;
173 if (CONFIG_ITEM(type
))
175 plugin
->conf
.count
++;
176 if (type
== CONFIG_ITEM_BOOL
)
177 plugin
->conf
.booleans
++;
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
;
198 va_start (ap
, 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
))
211 *(va_arg (ap
, module_t
**)) = submodule
;
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
;
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
))
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
))
256 module
->pp_shortcuts
= pp
;
257 module
->i_shortcuts
= index
+ i_shortcuts
;
259 for (unsigned i
= 0; i
< i_shortcuts
; i
++)
264 case VLC_MODULE_CAPABILITY
:
265 module
->psz_capability
= va_arg (ap
, const char *);
268 case VLC_MODULE_SCORE
:
269 module
->i_score
= va_arg (ap
, int);
272 case VLC_MODULE_CB_OPEN
:
273 module
->activate_name
= va_arg(ap
, const char *);
274 module
->pf_activate
= va_arg (ap
, void *);
277 case VLC_MODULE_CB_CLOSE
:
278 module
->deactivate_name
= va_arg(ap
, const char *);
279 module
->pf_deactivate
= va_arg (ap
, void *);
282 case VLC_MODULE_NO_UNLOAD
:
283 #ifdef HAVE_DYNAMIC_PLUGINS
284 plugin
->unloadable
= false;
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
;
302 case VLC_MODULE_SHORTNAME
:
303 module
->psz_shortname
= va_arg (ap
, const char *);
306 case VLC_MODULE_DESCRIPTION
:
307 // TODO: do not set this in VLC_MODULE_NAME
308 module
->psz_longname
= va_arg (ap
, const char *);
311 case VLC_MODULE_HELP
:
312 module
->psz_help
= va_arg (ap
, const char *);
315 case VLC_MODULE_TEXTDOMAIN
:
316 plugin
->textdomain
= va_arg(ap
, const char *);
319 case VLC_CONFIG_NAME
:
321 const char *name
= va_arg (ap
, const char *);
323 assert (name
!= NULL
);
324 item
->psz_name
= name
;
328 case VLC_CONFIG_VALUE
:
330 if (IsConfigIntegerType (item
->i_type
)
331 || !CONFIG_ITEM(item
->i_type
))
334 item
->value
.i
= va_arg (ap
, int64_t);
337 if (IsConfigFloatType (item
->i_type
))
340 item
->value
.f
= va_arg (ap
, double);
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
;
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);
361 item
->min
.i
= va_arg (ap
, int64_t);
362 item
->max
.i
= va_arg (ap
, int64_t);
367 case VLC_CONFIG_ADVANCED
:
368 item
->b_advanced
= true;
371 case VLC_CONFIG_VOLATILE
:
372 item
->b_unsaveable
= true;
375 case VLC_CONFIG_PRIVATE
:
376 item
->b_internal
= true;
379 case VLC_CONFIG_REMOVED
:
380 item
->b_removed
= true;
383 case VLC_CONFIG_CAPABILITY
:
384 item
->psz_type
= va_arg (ap
, const char *);
387 case VLC_CONFIG_SHORTCUT
:
388 item
->i_short
= va_arg (ap
, int);
391 case VLC_CONFIG_SAFE
:
395 case VLC_CONFIG_DESC
:
396 item
->psz_text
= va_arg (ap
, const char *);
397 item
->psz_longtext
= va_arg (ap
, const char *);
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
);
407 break; /* nothing to do */
409 if (IsConfigIntegerType (item
->i_type
))
410 item
->list
.i
= va_arg(ap
, const int *);
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
;
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
;
434 case VLC_CONFIG_LIST_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
;
444 if (IsConfigStringType (item
->i_type
))
445 item
->list
.psz_cb
= cb
;
452 fprintf (stderr
, "LibVLC: unknown module property %d\n", propid
);
453 fprintf (stderr
, "LibVLC: too old to use this module?\n");
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
))
473 if (entry(vlc_plugin_desc_cb
, plugin
) != 0)
475 vlc_plugin_destroy(plugin
); /* partially initialized plug-in... */
481 struct vlc_plugin_symbol
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
500 static int vlc_plugin_gpa_cb(void *ctx
, void *tgt
, int propid
, ...)
510 case VLC_MODULE_CB_OPEN
:
511 case VLC_MODULE_CB_CLOSE
:
512 case VLC_CONFIG_LIST_CB
:
516 va_start(ap
, propid
);
517 name
= va_arg(ap
, const char *);
518 addr
= va_arg(ap
, void *);
526 struct vlc_plugin_symbol
*sym
= malloc(sizeof (*sym
));
531 struct vlc_plugin_symbol
**symp
= tsearch(sym
, rootp
,
532 vlc_plugin_symbol_compare
);
533 if (unlikely(symp
== NULL
))
540 { /* Duplicate symbol */
541 assert((*symp
)->addr
== sym
->addr
);
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
)
561 if (entry(vlc_plugin_gpa_cb
, &root
))
563 tdestroy(root
, free
);
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
)
579 { /* TODO: use this; do not define "NULL" as a name for NULL? */
584 const struct vlc_plugin_symbol
**symp
= tfind(&name
, &root
,
585 vlc_plugin_symbol_compare
);
590 *addrp
= (*symp
)->addr
;
594 int vlc_plugin_resolve(vlc_plugin_t
*plugin
, vlc_plugin_cb entry
)
596 void *syms
= vlc_plugin_get_symbols(entry
);
599 /* Resolve modules activate/deactivate callbacks */
600 for (module_t
*module
= plugin
->module
;
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
))
611 /* Resolve configuration callbacks */
612 for (size_t i
= 0; i
< plugin
->conf
.size
; i
++)
614 module_config_t
*item
= plugin
->conf
.items
+ i
;
617 if (item
->list_cb_name
== NULL
)
619 if (vlc_plugin_get_symbol(syms
, item
->list_cb_name
, &cb
))
622 if (IsConfigIntegerType (item
->i_type
))
623 item
->list
.i_cb
= cb
;
625 if (IsConfigStringType (item
->i_type
))
626 item
->list
.psz_cb
= cb
;
631 vlc_plugin_free_symbols(syms
);