filename | src/plugin.c |
changeset | 1075:1a21750d300c |
prev | 1071:182cfe43c09e |
next | 1296:30ecee61f811 |
author | nkeynes |
date | Wed Feb 15 17:54:51 2012 +1000 (12 years ago) |
permissions | -rw-r--r-- |
last change | Use GL_TEXTURE_2D instead of GL_TEXTURE_RECTANGLE_ARB for frame buffers, for systems that don't provide the latter (and there's not really much difference anyway). Add macro wrangling for GL_DEPTH24_STENCIL8 format |
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 | } |
.