modules.c 35.8 KB
Newer Older
Sam Hocevar's avatar
 
Sam Hocevar committed
1
/*****************************************************************************
2
 * modules.c : Builtin and plugin modules management functions
Sam Hocevar's avatar
 
Sam Hocevar committed
3
 *****************************************************************************
4
 * Copyright (C) 2001-2007 the VideoLAN team
5
 * $Id$
Sam Hocevar's avatar
 
Sam Hocevar committed
6
 *
7
 * Authors: Sam Hocevar <sam@zoy.org>
Sam Hocevar's avatar
 
Sam Hocevar committed
8
 *          Ethan C. Baldridge <BaldridgeE@cadmus.com>
Sam Hocevar's avatar
 
Sam Hocevar committed
9
 *          Hans-Peter Jansen <hpj@urpla.net>
10
 *          Gildas Bazin <gbazin@videolan.org>
Sam Hocevar's avatar
 
Sam Hocevar committed
11 12 13 14 15 16 17 18 19 20 21 22 23
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
Antoine Cellerier's avatar
Antoine Cellerier committed
24
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
Sam Hocevar's avatar
 
Sam Hocevar committed
25 26
 *****************************************************************************/

27 28 29 30
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

31
#include <vlc_common.h>
32
#include <vlc_plugin.h>
33
#include <vlc_memory.h>
34
#include "libvlc.h"
35

Sam Hocevar's avatar
 
Sam Hocevar committed
36 37
#include <stdlib.h>                                      /* free(), strtol() */
#include <stdio.h>                                              /* sprintf() */
Sam Hocevar's avatar
 
Sam Hocevar committed
38
#include <string.h>                                              /* strdup() */
39
#include <assert.h>
Sam Hocevar's avatar
 
Sam Hocevar committed
40

41 42 43 44
#ifdef HAVE_DIRENT_H
#   include <dirent.h>
#endif

45
#include <sys/types.h>
46 47 48
#ifdef HAVE_SYS_STAT_H
#   include <sys/stat.h>
#endif
49 50 51
#ifdef HAVE_UNISTD_H
#   include <unistd.h>
#endif
52 53 54
#ifdef ENABLE_NLS
# include <libintl.h>
#endif
Sam Hocevar's avatar
 
Sam Hocevar committed
55

56
#include "config/configuration.h"
Sam Hocevar's avatar
 
Sam Hocevar committed
57

58
#include <vlc_fs.h>
59
#include "vlc_arrays.h"
Gildas Bazin's avatar
 
Gildas Bazin committed
60

61
#include "modules/modules.h"
Clément Stenac's avatar
Clément Stenac committed
62

63
static module_bank_t *p_module_bank = NULL;
64
static vlc_mutex_t module_lock = VLC_STATIC_MUTEX;
65

66 67
int vlc_entry__main( module_t * );

Sam Hocevar's avatar
 
Sam Hocevar committed
68 69 70
/*****************************************************************************
 * Local prototypes
 *****************************************************************************/
Sam Hocevar's avatar
 
Sam Hocevar committed
71
#ifdef HAVE_DYNAMIC_PLUGINS
72 73 74 75 76
static void AllocateAllPlugins( vlc_object_t *, module_bank_t * );
static void AllocatePluginDir( vlc_object_t *, module_bank_t *, const char *,
                               unsigned );
static int  AllocatePluginFile( vlc_object_t *, module_bank_t *, const char *,
                                int64_t, int64_t );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
77
static module_t * AllocatePlugin( vlc_object_t *, const char * );
Sam Hocevar's avatar
 
Sam Hocevar committed
78
#endif
79
static int  AllocateBuiltinModule( vlc_object_t *, int ( * ) ( module_t * ) );
80
static void DeleteModule ( module_bank_t *, module_t * );
Sam Hocevar's avatar
 
Sam Hocevar committed
81
#ifdef HAVE_DYNAMIC_PLUGINS
82 83
static void   DupModule        ( module_t * );
static void   UndupModule      ( module_t * );
84
#endif
Sam Hocevar's avatar
 
Sam Hocevar committed
85

86
#undef module_InitBank
87 88 89 90
/**
 * Init bank
 *
 * Creates a module bank structure which will be filled later
Gildas Bazin's avatar
 
Gildas Bazin committed
91
 * on with all the modules found.
92 93 94
 * \param p_this vlc object structure
 * \return nothing
 */
95
void module_InitBank( vlc_object_t *p_this )
Sam Hocevar's avatar
 
Sam Hocevar committed
96
{
97
    module_bank_t *p_bank = NULL;
98

99
    vlc_mutex_lock( &module_lock );
100

101
    if( p_module_bank == NULL )
102
    {
103
        p_bank = calloc (1, sizeof(*p_bank));
104 105 106
        p_bank->i_usage = 1;
        p_bank->i_cache = p_bank->i_loaded_cache = 0;
        p_bank->pp_cache = p_bank->pp_loaded_cache = NULL;
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
107
        p_bank->b_cache = p_bank->b_cache_dirty = false;
108
        p_bank->head = NULL;
109 110

        /* Everything worked, attach the object */
111
        p_module_bank = p_bank;
112 113 114 115 116 117 118

        /* Fills the module bank structure with the main module infos.
         * This is very useful as it will allow us to consider the main
         * library just as another module, and for instance the configuration
         * options of main will be available in the module bank structure just
         * as for every other module. */
        AllocateBuiltinModule( p_this, vlc_entry__main );
119
        vlc_rwlock_init (&config_lock);
120
        config_SortConfig ();
121
    }
122
    else
123
        p_module_bank->i_usage++;
124

125 126 127 128 129 130 131 132
    /* We do retain the module bank lock until the plugins are loaded as well.
     * This is ugly, this staged loading approach is needed: LibVLC gets
     * some configuration parameters relevant to loading the plugins from
     * the main (builtin) module. The module bank becomes shared read-only data
     * once it is ready, so we need to fully serialize initialization.
     * DO NOT UNCOMMENT the following line unless you managed to squeeze
     * module_LoadPlugins() before you unlock the mutex. */
    /*vlc_mutex_unlock( &module_lock );*/
Gildas Bazin's avatar
 
Gildas Bazin committed
133 134
}

135
#undef module_EndBank
136 137
/**
 * Unloads all unused plugin modules and empties the module
Sam Hocevar's avatar
 
Sam Hocevar committed
138
 * bank in case of success.
139 140 141
 * \param p_this vlc object structure
 * \return nothing
 */
142
void module_EndBank( vlc_object_t *p_this, bool b_plugins )
Sam Hocevar's avatar
 
Sam Hocevar committed
143
{
144 145 146
    module_bank_t *p_bank = p_module_bank;

    assert (p_bank != NULL);
147

148
    /* Save the configuration */
149
    if( !var_InheritBool( p_this, "ignore-config" ) )
150
        config_AutoSaveConfigFile( p_this );
151

152 153 154 155 156 157 158
    /* If plugins were _not_ loaded, then the caller still has the bank lock
     * from module_InitBank(). */
    if( b_plugins )
        vlc_mutex_lock( &module_lock );
    /*else
        vlc_assert_locked( &module_lock ); not for static mutexes :( */

159
    if( --p_bank->i_usage > 0 )
160
    {
161
        vlc_mutex_unlock( &module_lock );
162 163
        return;
    }
164 165

    config_UnsortConfig ();
166
    vlc_rwlock_destroy (&config_lock);
167 168
    p_module_bank = NULL;
    vlc_mutex_unlock( &module_lock );
169

170
#ifdef HAVE_DYNAMIC_PLUGINS
171 172
    while( p_bank->i_loaded_cache-- )
    {
173 174
        if( p_bank->pp_loaded_cache[p_bank->i_loaded_cache] )
        {
175
            DeleteModule( p_bank,
176
                    p_bank->pp_loaded_cache[p_bank->i_loaded_cache]->p_module );
177 178 179
            free( p_bank->pp_loaded_cache[p_bank->i_loaded_cache]->psz_file );
            free( p_bank->pp_loaded_cache[p_bank->i_loaded_cache] );
        }
180
    }
181
    free( p_bank->pp_loaded_cache );
182 183 184 185
    while( p_bank->i_cache-- )
    {
        free( p_bank->pp_cache[p_bank->i_cache]->psz_file );
        free( p_bank->pp_cache[p_bank->i_cache] );
186
    }
187
    free( p_bank->pp_cache );
188 189
#endif

190
    while( p_bank->head != NULL )
191
        DeleteModule( p_bank, p_bank->head );
Sam Hocevar's avatar
 
Sam Hocevar committed
192

193
    free( p_bank );
Sam Hocevar's avatar
 
Sam Hocevar committed
194 195
}

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
196
#undef module_LoadPlugins
197
/**
198
 * Loads module descriptions for all available plugins.
199
 * Fills the module bank structure with the plugin modules.
200
 *
201 202 203
 * \param p_this vlc object structure
 * \return nothing
 */
204
void module_LoadPlugins( vlc_object_t * p_this )
205
{
206 207 208 209 210
    module_bank_t *p_bank = p_module_bank;

    assert( p_bank );
    /*vlc_assert_locked( &module_lock ); not for static mutexes :( */

211
#ifdef HAVE_DYNAMIC_PLUGINS
212
    if( p_bank->i_usage == 1 )
213
    {
214
        msg_Dbg( p_this, "checking plugin modules" );
215
        p_module_bank->b_cache = var_InheritBool( p_this, "plugins-cache" );
216 217

        AllocateAllPlugins( p_this, p_module_bank );
218 219
        config_UnsortConfig ();
        config_SortConfig ();
220
    }
221
#endif
222
    vlc_mutex_unlock( &module_lock );
Sam Hocevar's avatar
 
Sam Hocevar committed
223 224
}

225 226 227 228 229 230 231
/**
 * Checks whether a module implements a capability.
 *
 * \param m the module
 * \param cap the capability to check
 * \return TRUE if the module have the capability
 */
232
bool module_provides( const module_t *m, const char *cap )
233 234 235 236
{
    return !strcmp( m->psz_capability, cap );
}

237 238 239 240 241 242
/**
 * Get the internal name of a module
 *
 * \param m the module
 * \return the module name
 */
243
const char *module_get_object( const module_t *m )
244 245 246 247
{
    return m->psz_object_name;
}

248 249 250 251 252 253 254
/**
 * Get the human-friendly name of a module.
 *
 * \param m the module
 * \param long_name TRUE to have the long name of the module
 * \return the short or long name of the module
 */
255
const char *module_get_name( const module_t *m, bool long_name )
256 257 258
{
    if( long_name && ( m->psz_longname != NULL) )
        return m->psz_longname;
259

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
260
    return m->psz_shortname ? m->psz_shortname : m->psz_object_name;
261 262
}

263 264 265 266 267 268
/**
 * Get the help for a module
 *
 * \param m the module
 * \return the help
 */
269
const char *module_get_help( const module_t *m )
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
270 271 272 273
{
    return m->psz_help;
}

274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295
/**
 * Get the capability for a module
 *
 * \param m the module
 * return the capability
 */
const char *module_get_capability( const module_t *m )
{
    return m->psz_capability;
}

/**
 * Get the score for a module
 *
 * \param m the module
 * return the score for the capability
 */
int module_get_score( const module_t *m )
{
    return m->i_score;
}

296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313
/**
 * Translate a string using the module's text domain
 *
 * \param m the module
 * \param str the American English ASCII string to localize
 * \return the gettext-translated string
 */
const char *module_gettext (const module_t *m, const char *str)
{
#ifdef ENABLE_NLS
    const char *domain = m->domain ? m->domain : PACKAGE_NAME;
    return dgettext (domain, str);
#else
    (void)m;
    return str;
#endif
}

314 315 316 317 318 319 320 321 322 323 324
module_t *module_hold (module_t *m)
{
    vlc_hold (&m->vlc_gc_data);
    return m;
}

void module_release (module_t *m)
{
    vlc_release (&m->vlc_gc_data);
}

325 326
/**
 * Frees the flat list of VLC modules.
327
 * @param list list obtained by module_list_get()
328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349
 * @param length number of items on the list
 * @return nothing.
 */
void module_list_free (module_t **list)
{
    if (list == NULL)
        return;

    for (size_t i = 0; list[i] != NULL; i++)
         module_release (list[i]);
    free (list);
}

/**
 * Gets the flat list of VLC modules.
 * @param n [OUT] pointer to the number of modules or NULL
 * @return NULL-terminated table of module pointers
 *         (release with module_list_free()), or NULL in case of error.
 */
module_t **module_list_get (size_t *n)
{
    /* TODO: this whole module lookup is quite inefficient */
350
    /* Remove this and improve module_need */
351 352 353
    module_t **tab = NULL;
    size_t i = 0;

354
    assert (p_module_bank);
355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375
    for (module_t *mod = p_module_bank->head; mod; mod = mod->next)
    {
         module_t **nt;
         nt  = realloc (tab, (i + 2 + mod->submodule_count) * sizeof (*tab));
         if (nt == NULL)
         {
             module_list_free (tab);
             return NULL;
         }

         tab = nt;
         tab[i++] = module_hold (mod);
         for (module_t *subm = mod->submodule; subm; subm = subm->next)
             tab[i++] = module_hold (subm);
         tab[i] = NULL;
    }
    if (n != NULL)
        *n = i;
    return tab;
}

376 377 378
typedef struct module_list_t
{
    module_t *p_module;
379
    int16_t  i_score;
380 381 382 383 384 385 386 387 388 389 390
    bool     b_force;
} module_list_t;

static int modulecmp (const void *a, const void *b)
{
    const module_list_t *la = a, *lb = b;
    /* Note that qsort() uses _ascending_ order,
     * so the smallest module is the one with the biggest score. */
    return lb->i_score - la->i_score;
}

391
#undef module_need
392 393 394 395
/**
 * module Need
 *
 * Return the best module function, given a capability list.
396
 *
397 398 399
 * \param p_this the vlc object
 * \param psz_capability list of capabilities needed
 * \param psz_name name of the module asked
400 401
 * \param b_strict if true, do not fallback to plugin with a different name
 *                 but the same capability
402 403
 * \return the module or NULL in case of a failure
 */
404 405
module_t * module_need( vlc_object_t *p_this, const char *psz_capability,
                        const char *psz_name, bool b_strict )
Sam Hocevar's avatar
 
Sam Hocevar committed
406
{
407
    stats_TimerStart( p_this, "module_need()", STATS_TIMER_MODULE_NEED );
408

409
    module_list_t *p_list;
Sam Hocevar's avatar
 
Sam Hocevar committed
410
    module_t *p_module;
411
    int i_shortcuts = 0;
412
    char *psz_shortcuts = NULL, *psz_var = NULL, *psz_alias = NULL;
413
    bool b_force_backup = p_this->b_force;
Sam Hocevar's avatar
 
Sam Hocevar committed
414

415 416 417
    /* Deal with variables */
    if( psz_name && psz_name[0] == '$' )
    {
Antoine Cellerier's avatar
Antoine Cellerier committed
418
        psz_name = psz_var = var_CreateGetString( p_this, psz_name + 1 );
419 420
    }

421
    /* Count how many different shortcuts were asked for */
422
    if( psz_name && *psz_name )
Sam Hocevar's avatar
 
Sam Hocevar committed
423
    {
Gildas Bazin's avatar
 
Gildas Bazin committed
424
        char *psz_parser, *psz_last_shortcut;
425

426 427 428
        /* If the user wants none, give him none. */
        if( !strcmp( psz_name, "none" ) )
        {
429
            free( psz_var );
430 431 432
            stats_TimerStop( p_this, STATS_TIMER_MODULE_NEED );
            stats_TimerDump( p_this, STATS_TIMER_MODULE_NEED );
            stats_TimerClean( p_this, STATS_TIMER_MODULE_NEED );
433 434 435
            return NULL;
        }

436
        i_shortcuts++;
437
        psz_parser = psz_shortcuts = psz_last_shortcut = strdup( psz_name );
438

439
        while( ( psz_parser = strchr( psz_parser, ',' ) ) )
Sam Hocevar's avatar
 
Sam Hocevar committed
440
        {
441 442 443
             *psz_parser = '\0';
             i_shortcuts++;
             psz_last_shortcut = ++psz_parser;
Sam Hocevar's avatar
 
Sam Hocevar committed
444
        }
Gildas Bazin's avatar
 
Gildas Bazin committed
445 446 447 448

        /* Check if the user wants to override the "strict" mode */
        if( psz_last_shortcut )
        {
449 450
            if( !strcmp(psz_last_shortcut, "none") )
            {
451
                b_strict = true;
452 453 454 455
                i_shortcuts--;
            }
            else if( !strcmp(psz_last_shortcut, "any") )
            {
456
                b_strict = false;
457 458
                i_shortcuts--;
            }
Gildas Bazin's avatar
 
Gildas Bazin committed
459
        }
Sam Hocevar's avatar
 
Sam Hocevar committed
460
    }
Sam Hocevar's avatar
 
Sam Hocevar committed
461

Sam Hocevar's avatar
 
Sam Hocevar committed
462
    /* Sort the modules and test them */
463 464 465
    size_t count;
    module_t **p_all = module_list_get (&count);
    p_list = malloc( count * sizeof( module_list_t ) );
Sam Hocevar's avatar
 
Sam Hocevar committed
466

Sam Hocevar's avatar
 
Sam Hocevar committed
467
    /* Parse the module list for capabilities and probe each of them */
468 469
    count = 0;
    for (size_t i = 0; (p_module = p_all[i]) != NULL; i++)
Sam Hocevar's avatar
 
Sam Hocevar committed
470
    {
471
        int i_shortcut_bonus = 0;
472

473
        /* Test that this module can do what we need */
474
        if( !module_provides( p_module, psz_capability ) )
475
            continue;
Sam Hocevar's avatar
 
Sam Hocevar committed
476

477
        /* If we required a shortcut, check this plugin provides it. */
478
        if( i_shortcuts > 0 )
Sam Hocevar's avatar
 
Sam Hocevar committed
479
        {
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
480
            const char *name = psz_shortcuts;
Sam Hocevar's avatar
 
Sam Hocevar committed
481

482
            for( unsigned i_short = i_shortcuts; i_short > 0; i_short-- )
Sam Hocevar's avatar
 
Sam Hocevar committed
483
            {
484
                for( unsigned i = 0; p_module->pp_shortcuts[i]; i++ )
485
                {
486
                    char *c;
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
487 488 489 490
                    if( ( c = strchr( name, '@' ) )
                        ? !strncasecmp( name, p_module->pp_shortcuts[i],
                                        c-name )
                        : !strcasecmp( name, p_module->pp_shortcuts[i] ) )
Gildas Bazin's avatar
 
Gildas Bazin committed
491 492
                    {
                        /* Found it */
493 494
                        if( c && c[1] )
                            psz_alias = c+1;
495
                        i_shortcut_bonus = i_short * 10000;
496
                        goto found_shortcut;
Gildas Bazin's avatar
 
Gildas Bazin committed
497
                    }
498 499
                }

500
                /* Go to the next shortcut... This is so lame! */
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
501
                name += strlen( name ) + 1;
Sam Hocevar's avatar
 
Sam Hocevar committed
502
            }
Sam Hocevar's avatar
 
Sam Hocevar committed
503

504 505 506
            /* If we are in "strict" mode and we couldn't
             * find the module in the list of provided shortcuts,
             * then kick the bastard out of here!!! */
507
            if( b_strict )
Sam Hocevar's avatar
 
Sam Hocevar committed
508
                continue;
Sam Hocevar's avatar
 
Sam Hocevar committed
509
        }
510 511 512

        /* Trash <= 0 scored plugins (they can only be selected by shortcut) */
        if( p_module->i_score <= 0 )
513
            continue;
514

515
found_shortcut:
Sam Hocevar's avatar
 
Sam Hocevar committed
516
        /* Store this new module */
517
        p_list[count].p_module = module_hold (p_module);
518 519
        p_list[count].i_score = p_module->i_score + i_shortcut_bonus;
        p_list[count].b_force = i_shortcut_bonus && b_strict;
520
        count++;
Sam Hocevar's avatar
 
Sam Hocevar committed
521 522
    }

523
    /* We can release the list, interesting modules are held */
524
    module_list_free (p_all);
Sam Hocevar's avatar
 
Sam Hocevar committed
525

526 527
    /* Sort candidates by descending score */
    qsort (p_list, count, sizeof (p_list[0]), modulecmp);
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
528
    msg_Dbg( p_this, "looking for %s module: %zu candidate%s", psz_capability,
529 530
             count, count == 1 ? "" : "s" );

Sam Hocevar's avatar
 
Sam Hocevar committed
531
    /* Parse the linked list and use the first successful module */
532 533
    p_module = NULL;
    for (size_t i = 0; (i < count) && (p_module == NULL); i++)
Sam Hocevar's avatar
 
Sam Hocevar committed
534
    {
535
        module_t *p_cand = p_list[i].p_module;
536 537
#ifdef HAVE_DYNAMIC_PLUGINS
        /* Make sure the module is loaded in mem */
538
        module_t *p_real = p_cand->b_submodule ? p_cand->parent : p_cand;
539

540
        if( !p_real->b_builtin && !p_real->b_loaded )
541 542
        {
            module_t *p_new_module =
543
                AllocatePlugin( p_this, p_real->psz_filename );
544 545 546 547 548
            if( p_new_module == NULL )
            {   /* Corrupted module */
                msg_Err( p_this, "possibly corrupt module cache" );
                module_release( p_cand );
                continue;
549
            }
550 551
            CacheMerge( p_this, p_real, p_new_module );
            DeleteModule( p_module_bank, p_new_module );
552 553 554
        }
#endif

555
        p_this->b_force = p_list[i].b_force;
556 557 558 559 560

        int ret = VLC_SUCCESS;
        if( p_cand->pf_activate )
            ret = p_cand->pf_activate( p_this );
        switch( ret )
Sam Hocevar's avatar
 
Sam Hocevar committed
561
        {
562 563
        case VLC_SUCCESS:
            /* good module! */
564
            p_module = p_cand;
565 566 567 568 569 570 571 572
            break;

        case VLC_ETIMEOUT:
            /* good module, but aborted */
            module_release( p_cand );
            break;

        default: /* bad module */
573
            module_release( p_cand );
574 575 576 577 578 579
            continue;
        }

        /* Release the remaining modules */
        while (++i < count)
            module_release (p_list[i].p_module);
Sam Hocevar's avatar
 
Sam Hocevar committed
580
    }
Sam Hocevar's avatar
 
Sam Hocevar committed
581

Sam Hocevar's avatar
 
Sam Hocevar committed
582
    free( p_list );
583
    p_this->b_force = b_force_backup;
Sam Hocevar's avatar
 
Sam Hocevar committed
584

Sam Hocevar's avatar
 
Sam Hocevar committed
585
    if( p_module != NULL )
Sam Hocevar's avatar
 
Sam Hocevar committed
586
    {
587
        msg_Dbg( p_this, "using %s module \"%s\"",
588
                 psz_capability, p_module->psz_object_name );
589 590
        vlc_object_set_name( p_this, psz_alias ? psz_alias
                                               : p_module->psz_object_name );
591
    }
592
    else if( count == 0 )
593
        msg_Dbg( p_this, "no %s module matched \"%s\"",
594 595
                 psz_capability, (psz_name && *psz_name) ? psz_name : "any" );
    else
596 597
        msg_Dbg( p_this, "no %s module matching \"%s\" could be loaded",
                  psz_capability, (psz_name && *psz_name) ? psz_name : "any" );
Sam Hocevar's avatar
 
Sam Hocevar committed
598

599 600
    free( psz_shortcuts );
    free( psz_var );
601

602 603 604 605
    stats_TimerStop( p_this, STATS_TIMER_MODULE_NEED );
    stats_TimerDump( p_this, STATS_TIMER_MODULE_NEED );
    stats_TimerClean( p_this, STATS_TIMER_MODULE_NEED );

Sam Hocevar's avatar
 
Sam Hocevar committed
606
    /* Don't forget that the module is still locked */
607
    return p_module;
Sam Hocevar's avatar
 
Sam Hocevar committed
608 609
}

610
#undef module_unneed
611 612 613
/**
 * Module unneed
 *
614
 * This function must be called by the thread that called module_need, to
615
 * decrease the reference count and allow for hiding of modules.
616 617 618 619
 * \param p_this vlc object structure
 * \param p_module the module structure
 * \return nothing
 */
620
void module_unneed( vlc_object_t * p_this, module_t * p_module )
Sam Hocevar's avatar
 
Sam Hocevar committed
621
{
622 623 624 625 626 627
    /* Use the close method */
    if( p_module->pf_deactivate )
    {
        p_module->pf_deactivate( p_this );
    }

628
    msg_Dbg( p_this, "removing module \"%s\"", p_module->psz_object_name );
Sam Hocevar's avatar
 
Sam Hocevar committed
629

630
    module_release( p_module );
Sam Hocevar's avatar
 
Sam Hocevar committed
631 632
}

633 634 635 636 637 638
/**
 * Get a pointer to a module_t given it's name.
 *
 * \param psz_name the name of the module
 * \return a pointer to the module or NULL in case of a failure
 */
639
module_t *module_find( const char * psz_name )
640
{
641
    module_t **list, *module;
642 643 644 645 646 647

    list = module_list_get (NULL);
    if (!list)
        return NULL;

    for (size_t i = 0; (module = list[i]) != NULL; i++)
648
    {
649 650
        const char *psz_module_name = module->psz_object_name;

651
        if( psz_module_name && !strcmp( psz_module_name, psz_name ) )
652
        {
653 654
            module_hold (module);
            break;
655 656
        }
    }
657 658
    module_list_free (list);
    return module;
659 660
}

661 662 663 664 665 666
/**
 * Tell if a module exists and release it in thic case
 *
 * \param psz_name th name of the module
 * \return TRUE if the module exists
 */
667
bool module_exists (const char * psz_name)
668
{
669
    module_t *p_module = module_find (psz_name);
670
    if( p_module )
671
        module_release (p_module);
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
672
    return p_module != NULL;
673 674
}

675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709
/**
 * Get a pointer to a module_t that matches a shortcut.
 * This is a temporary hack for SD. Do not re-use (generally multiple modules
 * can have the same shortcut, so this is *broken* - use module_need()!).
 *
 * \param psz_shortcut shortcut of the module
 * \param psz_cap capability of the module
 * \return a pointer to the module or NULL in case of a failure
 */
module_t *module_find_by_shortcut (const char *psz_shortcut)
{
    module_t **list, *module;

    list = module_list_get (NULL);
    if (!list)
        return NULL;

    for (size_t i = 0; (module = list[i]) != NULL; i++)
    {
        for (size_t j = 0;
             (module->pp_shortcuts[j] != NULL) && (j < MODULE_SHORTCUT_MAX);
             j++)
        {
            if (!strcmp (module->pp_shortcuts[j], psz_shortcut))
            {
                module_hold (module);
                goto out;
             }
        }
    }
out:
    module_list_free (list);
    return module;
}

710 711 712 713 714 715 716
/**
 * Get the configuration of a module
 *
 * \param module the module
 * \param psize the size of the configuration returned
 * \return the configuration as an array
 */
717
module_config_t *module_config_get( const module_t *module, unsigned *restrict psize )
718
{
719
    unsigned i,j;
720
    unsigned size = module->confsize;
721
    module_config_t *config = malloc( size * sizeof( *config ) );
722

723
    assert( psize != NULL );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
724
    *psize = 0;
725

726 727 728
    if( !config )
        return NULL;

729
    for( i = 0, j = 0; i < size; i++ )
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
730
    {
731
        const module_config_t *item = module->p_config + i;
732
        if( item->b_internal /* internal option */
733
         || item->b_unsaveable /* non-modifiable option */
734
         || item->b_removed /* removed option */ )
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
735 736
            continue;

737
        memcpy( config + j, item, sizeof( *config ) );
738
        j++;
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
739
    }
740
    *psize = j;
741 742 743 744

    return config;
}

745 746 747 748 749 750
/**
 * Release the configuration
 *
 * \param the configuration
 * \return nothing
 */
751
void module_config_free( module_config_t *config )
752
{
753
    free( config );
754 755
}

Sam Hocevar's avatar
 
Sam Hocevar committed
756 757 758 759
/*****************************************************************************
 * Following functions are local.
 *****************************************************************************/

760 761 762 763 764 765 766
 /*****************************************************************************
 * copy_next_paths_token: from a PATH_SEP_CHAR (a ':' or a ';') separated paths
 * return first path.
 *****************************************************************************/
static char * copy_next_paths_token( char * paths, char ** remaining_paths )
{
    char * path;
767
    int i, done;
768 769 770 771 772
    bool escaped = false;

    assert( paths );

    /* Alloc a buffer to store the path */
Rafaël Carré's avatar
Rafaël Carré committed
773
    path = malloc( strlen( paths ) + 1 );
774 775 776
    if( !path ) return NULL;

    /* Look for PATH_SEP_CHAR (a ':' or a ';') */
777 778
    for( i = 0, done = 0 ; paths[i]; i++ )
    {
779
        /* Take care of \\ and \: or \; escapement */
780 781
        if( escaped )
        {
782
            escaped = false;
783
            path[done++] = paths[i];
784
        }
785 786 787 788
#ifdef WIN32
        else if( paths[i] == '/' )
            escaped = true;
#else
789 790
        else if( paths[i] == '\\' )
            escaped = true;
791
#endif
792 793 794
        else if( paths[i] == PATH_SEP_CHAR )
            break;
        else
795
            path[done++] = paths[i];
796
    }
Rémi Duraffort's avatar
Rémi Duraffort committed
797
    path[done] = 0;
798 799 800 801 802 803 804 805 806

    /* Return the remaining paths */
    if( remaining_paths ) {
        *remaining_paths = paths[i] ? &paths[i]+1 : NULL;
    }

    return path;
}

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
807
char *psz_vlcpath = NULL;
808

Sam Hocevar's avatar
 
Sam Hocevar committed
809 810 811
/*****************************************************************************
 * AllocateAllPlugins: load all plugin modules we can find.
 *****************************************************************************/
Sam Hocevar's avatar
 
Sam Hocevar committed
812
#ifdef HAVE_DYNAMIC_PLUGINS
813
static void AllocateAllPlugins( vlc_object_t *p_this, module_bank_t *p_bank )
Sam Hocevar's avatar
 
Sam Hocevar committed
814
{
815
    const char *vlcpath = psz_vlcpath;
816 817 818
    int count,i;
    char * path;
    vlc_array_t *arraypaths = vlc_array_new();
819
    const bool b_reset = var_InheritBool( p_this, "reset-plugins-cache" );
820 821 822

    /* Contruct the special search path for system that have a relocatable
     * executable. Set it to <vlc path>/modules and <vlc path>/plugins. */
823 824 825 826 827 828

    if( vlcpath && asprintf( &path, "%s" DIR_SEP "modules", vlcpath ) != -1 )
        vlc_array_append( arraypaths, path );
    if( vlcpath && asprintf( &path, "%s" DIR_SEP "plugins", vlcpath ) != -1 )
        vlc_array_append( arraypaths, path );
#ifndef WIN32
829
    vlc_array_append( arraypaths, strdup( PLUGIN_PATH ) );
830
#endif
Sam Hocevar's avatar
 
Sam Hocevar committed
831

832
    /* If the user provided a plugin path, we add it to the list */
833
    char *userpaths = var_InheritString( p_this, "plugin-path" );
834
    char *paths_iter;
835

836
    for( paths_iter = userpaths; paths_iter; )
837
    {
838
        path = copy_next_paths_token( paths_iter, &paths_iter );
839
        if( path )
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
840
            vlc_array_append( arraypaths, path );
841
    }
842

843 844
    count = vlc_array_count( arraypaths );
    for( i = 0 ; i < count ; i++ )
Sam Hocevar's avatar
 
Sam Hocevar committed
845
    {
846
        path = vlc_array_item_at_index( arraypaths, i );
847
        if( !path )
848
            continue;
849

850
        size_t offset = p_module_bank->i_cache;
851 852 853 854 855
        if( b_reset )
            CacheDelete( p_this, path );
        else
            CacheLoad( p_this, p_module_bank, path );

856
        msg_Dbg( p_this, "recursively browsing `%s'", path );
Sam Hocevar's avatar
 
Sam Hocevar committed
857

858
        /* Don't go deeper than 5 subdirectories */
859
        AllocatePluginDir( p_this, p_bank, path, 5 );
Sam Hocevar's avatar
 
Sam Hocevar committed
860

861 862
        CacheSave( p_this, path, p_module_bank->pp_cache + offset,
                   p_module_bank->i_cache - offset );
863
        free( path );
Sam Hocevar's avatar
 
Sam Hocevar committed
864
    }
Gildas Bazin's avatar
 
Gildas Bazin committed
865

866
    vlc_array_destroy( arraypaths );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
867
    free( userpaths );
Sam Hocevar's avatar
 
Sam Hocevar committed
868 869
}

Sam Hocevar's avatar
 
Sam Hocevar committed
870
/*****************************************************************************
871 872
 * AllocatePluginDir: recursively parse a directory to look for plugins
 *****************************************************************************/
873 874
static void AllocatePluginDir( vlc_object_t *p_this, module_bank_t *p_bank,
                               const char *psz_dir, unsigned i_maxdepth )
875
{
876
    if( i_maxdepth == 0 )
877 878
        return;

879
    DIR *dh = vlc_opendir (psz_dir);
880
    if (dh == NULL)