Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  bank.c   Sprache: C

 

/*****************************************************************************
 * bank.c : Modules list
 *****************************************************************************
 * Copyright (C) 2001-2011 VLC authors and VideoLAN
 *
 * Authors: Sam Hocevar <sam@zoy.org>
 *          Ethan C. Baldridge <BaldridgeE@cadmus.com>
 *          Hans-Peter Jansen <hpj@urpla.net>
 *          Gildas Bazin <gbazin@videolan.org>
 *          Rémi Denis-Courmont
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/


#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#ifdef HAVE_SEARCH_H
# include <search.h>
#endif

#include <vlc_common.h>
#include <vlc_plugin.h>
#include <vlc_modules.h>
#include <vlc_fs.h>
#include <vlc_block.h>
#include "../libvlc.h"
#include "config/configuration.h"
#include "modules/modules.h"

/** Core module */
VLC_DECL_MODULE_ENTRY(core);

typedef struct vlc_modcap
{
    char *name;
    module_t **modv;
    size_t modc;
} vlc_modcap_t;

static int vlc_modcap_cmp(const void *a, const void *b)
{
    const vlc_modcap_t *capa = a, *capb = b;
    return strcmp(capa->name, capb->name);
}

static void vlc_modcap_free(void *data)
{
    vlc_modcap_t *cap = data;

    free(cap->modv);
    free(cap->name);
    free(cap);
}

static int vlc_module_cmp (const void *a, const void *b)
{
    module_t *const *ma = a, *const *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;
}

static void vlc_modcap_sort(const void *node, const VISIT which,
                            const int depth)
{
    vlc_modcap_t *const *cp = node, *cap = *cp;

    if (which != postorder && which != leaf)
        return;

    qsort(cap->modv, cap->modc, sizeof (*cap->modv), vlc_module_cmp);
    (void) depth;
}

static struct
{
    vlc_mutex_t lock;
    block_t *caches;
    void *caps_tree;
    size_t count;
    unsigned usage;
} modules = { VLC_STATIC_MUTEX, NULL, NULL, 0, 0 };

vlc_plugin_t *vlc_plugins = NULL;

/**
 * Adds a module to the bank
 */

static int vlc_module_store(module_t *mod)
{
    const char *name = module_get_capability(mod);
    vlc_modcap_t *cap = malloc(sizeof (*cap));
    if (unlikely(cap == NULL))
        return -1;

    cap->name = strdup(name);
    cap->modv = NULL;
    cap->modc = 0;

    if (unlikely(cap->name == NULL))
        goto error;

    void **cp = tsearch(cap, &modules.caps_tree, vlc_modcap_cmp);
    if (unlikely(cp == NULL))
        goto error;

    if (*cp != cap)
    {
        vlc_modcap_free(cap);
        cap = *cp;
    }

    module_t **modv = realloc(cap->modv, sizeof (*modv) * (cap->modc + 1));
    if (unlikely(modv == NULL))
        return -1;

    cap->modv = modv;
    cap->modv[cap->modc] = mod;
    cap->modc++;
    return 0;
error:
    vlc_modcap_free(cap);
    return -1;
}

/**
 * Adds a plugin (and all its modules) to the bank
 */

static void vlc_plugin_store(vlc_plugin_t *lib)
{
    vlc_mutex_assert(&modules.lock);

    lib->next = vlc_plugins;
    vlc_plugins = lib;
    modules.count += lib->modules_count;

    for (module_t *m = lib->module; m != NULL; m = m->next)
        vlc_module_store(m);
}

/**
 * Registers a statically-linked plug-in.
 */

static vlc_plugin_t *module_InitStatic(vlc_plugin_cb entry)
{
    /* Initializes the statically-linked library */
    vlc_plugin_t *lib = vlc_plugin_describe (entry);
    if (unlikely(lib == NULL))
        return NULL;

#ifdef HAVE_DYNAMIC_PLUGINS
    atomic_init(&lib->handle, 0);
    lib->unloadable = false;
#endif
    return lib;
}

/* With weak linking in __ELF__, there is no need to provide a definition
 * of vlc_static_modules at build time and it will be evaluated to NULL if
 * not provided at runtime. However, although __MACH__ implies the same runtime
 * consequences for weak linking, it will still require the definition to exist
 * at build time. To workaround this, we add -Wl,-U,vlc_static_modules. */

#if defined(__ELF__) \
    || (defined(__MACH__) && defined(HAVE_DYLIB_DYNAMIC_LOOKUP)) \
    || !defined(HAVE_DYNAMIC_PLUGINS)
VLC_WEAK
extern const vlc_plugin_cb vlc_static_modules[];

static void module_InitStaticModules(void)
{
    if (!vlc_static_modules)
        return;

    for (unsigned i = 0; vlc_static_modules[i]; i++)
    {
        vlc_plugin_t *lib = module_InitStatic(vlc_static_modules[i]);
        if (likely(lib != NULL))
            vlc_plugin_store(lib);
    }
}
#else
static void module_InitStaticModules(void) { }
#endif

#ifdef HAVE_DYNAMIC_PLUGINS
static const char *module_GetVersion(void *handle)
{
    const char *(*get_api_version)(void);

    get_api_version = vlc_dlsym(handle, "vlc_entry_api_version");
    if (get_api_version == NULL)
        return NULL;

    return get_api_version();
}

static void *module_Open(struct vlc_logger *log,
                         const char *path, bool fast)
{
    void *handle = vlc_dlopen(path, fast);
    if (handle == NULL)
    {
        char *errmsg = vlc_dlerror();

        vlc_error(log, "cannot load plug-in %s: %s", path,
                  errmsg ? errmsg : "unknown error");
        free(errmsg);
        return NULL;
    }

    const char *str = module_GetVersion(handle);
    if (str == NULL) {
        vlc_error(log, "cannot load plug-in %s: %s", path,
                  "unknown version or not a plug-in");
error:
        vlc_dlclose(handle);
        return NULL;
    }

    if (strcmp(str, VLC_API_VERSION_STRING)) {
        vlc_error(log, "cannot load plug-in %s: unsupported version %s", path,
                  str);
        goto error;
    }

    return handle;
}

/**
 * Loads a dynamically-linked plug-in into memory and initialize it.
 *
 * The module can then be handled by module_need() and module_unneed().
 *
 * \param path file path of the shared object
 * \param fast whether to optimize loading for speed or safety
 *             (fast is used when the plug-in is registered but not used)
 */

static vlc_plugin_t *module_InitDynamic(libvlc_int_t *obj, const char *path,
                                        bool fast)
{
    void *handle = module_Open(vlc_object_logger(obj), path, fast);
    if (handle == NULL)
        return NULL;

    /* Try to resolve the symbol */
    vlc_plugin_cb entry = vlc_dlsym(handle, "vlc_entry");
    if (entry == NULL)
    {
        msg_Warn (obj, "cannot find plug-in entry point in %s", path);
        goto error;
    }

    /* We can now try to call the symbol */
    vlc_plugin_t *plugin = vlc_plugin_describe(entry);
    if (unlikely(plugin == NULL))
    {
        /* With a well-written module we shouldn't have to print an
         * additional error message here, but just make sure. */

        msg_Err (obj, "cannot initialize plug-in %s", path);
        goto error;
    }

    atomic_init(&plugin->handle, (uintptr_t)handle);
    return plugin;
error:
    vlc_dlclose(handle);
    return NULL;
}

typedef enum
{
    CACHE_READ_FILE  = 0x1,
    CACHE_SCAN_DIR   = 0x2,
    CACHE_WRITE_FILE = 0x4,
} cache_mode_t;

typedef struct module_bank
{
    libvlc_int_t *obj;
    const char   *base;
    cache_mode_t  mode;

    size_t        size;
    vlc_plugin_t **plugins;
    vlc_plugin_t *cache;
} module_bank_t;

/**
 * Scans a plug-in from a file.
 */

static int AllocatePluginFile (module_bank_t *bank, const char *abspath,
                               const char *relpath, const struct stat *st)
{
    vlc_plugin_t *plugin = NULL;

    /* Check our plugins cache first then load plugin if needed */
    if (bank->mode & CACHE_READ_FILE)
    {
        plugin = vlc_cache_lookup(&bank->cache, relpath);

        if (plugin != NULL
         && (plugin->mtime != (int64_t)st->st_mtime
          || plugin->size != (uint64_t)st->st_size))
        {
            msg_Err(bank->obj, "stale plugins cache: modified %s",
                    plugin->abspath);
            vlc_plugin_destroy(plugin);
            plugin = NULL;
        }
    }

    if (plugin == NULL)
    {
        char *path = strdup(relpath);
        if (path == NULL)
            return -1;

        plugin = module_InitDynamic(bank->obj, abspath, true);

        if (plugin != NULL)
        {
            plugin->path = path;
            plugin->mtime = st->st_mtime;
            plugin->size = st->st_size;
        }
        else free(path);
    }

    if (plugin == NULL)
        return -1;

    vlc_plugin_store(plugin);

    if (bank->mode & CACHE_WRITE_FILE) /* Add entry to to-be-saved cache */
    {
        bank->plugins = xrealloc(bank->plugins,
                                 (bank->size + 1) * sizeof (vlc_plugin_t *));
        bank->plugins[bank->size] = plugin;
        bank->size++;
    }

    /* TODO: deal with errors */
    return  0;
}

#ifdef __APPLE__
/* Apple specific framework library browsing */

static int AllocatePluginFramework (module_bank_t *bank, const char *file,
                                    const char *relpath, const char *abspath)
{
    int i_ret = VLC_EGENERIC;
    size_t len_name = strlen (file);

    /* Skip frameworks not matching plugins naming conventions. */
    if (len_name < strlen("_plugin.framework")
      || strncmp(file + len_name - strlen("_plugin.framework"),
                 "_plugin", strlen("_plugin")) != 0)
    {
        /* The framework doesn't contain plugins, there's no need to
         * browse the rest of the framework folder. */

        return VLC_EGENERIC;
    }

    /* The framework is a plugin, extract the dylib from it. */
    int filename_len = len_name - strlen(".framework");

    char *framework_relpath = NULL, *framework_abspath = NULL;
    /* Compute absolute path */
    if (asprintf (&framework_abspath, "%s"DIR_SEP"%.*s",
                  abspath, filename_len, file) == -1)
    {
        framework_abspath = NULL;
        goto end;
    }

    struct stat framework_st;
    if (vlc_stat (framework_abspath, &framework_st) == -1
     || !S_ISREG (framework_st.st_mode))
        goto end;

    if (asprintf (&framework_relpath, "%s"DIR_SEP"%.*s",
                  relpath, filename_len, file) == -1)
        framework_relpath = NULL;

    i_ret = AllocatePluginFile (bank, framework_abspath, framework_relpath, &framework_st);

end:
    free(framework_relpath);
    free(framework_abspath);
    return i_ret;
}
#endif


/**
 * Recursively browses a directory to look for plug-ins.
 */

static void AllocatePluginDir (module_bank_t *bank, unsigned maxdepth,
                               const char *absdir, const char *reldir)
{
    if (maxdepth == 0)
        return;
    maxdepth--;

    vlc_DIR *dh = vlc_opendir (absdir);
    if (dh == NULL)
        return;

    /* Parse the directory and try to load all files it contains. */
    for (;;)
    {
        char *relpath = NULL, *abspath = NULL;
        const char *file = vlc_readdir (dh);
        if (file == NULL)
            break;

        /* Skip ".", ".." */
        if (!strcmp (file, ".") || !strcmp (file, ".."))
            continue;

        /* Compute path relative to plug-in base directory */
        if (reldir != NULL)
        {
            if (asprintf (&relpath, "%s"DIR_SEP"%s", reldir, file) == -1)
                relpath = NULL;
        }
        else
            relpath = strdup (file);
        if (unlikely(relpath == NULL))
            continue;

        /* Compute absolute path */
        if (asprintf (&abspath, "%s"DIR_SEP"%s", bank->base, relpath) == -1)
        {
            abspath = NULL;
            goto skip;
        }

        struct stat st;
        if (vlc_stat (abspath, &st) == -1)
            goto skip;

        if (S_ISREG (st.st_mode))
        {
            static const char prefix[] = "lib";
            static const char suffix[] = "_plugin"LIBEXT;
            size_t len = strlen (file);

#ifndef __OS2__
            /* Check that file matches the "lib*_plugin"LIBEXT pattern */
            if (len > strlen (suffix)
             && !strncmp (file, prefix, strlen (prefix))
             && !strcmp (file + len - strlen (suffix), suffix))
#else
            /* We load all the files ending with LIBEXT on OS/2,
             * because OS/2 has a 8.3 length limitation for DLL name */

            if (len > strlen (LIBEXT)
             && !strcasecmp (file + len - strlen (LIBEXT), LIBEXT))
#endif
                AllocatePluginFile (bank, abspath, relpath, &st);
        }
        else if (S_ISDIR (st.st_mode))
        {
#ifdef __APPLE__
            size_t len_name = strlen (file);
            const char *framework_extension =
                file + len_name - strlen(".framework");

            if (len_name > strlen(".framework")
             && strcmp(framework_extension, ".framework") == 0)
            {
                AllocatePluginFramework (bank, file, relpath, abspath);
                /* Don't browse framework directories. */
                goto skip;
            }
#endif

            /* Recurse into another directory */
            AllocatePluginDir (bank, maxdepth, abspath, relpath);
        }
    skip:
        free (relpath);
        free (abspath);
    }
    vlc_closedir (dh);
}

/**
 * Scans for plug-ins within a file system hierarchy.
 * \param path base directory to browse
 */

static void AllocatePluginPath(libvlc_int_t *obj, const char *path,
                               cache_mode_t mode)
{
    module_bank_t bank =
    {
        .obj = obj,
        .base = path,
        .mode = mode,
    };

    if (mode & CACHE_READ_FILE)
        bank.cache = vlc_cache_load(obj, path, &modules.caches);
    else
        msg_Dbg(bank.obj, "ignoring plugins cache file");

    if (mode & CACHE_SCAN_DIR)
    {
        msg_Dbg(obj, "recursively browsing `%s'", bank.base);

        /* Don't go deeper than 5 subdirectories */
        AllocatePluginDir(&bank, 5, path, NULL);
    }

    /* Deal with unmatched cache entries from cache file */
    while (bank.cache != NULL)
    {
        vlc_plugin_t *plugin = bank.cache;

        bank.cache = plugin->next;
        if (mode & CACHE_SCAN_DIR)
            vlc_plugin_destroy(plugin);
        else
            vlc_plugin_store(plugin);
    }

    if (mode & CACHE_WRITE_FILE)
        CacheSave(obj, path, bank.plugins, bank.size);

    free(bank.plugins);
}

#if defined(_WIN32)
# if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
#  define HAVE_FORCED_PLUGINS
# endif
#endif

/**
 * Enumerates all dynamic plug-ins that can be found.
 *
 * This function will recursively browse the default plug-ins directory and any
 * directory listed in the VLC_PLUGIN_PATH environment variable.
 * For performance reasons, a cache is normally used so that plug-in shared
 * objects do not need to loaded and linked into the process.
 */

static void AllocateAllPlugins (libvlc_int_t *p_this)
{
    char *paths;
    cache_mode_t mode = 0;

    if (var_InheritBool(p_this, "plugins-cache"))
        mode |= CACHE_READ_FILE;
    if (var_InheritBool(p_this, "plugins-scan"))
        mode |= CACHE_SCAN_DIR;
    if (var_InheritBool(p_this, "reset-plugins-cache"))
        mode = (mode | CACHE_WRITE_FILE) & ~CACHE_READ_FILE;

#ifdef HAVE_FORCED_PLUGINS
    /* Windows Store Apps can not load external plugins with absolute paths. */
    AllocatePluginPath (p_this, "plugins", mode);
#else
    /* Construct the special search path for system that have a relocatable
     * executable. Set it to <vlc path>/plugins. */

    char *vlcpath = config_GetSysPath(VLC_PKG_LIB_DIR, "plugins");
    if (likely(vlcpath != NULL))
    {
        AllocatePluginPath(p_this, vlcpath, mode);
        free(vlcpath);
    }
#endif

    /* If the user provided a plugin path, we add it to the list */
    paths = getenv( "VLC_PLUGIN_PATH" );
    if( paths == NULL )
        return;

#ifdef _WIN32
    paths = realpath( paths, NULL );
#else
    paths = strdup( paths ); /* don't harm the environment ! :) */
#endif
    if( unlikely(paths == NULL) )
        return;

    for( char *buf, *path = strtok_r( paths, PATH_SEP, &buf );
         path != NULL;
         path = strtok_r( NULL, PATH_SEP, &buf ) )
        AllocatePluginPath (p_this, path, mode);

    free( paths );
}

/**
 * Ensures that a plug-in is loaded.
 *
 * \note This function is thread-safe but not re-entrant.
 *
 * \return 0 on success, -1 on failure
 */

int vlc_plugin_Map(struct vlc_logger *log, vlc_plugin_t *plugin)
{
    static vlc_mutex_t lock = VLC_STATIC_MUTEX;

    if (plugin->abspath == NULL)
        return 0; /* static module needs not be mapped */
    if (atomic_load_explicit(&plugin->handle, memory_order_acquire))
        return 0; /* fast path: already loaded */

    /* Try to load the plug-in (without locks, so read-only) */
    assert(plugin->abspath != NULL);

    void *handle = module_Open(log, plugin->abspath, false);
    if (handle == NULL)
        return -1;

    vlc_plugin_cb entry = vlc_dlsym(handle, "vlc_entry");
    if (entry == NULL)
    {
        vlc_error(log, "cannot find plug-in entry point in %s",
                  plugin->abspath);
        goto error;
    }

    vlc_mutex_lock(&lock);
    if (atomic_load_explicit(&plugin->handle, memory_order_relaxed) == 0)
    {   /* Lock is held, update the plug-in structure */
        if (vlc_plugin_resolve(plugin, entry))
        {
            vlc_mutex_unlock(&lock);
            goto error;
        }

        atomic_store_explicit(&plugin->handle, (uintptr_t)handle,
                              memory_order_release);
    }
    else /* Another thread won the race to load the plugin */
        vlc_dlclose(handle);
    vlc_mutex_unlock(&lock);

    return 0;
error:
    vlc_dlclose(handle);
    return -1;
}

/**
 * Ensures that a module is not loaded.
 *
 * \note This function is not thread-safe. The caller must ensure that the
 * plug-in is no longer used before calling this function.
 */

static void vlc_plugin_Unmap(vlc_plugin_t *plugin)
{
    if (!plugin->unloadable)
        return;

    void *handle = (void *)atomic_exchange_explicit(&plugin->handle, 0,
                                                    memory_order_acquire);
    if (handle != NULL)
        vlc_dlclose(handle);
}

void *vlc_plugin_Symbol(struct vlc_logger *log,
                        vlc_plugin_t *plugin, const char *name)
{
    if (plugin->abspath == NULL || vlc_plugin_Map(log, plugin))
        return NULL;

    void *handle = (void *)atomic_load_explicit(&plugin->handle,
                                                memory_order_relaxed);
    assert(handle != NULL);
    return vlc_dlsym(handle, name);
}
#else
int vlc_plugin_Map(struct vlc_logger *log, vlc_plugin_t *plugin)
{
    (void) log; (void) plugin;
    return 0;
}

static void vlc_plugin_Unmap(vlc_plugin_t *plugin)
{
    (void) plugin;
}

void *vlc_plugin_Symbol(struct vlc_logger *log,
                        vlc_plugin_t *plugin, const char *name)
{
    (void) log; (void) plugin; (void) name;
    return NULL;
}
#endif /* HAVE_DYNAMIC_PLUGINS */

/**
 * Init bank
 *
 * Creates a module bank structure which will be filled later
 * on with all the modules found.
 */

void module_InitBank (void)
{
    vlc_mutex_lock (&modules.lock);

    if (modules.usage == 0)
    {
        /* Fills the module bank structure with the core module infos.
         * This is very useful as it will allow us to consider the core
         * library just as another module, and for instance the configuration
         * options of core will be available in the module bank structure just
         * as for every other module. */

        vlc_plugin_t *plugin = module_InitStatic(VLC_MODULE_ENTRY(core));
        if (likely(plugin != NULL))
            vlc_plugin_store(plugin);
        config_SortConfig ();
    }
    modules.usage++;

    /* 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 core (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 (&modules.lock);*/
}

/**
 * Unloads all unused plugin modules and empties the module
 * bank in case of success.
 */

void module_EndBank (bool b_plugins)
{
    vlc_plugin_t *libs = NULL;
    block_t *caches = NULL;
    void *caps_tree = NULL;

    /* If plugins were _not_ loaded, then the caller still has the bank lock
     * from module_InitBank(). */

    if( b_plugins )
        vlc_mutex_lock (&modules.lock);
    else
        vlc_mutex_assert(&modules.lock);

    assert (modules.usage > 0);
    if (--modules.usage == 0)
    {
        config_UnsortConfig ();
        libs = vlc_plugins;
        caches = modules.caches;
        caps_tree = modules.caps_tree;
        vlc_plugins = NULL;
        modules.caches = NULL;
        modules.caps_tree = NULL;
        modules.count = 0;
    }
    vlc_mutex_unlock (&modules.lock);

    tdestroy(caps_tree, vlc_modcap_free);

    while (libs != NULL)
    {
        vlc_plugin_t *lib = libs;

        libs = lib->next;
        vlc_plugin_Unmap(lib);
        vlc_plugin_destroy(lib);
    }

    block_ChainRelease(caches);
}

/**
 * Loads module descriptions for all available plugins.
 * Fills the module bank structure with the plugin modules.
 *
 * \param obj vlc object structure
 */

void module_LoadPlugins(libvlc_int_t *obj)
{
    /*vlc_mutex_assert (&modules.lock); not for static mutexes :( */

    if (modules.usage == 1)
    {
        module_InitStaticModules ();
#ifdef HAVE_DYNAMIC_PLUGINS
        msg_Dbg (obj, "searching plug-in modules");
        AllocateAllPlugins (obj);
#endif
        config_UnsortConfig ();
        config_SortConfig ();

        twalk(modules.caps_tree, vlc_modcap_sort);
    }
    vlc_mutex_unlock (&modules.lock);

    msg_Dbg (obj, "plug-ins loaded: %zu modules", modules.count);
}

void module_list_free (module_t **list)
{
    free (list);
}

module_t **module_list_get (size_t *n)
{
    assert (n != NULL);
    *n = modules.count;

    if (unlikely(modules.count == 0))
        return NULL;

    module_t **tab = malloc(modules.count * sizeof(*tab));
    if (unlikely(tab == NULL))
        return NULL;

    size_t i = 0;
    for (vlc_plugin_t *lib = vlc_plugins; lib != NULL; lib = lib->next)
    {
        for (module_t *m = lib->module; m != NULL; m = m->next)
        {
            assert(i < modules.count);
            tab[i++] = m;
        }
    }
    return tab;
}

size_t module_list_cap(module_t *const **restrict list, const char *name)
{
    vlc_modcap_t key;

    assert(name != NULL);
    key.name = (char *)name;

    const void **cp = tfind(&key, &modules.caps_tree, vlc_modcap_cmp);
    if (cp == NULL)
    {
        *list = NULL;
        return 0;
    }

    const vlc_modcap_t *cap = *cp;

    *list = cap->modv;
    return cap->modc;
}

Messung
CHZG
849610093

¤ Dauer der Verarbeitung: 0.18 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover


Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=1104842
#Domains=499165