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)
deactivate (obj);
}
typedef struct module_list_t
static bool module_match_name (const module_t *m, const char *name)
{
module_t *p_module;
int16_t i_score;
bool b_force;
} module_list_t;
/* Plugins with zero score must be matched explicitly. */
if (!strcasecmp ("any", name))
return m->i_score > 0;
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;
/* Note that qsort() uses _ascending_ order,
* so the smallest module is the one with the biggest score. */
return lb->i_score - la->i_score;
int ret = VLC_SUCCESS;
if (module_Map (obj, m))
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
......@@ -185,198 +201,124 @@ static int modulecmp (const void *a, const void *b)
* variable arguments passed to this function. This scheme is meant to
* support arbitrary prototypes for the module entry point.
*
* \param p_this VLC object
* \param psz_capability capability, i.e. class of module
* \param psz_name name name of the module asked, if any
* \param b_strict if true, do not fallback to plugin with a different name
* \param obj VLC object
* \param capability capability, i.e. class of module
* \param name name name of the module asked, if any
* \param strict if true, do not fallback to plugin with a different name
* but the same capability
* \param probe module probe callback
* \return the module or NULL in case of a failure
*/
module_t *vlc_module_load(vlc_object_t *p_this, const char *psz_capability,
const char *psz_name, bool b_strict,
module_t *vlc_module_load(vlc_object_t *obj, const char *capability,
const char *name, bool strict,
vlc_activate_t probe, ...)
{
int i_shortcuts = 0;
char *psz_shortcuts = NULL, *psz_var = NULL;
bool b_force_backup = p_this->b_force;
char *var = NULL;
if (name == NULL || name[0] == '\0')
name = "any";
/* Deal with variables */
if( psz_name && psz_name[0] == '$' )
if (name[0] == '$')
{
psz_name = psz_var = var_CreateGetString( p_this, psz_name + 1 );
var = var_InheritString (obj, name + 1);
name = (var != NULL) ? var : "any";
}
/* Count how many different shortcuts were asked for */
if( psz_name && *psz_name )
{
char *psz_parser, *psz_last_shortcut;
/* Find matching modules */
module_t **mods;
ssize_t total = module_list_cap (&mods, capability);
/* If the user wants none, give him none. */
if( !strcmp( psz_name, "none" ) )
msg_Dbg (obj, "looking for %s module matching \"%s\": %zd candidates",
capability, name, total);
if (total <= 0)
{
free( psz_var );
module_list_free (mods);
msg_Dbg (obj, "no %s modules", capability);
return NULL;
}
i_shortcuts++;
psz_parser = psz_shortcuts = psz_last_shortcut = strdup( psz_name );
module_t *module = NULL;
const bool b_force_backup = obj->b_force; /* FIXME: remove this */
va_list args;
while( ( psz_parser = strchr( psz_parser, ',' ) ) )
va_start(args, probe);
while (*name)
{
*psz_parser = '\0';
i_shortcuts++;
psz_last_shortcut = ++psz_parser;
}
char buf[32];
size_t slen = strcspn (name, ",");
/* Check if the user wants to override the "strict" mode */
if( psz_last_shortcut )
{
if( !strcmp(psz_last_shortcut, "none") )
{
b_strict = true;
i_shortcuts--;
}
else if( !strcmp(psz_last_shortcut, "any") )
if (likely(slen < sizeof (buf)))
{
b_strict = false;
i_shortcuts--;
}
}
memcpy(buf, name, slen);
buf[slen] = '\0';
}
name += slen;
name += strspn (name, ",");
if (unlikely(slen >= sizeof (buf)))
continue;
/* 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 ) );
const char *shortcut = buf;
assert (shortcut != NULL);
/* Parse the module list for capabilities and probe each of them */
for (size_t i = 0; i < total; i++)
obj->b_force = strict && strcasecmp ("any", shortcut);
for (ssize_t i = 0; i < total; i++)
{
module_t *p_module = p_all[i];
int i_shortcut_bonus = 0;
/* Test that this module can do what we need */
if( !module_provides( p_module, psz_capability ) )
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...
/* 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] ) )
int ret = module_load (obj, cand, probe, args);
switch (ret)
{
/* Found it */
i_shortcut_bonus = i_short * 10000;
goto found_shortcut;
case VLC_SUCCESS:
module = cand;
/* fall through */
case VLC_ETIMEOUT:
goto done;
}
}
/* 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 */
module_list_free (p_all);
if( match == 0 )
/* None of the shortcuts matched, fall back to any module */
if (!strict)
{
msg_Dbg( p_this, "no %s module matched \"%s\"",
psz_capability, (psz_name && *psz_name) ? psz_name : "any" );
return NULL; // shortcut
}
/* Sort candidates by descending score */
qsort (p_list, match, sizeof (p_list[0]), modulecmp);
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_start(args, probe);
for (size_t i = 0; (i < match) && (p_module == NULL); i++)
obj->b_force = false;
for (ssize_t i = 0; i < total; i++)
{
module_t *p_cand = p_list[i].p_module;
if (module_Map (p_this, p_cand))
module_t *cand = mods[i];
if (cand == NULL)
continue;
p_this->b_force = p_list[i].b_force;
int ret;
if (likely(p_cand->pf_activate != NULL))
{
va_list ap;
va_copy(ap, args);
ret = probe(p_cand->pf_activate, ap);
va_end(ap);
}
else
ret = VLC_SUCCESS;
int ret = module_load (obj, cand, probe, args);
switch (ret)
{
case VLC_SUCCESS:
/* good module! */
p_module = p_cand;
break;
module = cand;
/* fall through */
case VLC_ETIMEOUT:
/* good module, but aborted */
break;
default: /* bad module */
continue;
goto done;
}
}
}
done:
va_end (args);
free( p_list );
p_this->b_force = b_force_backup;
obj->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\"",
psz_capability, module_get_object(p_module) );
vlc_object_set_name( p_this, module_get_object(p_module) );
msg_Dbg (obj, "using %s module \"%s\"", capability,
module_get_object (module));
vlc_object_set_name (obj, module_get_object (module));
}
else
msg_Dbg( p_this, "no %s module matching \"%s\" could be loaded",
psz_capability, (psz_name && *psz_name) ? psz_name : "any" );
free( psz_shortcuts );
free( psz_var );
/* Don't forget that the module is still locked */
return p_module;
msg_Dbg (obj, "no %s modules matched", capability);
return 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