//====================================================
//
//      Copyright 2008-2010 iAnywhere Solutions, Inc.
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//
//   See the License for the specific language governing permissions and
//   limitations under the License.
//
//   While not a requirement of the license, if you do modify this file, we
//   would appreciate hearing about it. Please email
//   sqlany_interfaces@sybase.com
//
//====================================================
#include <string.h>
#include <stdlib.h>
#include <stdio.h>

#if defined( _WIN32 )
#include <windows.h>
#define DEFAULT_LIBRARY_NAME "dbcapi.dll"
#else
#include <dlfcn.h>
/* assume we are running on a UNIX platform */
#if defined( __APPLE__ )
#define LIB_EXT "dylib"
#else
#define LIB_EXT "so"
#endif
#if defined( _REENTRANT ) || defined( _THREAD_SAFE ) \
 || defined( __USE_REENTRANT )
/* if building a thread-safe library, we need to load
   the thread-safe dbcapi library */
#define DEFAULT_LIBRARY_NAME "libdbcapi_r." LIB_EXT
#else
#define DEFAULT_LIBRARY_NAME "libdbcapi." LIB_EXT
#endif
#endif

#include "sacapidll.h"

static
void * loadLibrary( const char * name )
/*************************************/
{
  void * handle;
#if defined( _WIN32 )
  handle = LoadLibrary( name );
#else
  handle = dlopen( name, RTLD_LAZY );
#endif
  return handle;
}

static
void unloadLibrary( void * handle )
/**********************************/
{
#if defined( _WIN32 )
  FreeLibrary( handle );
#else
  dlclose( handle );
#endif
}

static
void * findSymbol( void * dll_handle, char * name )
/**************************************************/
{
#if defined( _WIN32 )
  return GetProcAddress( dll_handle, name );
#else
  return dlsym( dll_handle, name );
#endif
}

#define LookupSymbol( api, sym )     \
  api->sym = (sym ## _func)findSymbol( api->dll_handle, #sym );

#define LookupSymbolAndCheck( api, sym )    \
  api->sym = (sym ## _func)findSymbol( api->dll_handle, #sym ); \
  if( api->sym == NULL ) {     \
    unloadLibrary( api->dll_handle );    \
    return 0;       \
  }

int sqlany_initialize_interface( SQLAnywhereInterface * api, const char * path )
/*******************************************************************************/
{
  char * env;
  memset( api, 0, sizeof( *api ) );

  if ( path != NULL )
  {
    api->dll_handle = loadLibrary( path );
    if ( api->dll_handle != NULL )
    {
      goto loaded;
    }
  }
  env = getenv( "SQLANY_API_DLL" );
  if ( env != NULL )
  {
    api->dll_handle = loadLibrary( env );
    if ( api->dll_handle != NULL )
    {
      goto loaded;
    }
  }
  api->dll_handle = loadLibrary( DEFAULT_LIBRARY_NAME );
  if ( api->dll_handle != NULL )
  {
    goto loaded;
  }
  return 0;

loaded:
  LookupSymbolAndCheck( api, sqlany_init );
  LookupSymbolAndCheck( api, sqlany_fini );
  LookupSymbolAndCheck( api, sqlany_new_connection );
  LookupSymbolAndCheck( api, sqlany_free_connection );
  LookupSymbolAndCheck( api, sqlany_make_connection );
  LookupSymbolAndCheck( api, sqlany_connect );
  LookupSymbolAndCheck( api, sqlany_disconnect );
  LookupSymbolAndCheck( api, sqlany_execute_immediate );
  LookupSymbolAndCheck( api, sqlany_prepare );
  LookupSymbolAndCheck( api, sqlany_free_stmt );
  LookupSymbolAndCheck( api, sqlany_num_params );
  LookupSymbolAndCheck( api, sqlany_describe_bind_param );
  LookupSymbolAndCheck( api, sqlany_bind_param );
  LookupSymbolAndCheck( api, sqlany_send_param_data );
  LookupSymbolAndCheck( api, sqlany_reset );
  LookupSymbolAndCheck( api, sqlany_get_bind_param_info );
  LookupSymbolAndCheck( api, sqlany_execute );
  LookupSymbolAndCheck( api, sqlany_execute_direct );
  LookupSymbolAndCheck( api, sqlany_fetch_absolute );
  LookupSymbolAndCheck( api, sqlany_fetch_next );
  LookupSymbolAndCheck( api, sqlany_get_next_result );
  LookupSymbolAndCheck( api, sqlany_affected_rows );
  LookupSymbolAndCheck( api, sqlany_num_cols );
  LookupSymbolAndCheck( api, sqlany_num_rows );
  LookupSymbolAndCheck( api, sqlany_get_column );
  LookupSymbolAndCheck( api, sqlany_get_data );
  LookupSymbolAndCheck( api, sqlany_get_data_info );
  LookupSymbolAndCheck( api, sqlany_get_column_info );
  LookupSymbolAndCheck( api, sqlany_commit );
  LookupSymbolAndCheck( api, sqlany_rollback );
  LookupSymbolAndCheck( api, sqlany_client_version );
  LookupSymbolAndCheck( api, sqlany_error );
  LookupSymbolAndCheck( api, sqlany_sqlstate );
  LookupSymbolAndCheck( api, sqlany_clear_error );

#if _SACAPI_VERSION+0 >= 2
  /* We don't report an error if we don't find the v2 entry points.
     That allows the calling app to revert to v1 */
  LookupSymbol( api, sqlany_init_ex );
  LookupSymbol( api, sqlany_fini_ex );
  LookupSymbol( api, sqlany_new_connection_ex );
  LookupSymbol( api, sqlany_make_connection_ex );
  LookupSymbol( api, sqlany_client_version_ex );
  LookupSymbolAndCheck( api, sqlany_cancel );
#endif

  api->initialized = 1;
  return 1;
}
#undef LookupSymbolAndCheck

void sqlany_finalize_interface( SQLAnywhereInterface * api )
/***********************************************************/
{
  if ( !api->initialized )
  {
    return;
  }
  unloadLibrary( api->dll_handle );
  memset( api, 0, sizeof( *api ) );
}


