[vlc-devel] [RFC PATCH 01/12] modules: add module_need_next and vlc_module_load_next

Thomas Guillem thomas at gllm.fr
Tue Jul 19 19:36:23 CEST 2016


These functions save the previous state of a successful vlc_module_load(). A
second call to this function with the saved context allows to load a module
that come after the previous one (i.e. with a lower priority or after the list
given in command line).

TODO: document vlc_modules.h
---
 include/vlc_modules.h |   5 ++
 src/libvlccore.sym    |   2 +
 src/modules/modules.c | 162 +++++++++++++++++++++++++++++++++++++-------------
 3 files changed, 128 insertions(+), 41 deletions(-)

diff --git a/include/vlc_modules.h b/include/vlc_modules.h
index 7f45217..238690d 100644
--- a/include/vlc_modules.h
+++ b/include/vlc_modules.h
@@ -36,10 +36,15 @@ typedef void (*vlc_deactivate_t)(void *func, va_list args);
 VLC_API module_t * vlc_module_load( vlc_object_t *obj, const char *cap, const char *name, bool strict, vlc_activate_t probe, ... ) VLC_USED;
 #define vlc_module_load(o,c,n,s,...) \
         vlc_module_load(VLC_OBJECT(o),c,n,s,__VA_ARGS__)
+VLC_API module_t * vlc_module_load_next( vlc_object_t *obj, const char *cap, const char *name, bool strict, void **, vlc_activate_t probe, ... ) VLC_USED;
+#define vlc_module_load_next(o,c,n,s,t,...) \
+        vlc_module_load_next(VLC_OBJECT(o),c,n,s,t,__VA_ARGS__)
 VLC_API void vlc_module_unload( module_t *, vlc_deactivate_t deinit, ... );
 
 VLC_API module_t * module_need( vlc_object_t *, const char *, const char *, bool ) VLC_USED;
 #define module_need(a,b,c,d) module_need(VLC_OBJECT(a),b,c,d)
+VLC_API module_t * module_need_next( vlc_object_t *, const char *, const char *, bool, void ** ) VLC_USED;
+#define module_need_next(a,b,c,d,e) module_need_next(VLC_OBJECT(a),b,c,d,e)
 VLC_API void module_unneed( vlc_object_t *, module_t * );
 #define module_unneed(a,b) module_unneed(VLC_OBJECT(a),b)
 VLC_API bool module_exists(const char *) VLC_USED;
diff --git a/src/libvlccore.sym b/src/libvlccore.sym
index 1e634dd..a83898d 100644
--- a/src/libvlccore.sym
+++ b/src/libvlccore.sym
@@ -269,9 +269,11 @@ module_gettext
 module_list_free
 module_list_get
 module_need
+module_need_next
 module_provides
 module_unneed
 vlc_module_load
+vlc_module_load_next
 vlc_module_unload
 vlc_Log
 vlc_LogSet
diff --git a/src/modules/modules.c b/src/modules/modules.c
index 7ba6492..b39e3f4 100644
--- a/src/modules/modules.c
+++ b/src/modules/modules.c
@@ -188,41 +188,53 @@ static int module_load (vlc_object_t *obj, module_t *m,
     return ret;
 }
 
-#undef vlc_module_load
-/**
- * Finds and instantiates the best module of a certain type.
- * All candidates modules having the specified capability and name will be
- * sorted in decreasing order of priority. Then the probe callback will be
- * invoked for each module, until it succeeds (returns 0), or all candidate
- * module failed to initialize.
- *
- * The probe callback first parameter is the address of the module entry point.
- * Further parameters are passed as an argument list; it corresponds to the
- * variable arguments passed to this function. This scheme is meant to
- * support arbitrary prototypes for the module entry point.
- *
- * \param obj VLC object
- * \param capability capability, i.e. class of module
- * \param 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 *obj, const char *capability,
-                          const char *name, bool strict,
-                          vlc_activate_t probe, ...)
+static module_t *
+vlc_module_load_common(vlc_object_t *obj, const char *capability,
+                       const char *name, bool strict, void **saveptr,
+                       vlc_activate_t probe, va_list args)
 {
-    char *var = NULL;
+    struct savectx
+    {
+        const char *name;
+        size_t start_index;
+        char data[];
+    };
 
-    if (name == NULL || name[0] == '\0')
-        name = "any";
+    char *var = NULL;
+    struct savectx *savectx;
+    size_t start_index = 0;
 
-    /* Deal with variables */
-    if (name[0] == '$')
+    if (saveptr != NULL && *saveptr != NULL)
     {
-        var = var_InheritString (obj, name + 1);
-        name = (var != NULL) ? var : "any";
+        savectx = *saveptr;
+        start_index = savectx->start_index;
+        name = savectx->name;
+    }
+    else
+    {
+        if (name == NULL || name[0] == '\0')
+            name = "any";
+
+        /* Deal with variables */
+        if (name[0] == '$')
+        {
+            var = var_InheritString (obj, name + 1);
+            name = (var != NULL) ? var : "any";
+        }
+        if (saveptr != NULL)
+        {
+            savectx = malloc(sizeof(struct savectx) + strlen(name) + 1);
+            if (savectx == NULL)
+            {
+                free(var);
+                return NULL;
+            }
+            strcpy(savectx->data, name);
+            name = savectx->name = savectx->data;
+            *saveptr = savectx;
+        }
+        else
+            savectx = NULL;
     }
 
     /* Find matching modules */
@@ -231,18 +243,16 @@ module_t *vlc_module_load(vlc_object_t *obj, const char *capability,
 
     msg_Dbg (obj, "looking for %s module matching \"%s\": %zd candidates",
              capability, name, total);
+
+    module_t *module = NULL;
+    const bool b_force_backup = obj->obj.force; /* FIXME: remove this */
     if (total <= 0)
     {
-        module_list_free (mods);
         msg_Dbg (obj, "no %s modules", capability);
-        return NULL;
+        goto done;
     }
+    assert((size_t)total > start_index);
 
-    module_t *module = NULL;
-    const bool b_force_backup = obj->obj.force; /* FIXME: remove this */
-    va_list args;
-
-    va_start(args, probe);
     while (*name)
     {
         char buf[32];
@@ -265,7 +275,7 @@ module_t *vlc_module_load(vlc_object_t *obj, const char *capability,
             goto done;
 
         obj->obj.force = strict && strcasecmp ("any", shortcut);
-        for (ssize_t i = 0; i < total; i++)
+        for (ssize_t i = start_index; i < total; i++)
         {
             module_t *cand = mods[i];
             if (cand == NULL)
@@ -278,19 +288,21 @@ module_t *vlc_module_load(vlc_object_t *obj, const char *capability,
             switch (ret)
             {
                 case VLC_SUCCESS:
+                    start_index = i + 1;
                     module = cand;
                     /* fall through */
                 case VLC_ETIMEOUT:
                     goto done;
             }
         }
+        start_index = 0;
     }
 
     /* None of the shortcuts matched, fall back to any module */
     if (!strict)
     {
         obj->obj.force = false;
-        for (ssize_t i = 0; i < total; i++)
+        for (ssize_t i = start_index; i < total; i++)
         {
             module_t *cand = mods[i];
             if (cand == NULL || module_get_score (cand) <= 0)
@@ -300,30 +312,91 @@ module_t *vlc_module_load(vlc_object_t *obj, const char *capability,
             switch (ret)
             {
                 case VLC_SUCCESS:
+                    start_index = i + 1;
                     module = cand;
                     /* fall through */
                 case VLC_ETIMEOUT:
                     goto done;
             }
         }
+        start_index = 0;
     }
 done:
-    va_end (args);
     obj->obj.force = b_force_backup;
     module_list_free (mods);
     free (var);
 
     if (module != NULL)
     {
+        if (savectx != NULL)
+        {
+            assert(name >= savectx->data
+                && name <= savectx->data + strlen(savectx->data));
+            savectx->name = name;
+            savectx->start_index = start_index < (size_t)total ? start_index : 0;
+        }
+
         msg_Dbg (obj, "using %s module \"%s\"", capability,
                  module_get_object (module));
         vlc_object_set_name (obj, module_get_object (module));
     }
     else
+    {
         msg_Dbg (obj, "no %s modules matched", capability);
+        free(savectx);
+        if (saveptr != NULL)
+            *saveptr = NULL;
+    }
     return module;
 }
 
+#undef vlc_module_load
+/**
+ * Finds and instantiates the best module of a certain type.
+ * All candidates modules having the specified capability and name will be
+ * sorted in decreasing order of priority. Then the probe callback will be
+ * invoked for each module, until it succeeds (returns 0), or all candidate
+ * module failed to initialize.
+ *
+ * The probe callback first parameter is the address of the module entry point.
+ * Further parameters are passed as an argument list; it corresponds to the
+ * variable arguments passed to this function. This scheme is meant to
+ * support arbitrary prototypes for the module entry point.
+ *
+ * \param obj VLC object
+ * \param capability capability, i.e. class of module
+ * \param 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 *obj, const char *capability,
+                          const char *name, bool strict,
+                          vlc_activate_t probe, ...)
+{
+    va_list args;
+
+    va_start(args, probe);
+    module_t *module = vlc_module_load_common(obj, capability, name, strict,
+                                              NULL, probe, args);
+    va_end (args);
+    return module;
+}
+
+#undef vlc_module_load_next
+module_t *vlc_module_load_next(vlc_object_t *obj, const char *capability,
+                            const char *name, bool strict, void **saveptr,
+                            vlc_activate_t probe, ...)
+{
+    va_list args;
+
+    va_start(args, probe);
+    module_t *module = vlc_module_load_common(obj, capability, name, strict,
+                                              saveptr, probe, args);
+    va_end (args);
+    return module;
+}
 
 /**
  * Deinstantiates a module.
@@ -366,6 +439,13 @@ module_t *module_need(vlc_object_t *obj, const char *cap, const char *name,
     return vlc_module_load(obj, cap, name, strict, generic_start, obj);
 }
 
+#undef module_need_next
+module_t *module_need_next(vlc_object_t *obj, const char *cap, const char *name,
+                      bool strict, void **saveptr)
+{
+    return vlc_module_load_next(obj, cap, name, strict, saveptr, generic_start, obj);
+}
+
 #undef module_unneed
 void module_unneed(vlc_object_t *obj, module_t *module)
 {
-- 
2.8.1



More information about the vlc-devel mailing list