Search
lxdream.org :: lxdream/src/plugin.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/plugin.c
changeset 1075:1a21750d300c
prev1071:182cfe43c09e
next1296:30ecee61f811
author nkeynes
date Fri Sep 17 20:08:50 2010 +1000 (13 years ago)
permissions -rw-r--r--
last change Refactor shader management to support multiple programs, which are all
defined in the shaders.glsl, rather than split up into one file per
fragment.
file annotate diff log raw
nkeynes@1024
     1
/**
nkeynes@1024
     2
 * $Id$
nkeynes@1024
     3
 *
nkeynes@1024
     4
 * Plugin loader code
nkeynes@1024
     5
 *
nkeynes@1024
     6
 * Copyright (c) 2009 Nathan Keynes.
nkeynes@1024
     7
 *
nkeynes@1024
     8
 * This program is free software; you can redistribute it and/or modify
nkeynes@1024
     9
 * it under the terms of the GNU General Public License as published by
nkeynes@1024
    10
 * the Free Software Foundation; either version 2 of the License, or
nkeynes@1024
    11
 * (at your option) any later version.
nkeynes@1024
    12
 *
nkeynes@1024
    13
 * This program is distributed in the hope that it will be useful,
nkeynes@1024
    14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
nkeynes@1024
    15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
nkeynes@1024
    16
 * GNU General Public License for more details.
nkeynes@1024
    17
 */
nkeynes@1024
    18
nkeynes@1027
    19
#include <sys/stat.h>
nkeynes@1024
    20
#include <dirent.h>
nkeynes@1024
    21
#include <dlfcn.h>
nkeynes@1024
    22
#include <string.h>
nkeynes@1024
    23
#include <glib/gmem.h>
nkeynes@1024
    24
#include <glib/gstrfuncs.h>
nkeynes@1024
    25
#include "plugin.h"
nkeynes@1041
    26
#include "lxpaths.h"
nkeynes@1024
    27
nkeynes@1024
    28
#ifdef APPLE_BUILD
nkeynes@1024
    29
#define SOEXT ".dylib"
nkeynes@1024
    30
#else
nkeynes@1024
    31
#define SOEXT ".so"
nkeynes@1024
    32
#endif
nkeynes@1024
    33
nkeynes@1027
    34
/** Dummy plugin used as a plugin directory marker */
nkeynes@1027
    35
#define DUMMY_PLUGIN ("lxdream_dummy" SOEXT) 
nkeynes@1024
    36
nkeynes@1027
    37
const char *plugin_type_string[] = { "undefined", "audio driver", "input driver" };
nkeynes@1027
    38
nkeynes@1027
    39
int main(int argc, char *argv[]);
nkeynes@1027
    40
static const char *exec_path = NULL;
nkeynes@1027
    41
nkeynes@1027
    42
/**
nkeynes@1027
    43
 * Return the full path to the main binary
nkeynes@1027
    44
 */
nkeynes@1027
    45
static const char *get_exec_path()
nkeynes@1027
    46
{
nkeynes@1027
    47
    if( exec_path == NULL ) {
nkeynes@1027
    48
        Dl_info dli;
nkeynes@1027
    49
nkeynes@1027
    50
        /* Use dladdr for this, since it should be available for any platform
nkeynes@1027
    51
         * that we can support plugins on at all.
nkeynes@1027
    52
         */
nkeynes@1027
    53
        if( dladdr( main, &dli) ) {
nkeynes@1027
    54
            gchar *path = g_strdup( dli.dli_fname );
nkeynes@1027
    55
            char *i = strrchr( path, '/' );
nkeynes@1027
    56
            if( i > path ) {
nkeynes@1027
    57
                *i = '\0';
nkeynes@1027
    58
                exec_path = path;
nkeynes@1027
    59
            } else {
nkeynes@1027
    60
                g_free(path);
nkeynes@1027
    61
            }
nkeynes@1027
    62
        }
nkeynes@1027
    63
    }
nkeynes@1027
    64
    return exec_path;
nkeynes@1027
    65
}
nkeynes@1027
    66
    
nkeynes@1027
    67
static gboolean plugin_load( const gchar *plugin_path )
nkeynes@1024
    68
{
nkeynes@1024
    69
    void *so = dlopen(plugin_path, RTLD_NOW|RTLD_LOCAL);
nkeynes@1024
    70
    if( so == NULL ) {
nkeynes@1024
    71
        WARN("Failed to load plugin '%s': %s", plugin_path, dlerror());
nkeynes@1024
    72
        return FALSE;
nkeynes@1024
    73
    }
nkeynes@1024
    74
    
nkeynes@1024
    75
    struct plugin_struct *plugin = (struct plugin_struct *)dlsym(so,"lxdream_plugin_entry");
nkeynes@1024
    76
    if( plugin == NULL ) {
nkeynes@1024
    77
        WARN("Failed to load plugin: '%s': Not an lxdream plugin", plugin_path);
nkeynes@1024
    78
        dlclose(so);
nkeynes@1024
    79
        return FALSE;
nkeynes@1024
    80
    }
nkeynes@1024
    81
nkeynes@1024
    82
    if( strcmp(lxdream_short_version, plugin->version) != 0 ) {
nkeynes@1024
    83
        WARN("Failed to load plugin: '%s': Incompatible version (%s)", plugin_path, plugin->version);
nkeynes@1024
    84
        dlclose(so);
nkeynes@1024
    85
        return FALSE;
nkeynes@1024
    86
    }
nkeynes@1024
    87
nkeynes@1027
    88
    if( plugin->type == PLUGIN_NONE ) {
nkeynes@1027
    89
        /* 'dummy' plugin - we don't actually want to load it */
nkeynes@1027
    90
        dlclose(so);
nkeynes@1027
    91
        return FALSE;
nkeynes@1027
    92
    }
nkeynes@1027
    93
    
nkeynes@1024
    94
    if( plugin->type < PLUGIN_MIN_TYPE || plugin->type > PLUGIN_MAX_TYPE ) {
nkeynes@1024
    95
        WARN("Failed to load plugin: '%s': Unrecognized plugin type (%d)", plugin_path, plugin->type );
nkeynes@1024
    96
        dlclose(so);
nkeynes@1024
    97
        return FALSE;
nkeynes@1024
    98
    }
nkeynes@1024
    99
nkeynes@1024
   100
    if( plugin->register_plugin() == FALSE ) {
nkeynes@1024
   101
        WARN("Failed to load plugin: '%s': Initialization failed", plugin_path);
nkeynes@1024
   102
        dlclose(so);
nkeynes@1024
   103
        return FALSE;
nkeynes@1024
   104
    }
nkeynes@1075
   105
    DEBUG("Loaded %s '%s'", plugin_type_string[plugin->type], plugin->name);
nkeynes@1024
   106
    return TRUE;
nkeynes@1024
   107
}
nkeynes@1024
   108
nkeynes@1027
   109
static gboolean has_plugins( const gchar *path )
nkeynes@1027
   110
{
nkeynes@1027
   111
    struct stat st;
nkeynes@1027
   112
    
nkeynes@1027
   113
    gchar *dummy_name = g_strdup_printf( "%s/%s", path, DUMMY_PLUGIN );
nkeynes@1027
   114
    if( stat( dummy_name, &st ) == 0 ) {
nkeynes@1027
   115
        return TRUE;
nkeynes@1027
   116
    } else {
nkeynes@1027
   117
        return FALSE;
nkeynes@1027
   118
    }
nkeynes@1027
   119
}
nkeynes@1027
   120
nkeynes@1024
   121
/**
nkeynes@1024
   122
 * Scan the plugin dir and load all valid plugins.
nkeynes@1024
   123
 */
nkeynes@1027
   124
static int plugin_load_all( const gchar *plugin_dir )
nkeynes@1024
   125
{
nkeynes@1071
   126
    int plugin_count = 0;
nkeynes@1024
   127
    struct dirent *ent;
nkeynes@1027
   128
    
nkeynes@1024
   129
    DIR *dir = opendir(plugin_dir);
nkeynes@1024
   130
    if( dir == NULL ) {
nkeynes@1024
   131
        WARN( "Unable to open plugin directory '%s'", plugin_dir );
nkeynes@1024
   132
        return 0;
nkeynes@1024
   133
    }
nkeynes@1024
   134
    
nkeynes@1024
   135
    while( (ent = readdir(dir)) != NULL ) {
nkeynes@1024
   136
        const char *ext = strrchr(ent->d_name, '.');
nkeynes@1024
   137
        if( ext != NULL && strcasecmp(SOEXT,ext) == 0 ) {
nkeynes@1024
   138
            char *libname = g_strdup_printf( "%s/%s", plugin_dir,ent->d_name );
nkeynes@1024
   139
            if( plugin_load( libname ) ) {
nkeynes@1024
   140
                plugin_count++;
nkeynes@1024
   141
            }
nkeynes@1024
   142
            g_free(libname);
nkeynes@1024
   143
        }
nkeynes@1024
   144
    }
nkeynes@1024
   145
    return plugin_count;
nkeynes@1024
   146
}
nkeynes@1027
   147
nkeynes@1027
   148
int plugin_init()
nkeynes@1027
   149
{
nkeynes@1027
   150
    const char *path = get_exec_path();
nkeynes@1027
   151
    if( path == NULL || !has_plugins(path) ) {
nkeynes@1027
   152
        path = get_plugin_path();
nkeynes@1027
   153
    }
nkeynes@1027
   154
    
nkeynes@1075
   155
    DEBUG( "Plugin directory: %s", path );
nkeynes@1027
   156
    return plugin_load_all( path );
nkeynes@1027
   157
}
.