[vlc-devel] [PATCH 1/5] modules: module_list_cap sort list using the name argument

Thomas Guillem thomas at gllm.fr
Wed Jun 3 17:35:41 CEST 2015


This avoid to iterate in the list for each shortcuts from the name argument
since the list is already sorted with them.

This will also allow to extend the vlc_module_load function in order to load a
module coming just after an other one.
---
 src/config/core.c     |  11 ++---
 src/modules/bank.c    | 115 ++++++++++++++++++++++++++++++++++++++++++++------
 src/modules/modules.c |  91 ++++++++-------------------------------
 src/modules/modules.h |   9 +++-
 4 files changed, 134 insertions(+), 92 deletions(-)

diff --git a/src/config/core.c b/src/config/core.c
index de675c3..d1a7fca 100644
--- a/src/config/core.c
+++ b/src/config/core.c
@@ -382,8 +382,8 @@ ssize_t config_GetIntChoices (vlc_object_t *obj, const char *name,
 static ssize_t config_ListModules (const char *cap, char ***restrict values,
                                    char ***restrict texts)
 {
-    module_t **list;
-    ssize_t n = module_list_cap (&list, cap);
+    module_cap *list;
+    ssize_t n = module_list_cap (&list, cap, NULL);
     if (n <= 0)
     {
         *values = *texts = NULL;
@@ -398,10 +398,11 @@ static ssize_t config_ListModules (const char *cap, char ***restrict values,
 
     for (ssize_t i = 0; i < n; i++)
     {
-        vals[i + 1] = xstrdup (module_get_object (list[i]));
-        txts[i + 1] = xstrdup (module_gettext (list[i],
-                               module_get_name (list[i], true)));
+        vals[i + 1] = xstrdup (module_get_object (list[i].p_module));
+        txts[i + 1] = xstrdup (module_gettext (list[i].p_module,
+                               module_get_name (list[i].p_module, true)));
     }
+    free(list);
 
     vals[n + 1] = xstrdup ("none");
     txts[n + 1] = xstrdup (_("Disable"));
diff --git a/src/modules/bank.c b/src/modules/bank.c
index f4fba50..9f3a8fc 100644
--- a/src/modules/bank.c
+++ b/src/modules/bank.c
@@ -239,28 +239,111 @@ module_t **module_list_get (size_t *n)
     return tab;
 }
 
-static int modulecmp (const void *a, const void *b)
+static int module_cap_cmp (const void *a, const void *b)
 {
-    const module_t *const *ma = a, *const *mb = b;
+    const module_cap *ma = a, *mb = b;
     /* Note that qsort() uses _ascending_ order,
      * so the smallest module is the one with the biggest score. */
-    return (*mb)->i_score - (*ma)->i_score;
+    if (mb->i_cap_score == ma->i_cap_score)
+        return mb->p_module->i_score - ma->p_module->i_score;
+    /* Modules with a higher i_cap_score come first (i.e. modules that are
+     * forced by name argument) */
+    return mb->i_cap_score - ma->i_cap_score;
+}
+
+static bool module_match_name (const module_t *m, const char *name)
+{
+     for (unsigned i = 0; i < m->i_shortcuts; i++)
+          if (!strcasecmp (name, m->pp_shortcuts[i]))
+              return true;
+     return false;
+}
+
+static void
+module_cap_set (module_cap *mcap, module_t *module, const char **shortcut_list,
+                size_t shortcut_count)
+{
+    mcap->i_cap_score = 0;
+    mcap->p_module = module;
+
+    /* Set a positive i_cap_score if the module match any shortcuts. Shortcuts
+     * coming first will have a higher score. */
+
+    for (unsigned int i = 0; i < shortcut_count; ++i)
+    {
+        const char *name = shortcut_list[i];
+
+        if (module_match_name (module, name))
+        {
+            mcap->i_cap_score = shortcut_count - i;
+            break;
+        }
+
+        if (!strcasecmp (name, "none"))
+        {
+            mcap->i_cap_score = -1;
+            break;
+        }
+    }
 }
 
 /**
- * Builds a sorted list of all VLC modules with a given capability.
- * The list is sorted from the highest module score to the lowest.
+ * Builds a sorted list of all VLC modules with a given capability and a given
+ * name. The list is sorted from the highest module score to the lowest. If
+ * name is specified, modules that match a shortcut in name will have a higher
+ * priority.
  * @param list pointer to the table of modules [OUT]
  * @param cap capability of modules to look for
+ * @param name shortcut list asked, if any.
  * @return the number of matching found, or -1 on error (*list is then NULL).
  * @note *list must be freed with module_list_free().
  */
-ssize_t module_list_cap (module_t ***restrict list, const char *cap)
+ssize_t module_list_cap (module_cap **restrict list, const char *cap,
+                         const char *name)
 {
     /* TODO: This is quite inefficient. List should be sorted by capability. */
     ssize_t n = 0;
 
     assert (list != NULL);
+    char *buf = name ? strdup(name) : NULL;
+    const char **shortcut_list = NULL;
+    size_t shortcut_count = 0;
+
+    if (buf)
+    {
+        /* Count the number of shortcut from the name argument. */
+        char *itr = buf;
+        while (*itr)
+        {
+            size_t slen = strcspn (itr, ",");
+            itr += slen;
+            itr += strspn (itr, ",");
+            ++shortcut_count;
+        }
+
+        shortcut_list = malloc(shortcut_count * sizeof(const char *));
+        if (!shortcut_list)
+        {
+            free(buf);
+            return -1;
+        }
+
+        /* Fill the shortcut_list with every shortcut from the name argument. */
+        itr = buf;
+        shortcut_count = 0;
+        while (*itr)
+        {
+            size_t slen = strcspn (itr, ",");
+            char *shortcut = itr;
+
+            itr += slen;
+            itr += strspn (itr, ",");
+
+            shortcut[slen] = '\0';
+            shortcut_list[shortcut_count] = shortcut;
+            ++shortcut_count;
+        }
+    }
 
     for (module_t *mod = modules.head; mod != NULL; mod = mod->next)
     {
@@ -271,22 +354,28 @@ ssize_t module_list_cap (module_t ***restrict list, const char *cap)
                  n++;
     }
 
-    module_t **tab = malloc (sizeof (*tab) * n);
+    module_cap *tab = malloc (sizeof (module_cap) * n);
     *list = tab;
     if (unlikely(tab == NULL))
+    {
+        free(buf);
+        free(shortcut_list);
         return -1;
+    }
 
     for (module_t *mod = modules.head; mod != NULL; mod = mod->next)
     {
-         if (module_provides (mod, cap))
-             *(tab++)= mod;
-         for (module_t *subm = mod->submodule; subm != NULL; subm = subm->next)
-             if (module_provides (subm, cap))
-                 *(tab++) = subm;
+        if (module_provides (mod, cap))
+            module_cap_set ((tab++), mod, shortcut_list, shortcut_count);
+        for (module_t *subm = mod->submodule; subm != NULL; subm = subm->next)
+            if (module_provides (subm, cap))
+                module_cap_set ((tab++), subm, shortcut_list, shortcut_count);
     }
 
     assert (tab == *list + n);
-    qsort (*list, n, sizeof (*tab), modulecmp);
+    qsort (*list, n, sizeof (module_cap), module_cap_cmp);
+    free(buf);
+    free(shortcut_list);
     return n;
 }
 
diff --git a/src/modules/modules.c b/src/modules/modules.c
index 2fa9928..0f966f7 100644
--- a/src/modules/modules.c
+++ b/src/modules/modules.c
@@ -157,18 +157,6 @@ void module_stop (vlc_object_t *obj, const module_t *m)
         deactivate (obj);
 }
 
-static bool module_match_name (const module_t *m, const char *name)
-{
-     /* 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 module_load (vlc_object_t *obj, module_t *m,
                         vlc_activate_t init, va_list args)
 {
@@ -226,14 +214,14 @@ module_t *vlc_module_load(vlc_object_t *obj, const char *capability,
     }
 
     /* Find matching modules */
-    module_t **mods;
-    ssize_t total = module_list_cap (&mods, capability);
+    module_cap *modcaps;
+    ssize_t total = module_list_cap (&modcaps, capability, name);
 
     msg_Dbg (obj, "looking for %s module matching \"%s\": %zd candidates",
              capability, name, total);
     if (total <= 0)
     {
-        module_list_free (mods);
+        free (modcaps);
         msg_Dbg (obj, "no %s modules", capability);
         return NULL;
     }
@@ -243,74 +231,31 @@ module_t *vlc_module_load(vlc_object_t *obj, const char *capability,
     va_list args;
 
     va_start(args, probe);
-    while (*name)
-    {
-        char buf[32];
-        size_t slen = strcspn (name, ",");
-
-        if (likely(slen < sizeof (buf)))
-        {
-            memcpy(buf, name, slen);
-            buf[slen] = '\0';
-        }
-        name += slen;
-        name += strspn (name, ",");
-        if (unlikely(slen >= sizeof (buf)))
-            continue;
 
-        const char *shortcut = buf;
-        assert (shortcut != NULL);
+    for (ssize_t i = 0; i < total; i++)
+    {
+        module_cap *modcap = &modcaps[i];
 
-        if (!strcasecmp ("none", shortcut))
+        if (modcap->i_cap_score == -1)
+            goto done;
+        if (modcap->i_cap_score == 0 && (strict || module_get_score (modcap->p_module) <= 0))
             goto done;
 
-        obj->b_force = strict && strcasecmp ("any", shortcut);
-        for (ssize_t i = 0; i < total; i++)
-        {
-            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...
-
-            int ret = module_load (obj, cand, probe, args);
-            switch (ret)
-            {
-                case VLC_SUCCESS:
-                    module = cand;
-                    /* fall through */
-                case VLC_ETIMEOUT:
-                    goto done;
-            }
-        }
-    }
-
-    /* None of the shortcuts matched, fall back to any module */
-    if (!strict)
-    {
-        obj->b_force = false;
-        for (ssize_t i = 0; i < total; i++)
+        obj->b_force = modcap->i_cap_score > 0;
+        int ret = module_load (obj, modcap->p_module, probe, args);
+        switch (ret)
         {
-            module_t *cand = mods[i];
-            if (cand == NULL || module_get_score (cand) <= 0)
-                continue;
-
-            int ret = module_load (obj, cand, probe, args);
-            switch (ret)
-            {
-                case VLC_SUCCESS:
-                    module = cand;
-                    /* fall through */
-                case VLC_ETIMEOUT:
-                    goto done;
-            }
+            case VLC_SUCCESS:
+                module = modcap->p_module;
+                /* fall through */
+            case VLC_ETIMEOUT:
+                goto done;
         }
     }
 done:
     va_end (args);
     obj->b_force = b_force_backup;
-    module_list_free (mods);
+    free (modcaps);
     free (var);
 
     if (module != NULL)
diff --git a/src/modules/modules.h b/src/modules/modules.h
index e38e952..00d67b1 100644
--- a/src/modules/modules.h
+++ b/src/modules/modules.h
@@ -100,6 +100,13 @@ struct module_t
     char *              domain;                            /* gettext domain */
 };
 
+typedef struct module_cap module_cap;
+struct module_cap
+{
+    int         i_cap_score;
+    module_t   *p_module;
+};
+
 module_t *vlc_plugin_describe (vlc_plugin_cb);
 module_t *vlc_module_create (module_t *);
 void vlc_module_destroy (module_t *);
@@ -110,7 +117,7 @@ size_t module_LoadPlugins( vlc_object_t * );
 void module_EndBank (bool);
 int module_Map (vlc_object_t *, module_t *);
 
-ssize_t module_list_cap (module_t ***, const char *);
+ssize_t module_list_cap (module_cap **, const char *, const char *);
 
 int vlc_bindtextdomain (const char *);
 
-- 
2.1.4




More information about the vlc-devel mailing list