]> git.sesse.net Git - vlc/blob - src/modules/modules.c
846b804dc5a48bbce69510bc36ea9f916702a9ae
[vlc] / src / modules / modules.c
1 /*****************************************************************************
2  * modules.c : Builtin and plugin modules management functions
3  *****************************************************************************
4  * Copyright (C) 2001-2011 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Sam Hocevar <sam@zoy.org>
8  *          Ethan C. Baldridge <BaldridgeE@cadmus.com>
9  *          Hans-Peter Jansen <hpj@urpla.net>
10  *          Gildas Bazin <gbazin@videolan.org>
11  *          RĂ©mi Denis-Courmont
12  *
13  * This program is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation; either version 2 of the License, or
16  * (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
26  *****************************************************************************/
27
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include <stdlib.h>
33 #include <string.h>
34 #ifdef ENABLE_NLS
35 # include <libintl.h>
36 #endif
37 #include <assert.h>
38
39 #include <vlc_common.h>
40 #include <vlc_modules.h>
41 #include "libvlc.h"
42 #include "config/configuration.h"
43 #include "vlc_arrays.h"
44 #include "modules/modules.h"
45
46 /**
47  * Checks whether a module implements a capability.
48  *
49  * \param m the module
50  * \param cap the capability to check
51  * \return TRUE if the module have the capability
52  */
53 bool module_provides( const module_t *m, const char *cap )
54 {
55     if (unlikely(m->psz_capability == NULL))
56         return false;
57     return !strcmp( m->psz_capability, cap );
58 }
59
60 /**
61  * Get the internal name of a module
62  *
63  * \param m the module
64  * \return the module name
65  */
66 const char *module_get_object( const module_t *m )
67 {
68     if (unlikely(m->i_shortcuts == 0))
69         return "unnamed";
70     return m->pp_shortcuts[0];
71 }
72
73 /**
74  * Get the human-friendly name of a module.
75  *
76  * \param m the module
77  * \param long_name TRUE to have the long name of the module
78  * \return the short or long name of the module
79  */
80 const char *module_get_name( const module_t *m, bool long_name )
81 {
82     if( long_name && ( m->psz_longname != NULL) )
83         return m->psz_longname;
84
85     if (m->psz_shortname != NULL)
86         return m->psz_shortname;
87     return module_get_object (m);
88 }
89
90 /**
91  * Get the help for a module
92  *
93  * \param m the module
94  * \return the help
95  */
96 const char *module_get_help( const module_t *m )
97 {
98     return m->psz_help;
99 }
100
101 /**
102  * Get the capability for a module
103  *
104  * \param m the module
105  * return the capability
106  */
107 const char *module_get_capability( const module_t *m )
108 {
109     return m->psz_capability;
110 }
111
112 /**
113  * Get the score for a module
114  *
115  * \param m the module
116  * return the score for the capability
117  */
118 int module_get_score( const module_t *m )
119 {
120     return m->i_score;
121 }
122
123 /**
124  * Translate a string using the module's text domain
125  *
126  * \param m the module
127  * \param str the American English ASCII string to localize
128  * \return the gettext-translated string
129  */
130 const char *module_gettext (const module_t *m, const char *str)
131 {
132     if (m->parent != NULL)
133         m = m->parent;
134     if (unlikely(str == NULL || *str == '\0'))
135         return "";
136 #ifdef ENABLE_NLS
137     const char *domain = m->domain;
138     return dgettext ((domain != NULL) ? domain : PACKAGE_NAME, str);
139 #else
140     (void)m;
141     return str;
142 #endif
143 }
144
145 #undef module_start
146 int module_start (vlc_object_t *obj, const module_t *m)
147 {
148    int (*activate) (vlc_object_t *) = m->pf_activate;
149
150    return (activate != NULL) ? activate (obj) : VLC_SUCCESS;
151 }
152
153 #undef module_stop
154 void module_stop (vlc_object_t *obj, const module_t *m)
155 {
156    void (*deactivate) (vlc_object_t *) = m->pf_deactivate;
157
158     if (deactivate != NULL)
159         deactivate (obj);
160 }
161
162 typedef struct module_list_t
163 {
164     module_t *p_module;
165     int16_t  i_score;
166     bool     b_force;
167 } module_list_t;
168
169 static int modulecmp (const void *a, const void *b)
170 {
171     const module_list_t *la = a, *lb = b;
172     /* Note that qsort() uses _ascending_ order,
173      * so the smallest module is the one with the biggest score. */
174     return lb->i_score - la->i_score;
175 }
176
177 #undef vlc_module_load
178 /**
179  * Finds and instantiates the best module of a certain type.
180  * All candidates modules having the specified capability and name will be
181  * sorted in decreasing order of priority. Then the probe callback will be
182  * invoked for each module, until it succeeds (returns 0), or all candidate
183  * module failed to initialize.
184  *
185  * The probe callback first parameter is the address of the module entry point.
186  * Further parameters are passed as an argument list; it corresponds to the
187  * variable arguments passed to this function. This scheme is meant to
188  * support arbitrary prototypes for the module entry point.
189  *
190  * \param p_this VLC object
191  * \param psz_capability capability, i.e. class of module
192  * \param psz_name name name of the module asked, if any
193  * \param b_strict if true, do not fallback to plugin with a different name
194  *                 but the same capability
195  * \param probe module probe callback
196  * \return the module or NULL in case of a failure
197  */
198 module_t *vlc_module_load(vlc_object_t *p_this, const char *psz_capability,
199                           const char *psz_name, bool b_strict,
200                           vlc_activate_t probe, ...)
201 {
202     stats_TimerStart( p_this, "module_need()", STATS_TIMER_MODULE_NEED );
203
204     module_list_t *p_list;
205     module_t *p_module;
206     int i_shortcuts = 0;
207     char *psz_shortcuts = NULL, *psz_var = NULL, *psz_alias = NULL;
208     bool b_force_backup = p_this->b_force;
209
210     /* Deal with variables */
211     if( psz_name && psz_name[0] == '$' )
212     {
213         psz_name = psz_var = var_CreateGetString( p_this, psz_name + 1 );
214     }
215
216     /* Count how many different shortcuts were asked for */
217     if( psz_name && *psz_name )
218     {
219         char *psz_parser, *psz_last_shortcut;
220
221         /* If the user wants none, give him none. */
222         if( !strcmp( psz_name, "none" ) )
223         {
224             free( psz_var );
225             stats_TimerStop( p_this, STATS_TIMER_MODULE_NEED );
226             stats_TimerDump( p_this, STATS_TIMER_MODULE_NEED );
227             stats_TimerClean( p_this, STATS_TIMER_MODULE_NEED );
228             return NULL;
229         }
230
231         i_shortcuts++;
232         psz_parser = psz_shortcuts = psz_last_shortcut = strdup( psz_name );
233
234         while( ( psz_parser = strchr( psz_parser, ',' ) ) )
235         {
236              *psz_parser = '\0';
237              i_shortcuts++;
238              psz_last_shortcut = ++psz_parser;
239         }
240
241         /* Check if the user wants to override the "strict" mode */
242         if( psz_last_shortcut )
243         {
244             if( !strcmp(psz_last_shortcut, "none") )
245             {
246                 b_strict = true;
247                 i_shortcuts--;
248             }
249             else if( !strcmp(psz_last_shortcut, "any") )
250             {
251                 b_strict = false;
252                 i_shortcuts--;
253             }
254         }
255     }
256
257     /* Sort the modules and test them */
258     size_t count;
259     module_t **p_all = module_list_get (&count);
260     p_list = malloc( count * sizeof( module_list_t ) );
261
262     /* Parse the module list for capabilities and probe each of them */
263     count = 0;
264     for (size_t i = 0; (p_module = p_all[i]) != NULL; i++)
265     {
266         int i_shortcut_bonus = 0;
267
268         /* Test that this module can do what we need */
269         if( !module_provides( p_module, psz_capability ) )
270             continue;
271
272         /* If we required a shortcut, check this plugin provides it. */
273         if( i_shortcuts > 0 )
274         {
275             const char *name = psz_shortcuts;
276
277             for( unsigned i_short = i_shortcuts; i_short > 0; i_short-- )
278             {
279                 for( unsigned i = 0; i < p_module->i_shortcuts; i++ )
280                 {
281                     char *c;
282                     if( ( c = strchr( name, '@' ) )
283                         ? !strncasecmp( name, p_module->pp_shortcuts[i],
284                                         c-name )
285                         : !strcasecmp( name, p_module->pp_shortcuts[i] ) )
286                     {
287                         /* Found it */
288                         if( c && c[1] )
289                             psz_alias = c+1;
290                         i_shortcut_bonus = i_short * 10000;
291                         goto found_shortcut;
292                     }
293                 }
294
295                 /* Go to the next shortcut... This is so lame! */
296                 name += strlen( name ) + 1;
297             }
298
299             /* If we are in "strict" mode and we couldn't
300              * find the module in the list of provided shortcuts,
301              * then kick the bastard out of here!!! */
302             if( b_strict )
303                 continue;
304         }
305
306         /* Trash <= 0 scored plugins (they can only be selected by shortcut) */
307         if( p_module->i_score <= 0 )
308             continue;
309
310 found_shortcut:
311         /* Store this new module */
312         p_list[count].p_module = p_module;
313         p_list[count].i_score = p_module->i_score + i_shortcut_bonus;
314         p_list[count].b_force = i_shortcut_bonus && b_strict;
315         count++;
316     }
317
318     /* We can release the list, interesting modules are held */
319     module_list_free (p_all);
320
321     /* Sort candidates by descending score */
322     qsort (p_list, count, sizeof (p_list[0]), modulecmp);
323     msg_Dbg( p_this, "looking for %s module: %zu candidate%s", psz_capability,
324              count, count == 1 ? "" : "s" );
325
326     /* Parse the linked list and use the first successful module */
327     va_list args;
328
329     va_start(args, probe);
330     p_module = NULL;
331
332     for (size_t i = 0; (i < count) && (p_module == NULL); i++)
333     {
334         module_t *p_cand = p_list[i].p_module;
335
336         if (module_Map (p_this, p_cand))
337             continue;
338         p_this->b_force = p_list[i].b_force;
339
340         int ret;
341
342         if (likely(p_cand->pf_activate != NULL))
343         {
344             va_list ap;
345
346             va_copy(ap, args);
347             ret = probe(p_cand->pf_activate, ap);
348             va_end(ap);
349         }
350         else
351             ret = VLC_SUCCESS;
352
353         switch (ret)
354         {
355         case VLC_SUCCESS:
356             /* good module! */
357             p_module = p_cand;
358             break;
359
360         case VLC_ETIMEOUT:
361             /* good module, but aborted */
362             break;
363
364         default: /* bad module */
365             continue;
366         }
367     }
368
369     va_end (args);
370     free( p_list );
371     p_this->b_force = b_force_backup;
372
373     if( p_module != NULL )
374     {
375         msg_Dbg( p_this, "using %s module \"%s\"",
376                  psz_capability, module_get_object(p_module) );
377         vlc_object_set_name( p_this, psz_alias ? psz_alias
378                                                : module_get_object(p_module) );
379     }
380     else if( count == 0 )
381         msg_Dbg( p_this, "no %s module matched \"%s\"",
382                  psz_capability, (psz_name && *psz_name) ? psz_name : "any" );
383     else
384         msg_Dbg( p_this, "no %s module matching \"%s\" could be loaded",
385                   psz_capability, (psz_name && *psz_name) ? psz_name : "any" );
386
387     free( psz_shortcuts );
388     free( psz_var );
389
390     stats_TimerStop( p_this, STATS_TIMER_MODULE_NEED );
391     stats_TimerDump( p_this, STATS_TIMER_MODULE_NEED );
392     stats_TimerClean( p_this, STATS_TIMER_MODULE_NEED );
393
394     /* Don't forget that the module is still locked */
395     return p_module;
396 }
397
398
399 /**
400  * Deinstantiates a module.
401  * \param module the module pointer as returned by vlc_module_load()
402  * \param deinit deactivation callback
403  */
404 void vlc_module_unload(module_t *module, vlc_deactivate_t deinit, ...)
405 {
406     if (module->pf_deactivate != NULL)
407     {
408         va_list ap;
409
410         va_start(ap, deinit);
411         deinit(module->pf_deactivate, ap);
412         va_end(ap);
413     }
414 }
415
416
417 static int generic_start(void *func, va_list ap)
418 {
419     vlc_object_t *obj = va_arg(ap, vlc_object_t *);
420     int (*activate)(vlc_object_t *) = func;
421
422     return activate(obj);
423 }
424
425 static void generic_stop(void *func, va_list ap)
426 {
427     vlc_object_t *obj = va_arg(ap, vlc_object_t *);
428     void (*deactivate)(vlc_object_t *) = func;
429
430     deactivate(obj);
431 }
432
433 #undef module_need
434 module_t *module_need(vlc_object_t *obj, const char *cap, const char *name,
435                       bool strict)
436 {
437     return vlc_module_load(obj, cap, name, strict, generic_start, obj);
438 }
439
440 #undef module_unneed
441 void module_unneed(vlc_object_t *obj, module_t *module)
442 {
443     msg_Dbg(obj, "removing module \"%s\"", module_get_object(module));
444     vlc_module_unload(module, generic_stop, obj);
445 }
446
447 /**
448  * Get a pointer to a module_t given it's name.
449  *
450  * \param name the name of the module
451  * \return a pointer to the module or NULL in case of a failure
452  */
453 module_t *module_find (const char *name)
454 {
455     module_t **list, *module;
456
457     assert (name != NULL);
458     list = module_list_get (NULL);
459     if (!list)
460         return NULL;
461
462     for (size_t i = 0; (module = list[i]) != NULL; i++)
463     {
464         if (unlikely(module->i_shortcuts == 0))
465             continue;
466         if (!strcmp (module->pp_shortcuts[0], name))
467             break;
468     }
469     module_list_free (list);
470     return module;
471 }
472
473 /**
474  * Tell if a module exists and release it in thic case
475  *
476  * \param psz_name th name of the module
477  * \return TRUE if the module exists
478  */
479 bool module_exists (const char * psz_name)
480 {
481     return module_find (psz_name) != NULL;
482 }
483
484 /**
485  * Get a pointer to a module_t that matches a shortcut.
486  * This is a temporary hack for SD. Do not re-use (generally multiple modules
487  * can have the same shortcut, so this is *broken* - use module_need()!).
488  *
489  * \param psz_shortcut shortcut of the module
490  * \param psz_cap capability of the module
491  * \return a pointer to the module or NULL in case of a failure
492  */
493 module_t *module_find_by_shortcut (const char *psz_shortcut)
494 {
495     module_t **list, *module;
496
497     list = module_list_get (NULL);
498     if (!list)
499         return NULL;
500
501     for (size_t i = 0; (module = list[i]) != NULL; i++)
502         for (size_t j = 0; j < module->i_shortcuts; j++)
503             if (!strcmp (module->pp_shortcuts[j], psz_shortcut))
504                 goto out;
505 out:
506     module_list_free (list);
507     return module;
508 }
509
510 /**
511  * Get the configuration of a module
512  *
513  * \param module the module
514  * \param psize the size of the configuration returned
515  * \return the configuration as an array
516  */
517 module_config_t *module_config_get( const module_t *module, unsigned *restrict psize )
518 {
519     unsigned i,j;
520     unsigned size = module->confsize;
521     module_config_t *config = malloc( size * sizeof( *config ) );
522
523     assert( psize != NULL );
524     *psize = 0;
525
526     if( !config )
527         return NULL;
528
529     for( i = 0, j = 0; i < size; i++ )
530     {
531         const module_config_t *item = module->p_config + i;
532         if( item->b_internal /* internal option */
533          || item->b_removed /* removed option */ )
534             continue;
535
536         memcpy( config + j, item, sizeof( *config ) );
537         j++;
538     }
539     *psize = j;
540
541     return config;
542 }
543
544 /**
545  * Release the configuration
546  *
547  * \param the configuration
548  * \return nothing
549  */
550 void module_config_free( module_config_t *config )
551 {
552     free( config );
553 }