Commit cf98594d authored by Rémi Denis-Courmont's avatar Rémi Denis-Courmont

module_need(): rewrite using module_list_cap()

parent a57b503d
...@@ -157,19 +157,35 @@ void module_stop (vlc_object_t *obj, const module_t *m) ...@@ -157,19 +157,35 @@ void module_stop (vlc_object_t *obj, const module_t *m)
deactivate (obj); deactivate (obj);
} }
typedef struct module_list_t static bool module_match_name (const module_t *m, const char *name)
{ {
module_t *p_module; /* Plugins with zero score must be matched explicitly. */
int16_t i_score; if (!strcasecmp ("any", name))
bool b_force; return m->i_score > 0;
} module_list_t;
for (unsigned i = 0; i < m->i_shortcuts; i++)
if (!strcasecmp (m->pp_shortcuts[i], name))
return true;
return false;
}
static int modulecmp (const void *a, const void *b) static int module_load (vlc_object_t *obj, module_t *m,
vlc_activate_t init, va_list args)
{ {
const module_list_t *la = a, *lb = b; int ret = VLC_SUCCESS;
/* Note that qsort() uses _ascending_ order,
* so the smallest module is the one with the biggest score. */ if (module_Map (obj, m))
return lb->i_score - la->i_score; return VLC_EGENERIC;
if (m->pf_activate != NULL)
{
va_list ap;
va_copy (ap, args);
ret = init (m->pf_activate, ap);
va_end (ap);
}
return ret;
} }
#undef vlc_module_load #undef vlc_module_load
...@@ -185,198 +201,124 @@ static int modulecmp (const void *a, const void *b) ...@@ -185,198 +201,124 @@ static int modulecmp (const void *a, const void *b)
* variable arguments passed to this function. This scheme is meant to * variable arguments passed to this function. This scheme is meant to
* support arbitrary prototypes for the module entry point. * support arbitrary prototypes for the module entry point.
* *
* \param p_this VLC object * \param obj VLC object
* \param psz_capability capability, i.e. class of module * \param capability capability, i.e. class of module
* \param psz_name name name of the module asked, if any * \param name name name of the module asked, if any
* \param b_strict if true, do not fallback to plugin with a different name * \param strict if true, do not fallback to plugin with a different name
* but the same capability * but the same capability
* \param probe module probe callback * \param probe module probe callback
* \return the module or NULL in case of a failure * \return the module or NULL in case of a failure
*/ */
module_t *vlc_module_load(vlc_object_t *p_this, const char *psz_capability, module_t *vlc_module_load(vlc_object_t *obj, const char *capability,
const char *psz_name, bool b_strict, const char *name, bool strict,
vlc_activate_t probe, ...) vlc_activate_t probe, ...)
{ {
int i_shortcuts = 0; char *var = NULL;
char *psz_shortcuts = NULL, *psz_var = NULL;
bool b_force_backup = p_this->b_force;
/* Deal with variables */
if( psz_name && psz_name[0] == '$' )
{
psz_name = psz_var = var_CreateGetString( p_this, psz_name + 1 );
}
/* Count how many different shortcuts were asked for */
if( psz_name && *psz_name )
{
char *psz_parser, *psz_last_shortcut;
/* If the user wants none, give him none. */
if( !strcmp( psz_name, "none" ) )
{
free( psz_var );
return NULL;
}
i_shortcuts++;
psz_parser = psz_shortcuts = psz_last_shortcut = strdup( psz_name );
while( ( psz_parser = strchr( psz_parser, ',' ) ) ) if (name == NULL || name[0] == '\0')
{ name = "any";
*psz_parser = '\0';
i_shortcuts++;
psz_last_shortcut = ++psz_parser;
}
/* Check if the user wants to override the "strict" mode */ /* Deal with variables */
if( psz_last_shortcut ) if (name[0] == '$')
{
if( !strcmp(psz_last_shortcut, "none") )
{
b_strict = true;
i_shortcuts--;
}
else if( !strcmp(psz_last_shortcut, "any") )
{
b_strict = false;
i_shortcuts--;
}
}
}
/* Sort the modules and test them */
size_t total, match = 0;
module_t **p_all = module_list_get (&total);
module_list_t *p_list = xmalloc( total * sizeof( module_list_t ) );
/* Parse the module list for capabilities and probe each of them */
for (size_t i = 0; i < total; i++)
{ {
module_t *p_module = p_all[i]; var = var_InheritString (obj, name + 1);
int i_shortcut_bonus = 0; name = (var != NULL) ? var : "any";
/* Test that this module can do what we need */
if( !module_provides( p_module, psz_capability ) )
continue;
/* If we required a shortcut, check this plugin provides it. */
if( i_shortcuts > 0 )
{
const char *name = psz_shortcuts;
for( unsigned i_short = i_shortcuts; i_short > 0; i_short-- )
{
for( unsigned i = 0; i < p_module->i_shortcuts; i++ )
{
if( !strcasecmp( name, p_module->pp_shortcuts[i] ) )
{
/* Found it */
i_shortcut_bonus = i_short * 10000;
goto found_shortcut;
}
}
/* Go to the next shortcut... This is so lame! */
name += strlen( name ) + 1;
}
/* 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!!! */
if( b_strict )
continue;
}
/* Trash <= 0 scored plugins (they can only be selected by shortcut) */
if( p_module->i_score <= 0 )
continue;
found_shortcut:
/* Store this new module */
p_list[match].p_module = p_module;
p_list[match].i_score = p_module->i_score + i_shortcut_bonus;
p_list[match].b_force = i_shortcut_bonus && b_strict;
match++;
} }
/* We can release the list, interesting modules are held */ /* Find matching modules */
module_list_free (p_all); module_t **mods;
ssize_t total = module_list_cap (&mods, capability);
if( match == 0 ) msg_Dbg (obj, "looking for %s module matching \"%s\": %zd candidates",
capability, name, total);
if (total <= 0)
{ {
msg_Dbg( p_this, "no %s module matched \"%s\"", module_list_free (mods);
psz_capability, (psz_name && *psz_name) ? psz_name : "any" ); msg_Dbg (obj, "no %s modules", capability);
return NULL; // shortcut return NULL;
} }
/* Sort candidates by descending score */ module_t *module = NULL;
qsort (p_list, match, sizeof (p_list[0]), modulecmp); const bool b_force_backup = obj->b_force; /* FIXME: remove this */
msg_Dbg( p_this, "looking for %s module: %zu candidate%s", psz_capability,
match, match == 1 ? "" : "s" );
/* Parse the linked list and use the first successful module */
module_t *p_module = NULL;
va_list args; va_list args;
va_start(args, probe); va_start(args, probe);
while (*name)
for (size_t i = 0; (i < match) && (p_module == NULL); i++)
{ {
module_t *p_cand = p_list[i].p_module; char buf[32];
size_t slen = strcspn (name, ",");
if (module_Map (p_this, p_cand)) if (likely(slen < sizeof (buf)))
{
memcpy(buf, name, slen);
buf[slen] = '\0';
}
name += slen;
name += strspn (name, ",");
if (unlikely(slen >= sizeof (buf)))
continue; continue;
p_this->b_force = p_list[i].b_force;
int ret; const char *shortcut = buf;
assert (shortcut != NULL);
if (likely(p_cand->pf_activate != NULL)) obj->b_force = strict && strcasecmp ("any", shortcut);
for (ssize_t i = 0; i < total; i++)
{ {
va_list ap; module_t *cand = mods[i];
if (cand == NULL)
continue; // module failed in previous iteration
if (!module_match_name (cand, shortcut))
continue;
mods[i] = NULL; // only try each module once at most...
va_copy(ap, args); int ret = module_load (obj, cand, probe, args);
ret = probe(p_cand->pf_activate, ap); switch (ret)
va_end(ap); {
case VLC_SUCCESS:
module = cand;
/* fall through */
case VLC_ETIMEOUT:
goto done;
}
} }
else }
ret = VLC_SUCCESS;
switch (ret) /* None of the shortcuts matched, fall back to any module */
if (!strict)
{
obj->b_force = false;
for (ssize_t i = 0; i < total; i++)
{ {
case VLC_SUCCESS: module_t *cand = mods[i];
/* good module! */ if (cand == NULL)
p_module = p_cand; continue;
break;
case VLC_ETIMEOUT:
/* good module, but aborted */
break;
default: /* bad module */ int ret = module_load (obj, cand, probe, args);
continue; switch (ret)
{
case VLC_SUCCESS:
module = cand;
/* fall through */
case VLC_ETIMEOUT:
goto done;
}
} }
} }
done:
va_end (args); va_end (args);
free( p_list ); obj->b_force = b_force_backup;
p_this->b_force = b_force_backup; module_list_free (mods);
free (var);
if( p_module != NULL ) if (module != NULL)
{ {
msg_Dbg( p_this, "using %s module \"%s\"", msg_Dbg (obj, "using %s module \"%s\"", capability,
psz_capability, module_get_object(p_module) ); module_get_object (module));
vlc_object_set_name( p_this, module_get_object(p_module) ); vlc_object_set_name (obj, module_get_object (module));
} }
else else
msg_Dbg( p_this, "no %s module matching \"%s\" could be loaded", msg_Dbg (obj, "no %s modules matched", capability);
psz_capability, (psz_name && *psz_name) ? psz_name : "any" ); return module;
free( psz_shortcuts );
free( psz_var );
/* Don't forget that the module is still locked */
return p_module;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment