| Index: third_party/dlfcn-win32/dlfcn.c
|
| ===================================================================
|
| --- third_party/dlfcn-win32/dlfcn.c (revision 0)
|
| +++ third_party/dlfcn-win32/dlfcn.c (revision 0)
|
| @@ -0,0 +1,312 @@
|
| +/*
|
| + * dlfcn-win32
|
| + * Copyright (c) 2007 Ramiro Polla
|
| + *
|
| + * This library 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 library 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 library; if not, write to the Free Software
|
| + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
| + */
|
| +
|
| +#include <windows.h>
|
| +#include <stdio.h>
|
| +
|
| +#include "dlfcn.h"
|
| +
|
| +/* Note:
|
| + * MSDN says these functions are not thread-safe. We make no efforts to have
|
| + * any kind of thread safety.
|
| + */
|
| +
|
| +typedef struct global_object {
|
| + HMODULE hModule;
|
| + struct global_object *previous;
|
| + struct global_object *next;
|
| +} global_object;
|
| +
|
| +static global_object first_object;
|
| +
|
| +/* These functions implement a double linked list for the global objects. */
|
| +static global_object *global_search( HMODULE hModule )
|
| +{
|
| + global_object *pobject;
|
| +
|
| + if( hModule == NULL )
|
| + return NULL;
|
| +
|
| + for( pobject = &first_object; pobject ; pobject = pobject->next )
|
| + if( pobject->hModule == hModule )
|
| + return pobject;
|
| +
|
| + return NULL;
|
| +}
|
| +
|
| +static void global_add( HMODULE hModule )
|
| +{
|
| + global_object *pobject;
|
| + global_object *nobject;
|
| +
|
| + if( hModule == NULL )
|
| + return;
|
| +
|
| + pobject = global_search( hModule );
|
| +
|
| + /* Do not add object again if it's already on the list */
|
| + if( pobject )
|
| + return;
|
| +
|
| + for( pobject = &first_object; pobject->next ; pobject = pobject->next );
|
| +
|
| + nobject = malloc( sizeof(global_object) );
|
| +
|
| + /* Should this be enough to fail global_add, and therefore also fail
|
| + * dlopen?
|
| + */
|
| + if( !nobject )
|
| + return;
|
| +
|
| + pobject->next = nobject;
|
| + nobject->next = NULL;
|
| + nobject->previous = pobject;
|
| + nobject->hModule = hModule;
|
| +}
|
| +
|
| +static void global_rem( HMODULE hModule )
|
| +{
|
| + global_object *pobject;
|
| +
|
| + if( hModule == NULL )
|
| + return;
|
| +
|
| + pobject = global_search( hModule );
|
| +
|
| + if( !pobject )
|
| + return;
|
| +
|
| + if( pobject->next )
|
| + pobject->next->previous = pobject->previous;
|
| + if( pobject->previous )
|
| + pobject->previous->next = pobject->next;
|
| +
|
| + free( pobject );
|
| +}
|
| +
|
| +/* POSIX says dlerror( ) doesn't have to be thread-safe, so we use one
|
| + * static buffer.
|
| + * MSDN says the buffer cannot be larger than 64K bytes, so we set it to
|
| + * the limit.
|
| + */
|
| +static char error_buffer[65535];
|
| +static char *current_error;
|
| +
|
| +static int copy_string( char *dest, int dest_size, const char *src )
|
| +{
|
| + int i = 0;
|
| +
|
| + /* gcc should optimize this out */
|
| + if( !src || !dest )
|
| + return 0;
|
| +
|
| + for( i = 0 ; i < dest_size-1 ; i++ )
|
| + {
|
| + if( !src[i] )
|
| + break;
|
| + else
|
| + dest[i] = src[i];
|
| + }
|
| + dest[i] = '\0';
|
| +
|
| + return i;
|
| +}
|
| +
|
| +static void save_err_str( const char *str )
|
| +{
|
| + DWORD dwMessageId;
|
| + DWORD pos;
|
| +
|
| + dwMessageId = GetLastError( );
|
| +
|
| + if( dwMessageId == 0 )
|
| + return;
|
| +
|
| + /* Format error message to:
|
| + * "<argument to function that failed>": <Windows localized error message>
|
| + */
|
| + pos = copy_string( error_buffer, sizeof(error_buffer), "\"" );
|
| + pos += copy_string( error_buffer+pos, sizeof(error_buffer)-pos, str );
|
| + pos += copy_string( error_buffer+pos, sizeof(error_buffer)-pos, "\": " );
|
| + pos += FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwMessageId,
|
| + MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ),
|
| + error_buffer+pos, sizeof(error_buffer)-pos, NULL );
|
| +
|
| + if( pos > 1 )
|
| + {
|
| + /* POSIX says the string must not have trailing <newline> */
|
| + if( error_buffer[pos-2] == '\r' && error_buffer[pos-1] == '\n' )
|
| + error_buffer[pos-2] = '\0';
|
| + }
|
| +
|
| + current_error = error_buffer;
|
| +}
|
| +
|
| +static void save_err_ptr_str( const void *ptr )
|
| +{
|
| + char ptr_buf[19]; /* 0x<pointer> up to 64 bits. */
|
| +
|
| + sprintf( ptr_buf, "0x%p", ptr );
|
| +
|
| + save_err_str( ptr_buf );
|
| +}
|
| +
|
| +void *dlopen( const char *file, int mode )
|
| +{
|
| + HMODULE hModule;
|
| + UINT uMode;
|
| +
|
| + current_error = NULL;
|
| +
|
| + /* Do not let Windows display the critical-error-handler message box */
|
| + uMode = SetErrorMode( SEM_FAILCRITICALERRORS );
|
| +
|
| + if( file == 0 )
|
| + {
|
| + /* POSIX says that if the value of file is 0, a handle on a global
|
| + * symbol object must be provided. That object must be able to access
|
| + * all symbols from the original program file, and any objects loaded
|
| + * with the RTLD_GLOBAL flag.
|
| + * The return value from GetModuleHandle( ) allows us to retrieve
|
| + * symbols only from the original program file. For objects loaded with
|
| + * the RTLD_GLOBAL flag, we create our own list later on.
|
| + */
|
| + hModule = GetModuleHandle( NULL );
|
| +
|
| + if( !hModule )
|
| + save_err_ptr_str( file );
|
| + }
|
| + else
|
| + {
|
| + char lpFileName[MAX_PATH];
|
| + int i;
|
| +
|
| + /* MSDN says backslashes *must* be used instead of forward slashes. */
|
| + for( i = 0 ; i < sizeof(lpFileName)-1 ; i++ )
|
| + {
|
| + if( !file[i] )
|
| + break;
|
| + else if( file[i] == '/' )
|
| + lpFileName[i] = '\\';
|
| + else
|
| + lpFileName[i] = file[i];
|
| + }
|
| + lpFileName[i] = '\0';
|
| +
|
| + /* POSIX says the search path is implementation-defined.
|
| + * LOAD_WITH_ALTERED_SEARCH_PATH is used to make it behave more closely
|
| + * to UNIX's search paths (start with system folders instead of current
|
| + * folder).
|
| + */
|
| + hModule = LoadLibraryEx( (LPSTR) lpFileName, NULL,
|
| + LOAD_WITH_ALTERED_SEARCH_PATH );
|
| +
|
| + /* If the object was loaded with RTLD_GLOBAL, add it to list of global
|
| + * objects, so that its symbols may be retrieved even if the handle for
|
| + * the original program file is passed. POSIX says that if the same
|
| + * file is specified in multiple invocations, and any of them are
|
| + * RTLD_GLOBAL, even if any further invocations use RTLD_LOCAL, the
|
| + * symbols will remain global.
|
| + */
|
| + if( !hModule )
|
| + save_err_str( lpFileName );
|
| + else if( (mode & RTLD_GLOBAL) )
|
| + global_add( hModule );
|
| + }
|
| +
|
| + /* Return to previous state of the error-mode bit flags. */
|
| + SetErrorMode( uMode );
|
| +
|
| + return (void *) hModule;
|
| +}
|
| +
|
| +int dlclose( void *handle )
|
| +{
|
| + HMODULE hModule = (HMODULE) handle;
|
| + BOOL ret;
|
| +
|
| + current_error = NULL;
|
| +
|
| + ret = FreeLibrary( hModule );
|
| +
|
| + /* If the object was loaded with RTLD_GLOBAL, remove it from list of global
|
| + * objects.
|
| + */
|
| + if( ret )
|
| + global_rem( hModule );
|
| + else
|
| + save_err_ptr_str( handle );
|
| +
|
| + /* dlclose's return value in inverted in relation to FreeLibrary's. */
|
| + ret = !ret;
|
| +
|
| + return (int) ret;
|
| +}
|
| +
|
| +void *dlsym( void *handle, const char *name )
|
| +{
|
| + FARPROC symbol;
|
| +
|
| + current_error = NULL;
|
| +
|
| + symbol = GetProcAddress( handle, name );
|
| +
|
| + if( symbol == NULL )
|
| + {
|
| + HMODULE hModule;
|
| +
|
| + /* If the handle for the original program file is passed, also search
|
| + * in all globally loaded objects.
|
| + */
|
| +
|
| + hModule = GetModuleHandle( NULL );
|
| +
|
| + if( hModule == handle )
|
| + {
|
| + global_object *pobject;
|
| +
|
| + for( pobject = &first_object; pobject ; pobject = pobject->next )
|
| + {
|
| + if( pobject->hModule )
|
| + {
|
| + symbol = GetProcAddress( pobject->hModule, name );
|
| + if( symbol != NULL )
|
| + break;
|
| + }
|
| + }
|
| + }
|
| + }
|
| +
|
| + if( symbol == NULL )
|
| + save_err_str( name );
|
| +
|
| + return (void*) symbol;
|
| +}
|
| +
|
| +char *dlerror( void )
|
| +{
|
| + char *error_pointer = current_error;
|
| +
|
| + /* POSIX says that invoking dlerror( ) a second time, immediately following
|
| + * a prior invocation, shall result in NULL being returned.
|
| + */
|
| + current_error = NULL;
|
| +
|
| + return error_pointer;
|
| +}
|
|
|
| Property changes on: third_party/dlfcn-win32/dlfcn.c
|
| ___________________________________________________________________
|
| Added: svn:eol-style
|
| + LF
|
|
|
|
|