617 строки
16 KiB
C
617 строки
16 KiB
C
/****************************************************
|
|
* SQLGetPrivateProfileString
|
|
*
|
|
* Mostly used with odbc.ini files but can be used for odbcinst.ini
|
|
*
|
|
* IF pszFileName[0] == '/' THEN
|
|
* use pszFileName
|
|
* ELSE
|
|
* use _odbcinst_ConfigModeINI() to get the complete file name for the current mode.
|
|
*
|
|
**************************************************
|
|
* This code was created by Peter Harvey @ CodeByDesign.
|
|
* Released under LGPL 28.JAN.99
|
|
*
|
|
* Contributions from...
|
|
* -----------------------------------------------
|
|
* Peter Harvey - pharvey@codebydesign.com
|
|
**************************************************/
|
|
#include <config.h>
|
|
#include <time.h>
|
|
#include <odbcinstext.h>
|
|
|
|
#ifdef ENABLE_INI_CACHING
|
|
|
|
#ifdef HAVE_LIBPTH
|
|
|
|
#include <pth.h>
|
|
|
|
static pth_mutex_t mutex_ini = PTH_MUTEX_INIT;
|
|
static int pth_init_called = 0;
|
|
|
|
static int mutex_entry( pth_mutex_t *mutex )
|
|
{
|
|
if ( !pth_init_called )
|
|
{
|
|
pth_init();
|
|
pth_init_called = 1;
|
|
}
|
|
return pth_mutex_acquire( mutex, 0, NULL );
|
|
}
|
|
|
|
static int mutex_exit( pth_mutex_t *mutex )
|
|
{
|
|
return pth_mutex_release( mutex );
|
|
}
|
|
|
|
#elif HAVE_LIBPTHREAD
|
|
|
|
#include <pthread.h>
|
|
|
|
static pthread_mutex_t mutex_ini = PTHREAD_MUTEX_INITIALIZER;
|
|
|
|
static int mutex_entry( pthread_mutex_t *mutex )
|
|
{
|
|
return pthread_mutex_lock( mutex );
|
|
}
|
|
|
|
static int mutex_exit( pthread_mutex_t *mutex )
|
|
{
|
|
return pthread_mutex_unlock( mutex );
|
|
}
|
|
|
|
#elif HAVE_LIBTHREAD
|
|
|
|
#include <thread.h>
|
|
|
|
static mutex_t mutex_ini;
|
|
|
|
static int mutex_entry( mutex_t *mutex )
|
|
{
|
|
return mutex_lock( mutex );
|
|
}
|
|
|
|
static int mutex_exit( mutex_t *mutex )
|
|
{
|
|
return mutex_unlock( mutex );
|
|
}
|
|
|
|
#else
|
|
|
|
#define mutex_entry(x)
|
|
#define mutex_exit(x)
|
|
|
|
#endif
|
|
|
|
static struct ini_cache *ini_cache_head = NULL;
|
|
|
|
static int _check_ini_cache( int *ret,
|
|
LPCSTR pszSection,
|
|
LPCSTR pszEntry,
|
|
LPCSTR pszDefault,
|
|
LPSTR pRetBuffer,
|
|
int nRetBuffer,
|
|
LPCSTR pszFileName )
|
|
{
|
|
struct ini_cache *ini_cache = ini_cache_head, *prev = NULL;
|
|
UWORD config_mode;
|
|
long tstamp = time( NULL );
|
|
|
|
if ( pszSection == NULL || pszEntry == NULL )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
config_mode = __get_config_mode();
|
|
|
|
/*
|
|
* look for expired entries, remove one each call
|
|
*/
|
|
|
|
for ( prev = NULL, ini_cache = ini_cache_head; ini_cache; ini_cache = ini_cache -> next )
|
|
{
|
|
if ( ini_cache -> timestamp < tstamp )
|
|
{
|
|
if ( prev )
|
|
{
|
|
prev -> next = ini_cache -> next;
|
|
}
|
|
else
|
|
{
|
|
ini_cache_head = ini_cache -> next;
|
|
}
|
|
|
|
if ( ini_cache -> fname )
|
|
free( ini_cache -> fname );
|
|
|
|
if ( ini_cache -> section )
|
|
free( ini_cache -> section );
|
|
|
|
if ( ini_cache -> entry )
|
|
free( ini_cache -> entry );
|
|
|
|
if ( ini_cache -> value )
|
|
free( ini_cache -> value );
|
|
|
|
if ( ini_cache -> default_value )
|
|
free( ini_cache -> default_value );
|
|
|
|
free( ini_cache );
|
|
|
|
break;
|
|
}
|
|
|
|
prev = ini_cache;
|
|
}
|
|
|
|
for ( ini_cache = ini_cache_head; ini_cache; ini_cache = ini_cache -> next )
|
|
{
|
|
if ( !pszFileName && ini_cache -> fname )
|
|
continue;
|
|
if ( pszFileName && !ini_cache -> fname )
|
|
continue;
|
|
if ( pszFileName && ini_cache -> fname && strcmp( pszFileName, ini_cache -> fname ))
|
|
continue;
|
|
|
|
if ( ini_cache -> config_mode != config_mode )
|
|
continue;
|
|
|
|
if ( !pszSection && ini_cache -> section )
|
|
continue;
|
|
if ( pszSection && !ini_cache -> section )
|
|
continue;
|
|
if ( pszSection && ini_cache -> section && strcmp( pszSection, ini_cache -> section ))
|
|
continue;
|
|
|
|
if ( !pszEntry && ini_cache -> entry )
|
|
continue;
|
|
if ( pszEntry && !ini_cache -> entry )
|
|
continue;
|
|
if ( pszEntry && ini_cache -> entry && strcmp( pszEntry, ini_cache -> entry ))
|
|
continue;
|
|
|
|
if ( !pszDefault && ini_cache -> default_value )
|
|
continue;
|
|
if ( pszDefault && !ini_cache -> default_value )
|
|
continue;
|
|
if ( pszDefault && ini_cache -> default_value && strcmp( pszDefault, ini_cache -> default_value ))
|
|
continue;
|
|
|
|
if ( !pRetBuffer && ini_cache -> value )
|
|
continue;
|
|
if ( pRetBuffer && !ini_cache -> value )
|
|
continue;
|
|
|
|
if ( nRetBuffer != ini_cache -> buffer_size )
|
|
continue;
|
|
|
|
if ( pRetBuffer )
|
|
{
|
|
if ( ini_cache -> value )
|
|
strcpy( pRetBuffer, ini_cache -> value );
|
|
|
|
*ret = ini_cache -> ret_value;
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int _save_ini_cache( int ret,
|
|
LPCSTR pszSection,
|
|
LPCSTR pszEntry,
|
|
LPCSTR pszDefault,
|
|
LPSTR pRetBuffer,
|
|
int nRetBuffer,
|
|
LPCSTR pszFileName )
|
|
{
|
|
struct ini_cache *ini_cache;
|
|
UWORD config_mode;
|
|
long tstamp = time( NULL ) + 20; /* expiry every 20 seconds */
|
|
|
|
ini_cache = calloc( sizeof( struct ini_cache ), 1 );
|
|
if ( !ini_cache )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if ( pszFileName )
|
|
ini_cache -> fname = strdup( pszFileName );
|
|
|
|
if ( pszSection )
|
|
ini_cache -> section = strdup( pszSection );
|
|
|
|
if ( pszEntry )
|
|
ini_cache -> entry = strdup( pszEntry );
|
|
|
|
if ( pRetBuffer && ret >= 0 )
|
|
ini_cache -> value = strdup( pRetBuffer );
|
|
|
|
if ( pszDefault )
|
|
ini_cache -> default_value = strdup( pszDefault );
|
|
|
|
ini_cache -> buffer_size = nRetBuffer;
|
|
ini_cache -> ret_value = ret;
|
|
|
|
config_mode = __get_config_mode();
|
|
ini_cache -> config_mode = config_mode;
|
|
|
|
ini_cache -> timestamp = tstamp;
|
|
|
|
ini_cache -> next = ini_cache_head;
|
|
ini_cache_head = ini_cache;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* wrappers to provide therad safety
|
|
*/
|
|
|
|
static int check_ini_cache( int *ret,
|
|
LPCSTR pszSection,
|
|
LPCSTR pszEntry,
|
|
LPCSTR pszDefault,
|
|
LPSTR pRetBuffer,
|
|
int nRetBuffer,
|
|
LPCSTR pszFileName )
|
|
{
|
|
int rval;
|
|
|
|
mutex_entry( &mutex_ini );
|
|
|
|
rval = _check_ini_cache( ret, pszSection, pszEntry, pszDefault,
|
|
pRetBuffer, nRetBuffer, pszFileName );
|
|
|
|
mutex_exit( &mutex_ini );
|
|
|
|
return rval;
|
|
}
|
|
|
|
static int save_ini_cache( int ret,
|
|
LPCSTR pszSection,
|
|
LPCSTR pszEntry,
|
|
LPCSTR pszDefault,
|
|
LPSTR pRetBuffer,
|
|
int nRetBuffer,
|
|
LPCSTR pszFileName )
|
|
{
|
|
int rval, cval;
|
|
|
|
mutex_entry( &mutex_ini );
|
|
|
|
/*
|
|
* check its not been inserted since the last check
|
|
*/
|
|
|
|
if ( !_check_ini_cache( &cval, pszSection, pszEntry, pszDefault,
|
|
pRetBuffer, nRetBuffer, pszFileName )) {
|
|
|
|
rval = _save_ini_cache( ret, pszSection, pszEntry, pszDefault,
|
|
pRetBuffer, nRetBuffer, pszFileName );
|
|
}
|
|
|
|
mutex_exit( &mutex_ini );
|
|
|
|
return rval;
|
|
}
|
|
|
|
|
|
#else
|
|
|
|
static int check_ini_cache( int *ret,
|
|
LPCSTR pszSection,
|
|
LPCSTR pszEntry,
|
|
LPCSTR pszDefault,
|
|
LPSTR pRetBuffer,
|
|
int nRetBuffer,
|
|
LPCSTR pszFileName )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static int save_ini_cache( int ret,
|
|
LPCSTR pszSection,
|
|
LPCSTR pszEntry,
|
|
LPCSTR pszDefault,
|
|
LPSTR pRetBuffer,
|
|
int nRetBuffer,
|
|
LPCSTR pszFileName )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
#endif
|
|
|
|
int SQLGetPrivateProfileString( LPCSTR pszSection,
|
|
LPCSTR pszEntry,
|
|
LPCSTR pszDefault,
|
|
LPSTR pRetBuffer,
|
|
int nRetBuffer,
|
|
LPCSTR pszFileName
|
|
)
|
|
{
|
|
HINI hIni;
|
|
int nBufPos = 0;
|
|
char szValue[INI_MAX_PROPERTY_VALUE+1];
|
|
char szFileName[ODBC_FILENAME_MAX+1];
|
|
UWORD nConfigMode;
|
|
int ini_done = 0;
|
|
int ret;
|
|
|
|
inst_logClear();
|
|
|
|
if ( check_ini_cache( &ret, pszSection, pszEntry, pszDefault, pRetBuffer, nRetBuffer, pszFileName ))
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
/* SANITY CHECKS */
|
|
if ( pRetBuffer == NULL || nRetBuffer < 2 )
|
|
{
|
|
inst_logPushMsg( __FILE__, __FILE__, __LINE__, LOG_CRITICAL, ODBC_ERROR_GENERAL_ERR, "" );
|
|
return -1;
|
|
}
|
|
if ( pszSection != NULL && pszEntry != NULL && pszDefault == NULL )
|
|
{
|
|
inst_logPushMsg( __FILE__, __FILE__, __LINE__, LOG_CRITICAL, ODBC_ERROR_GENERAL_ERR, "need default value - try empty string" );
|
|
return -1;
|
|
}
|
|
|
|
*pRetBuffer = '\0';
|
|
|
|
/*****************************************************
|
|
* SOME MS CODE (ie some drivers) MAY USE THIS FUNCTION TO GET ODBCINST INFO SO...
|
|
*****************************************************/
|
|
if ( pszFileName != NULL )
|
|
{
|
|
if ( strstr( pszFileName, "odbcinst" ) || strstr( pszFileName, "ODBCINST" ) )
|
|
{
|
|
ret = _SQLGetInstalledDrivers( pszSection, pszEntry, pszDefault, pRetBuffer, nRetBuffer );
|
|
|
|
if ( ret == -1 )
|
|
{
|
|
/* try to use any default provided */
|
|
if ( pRetBuffer && nRetBuffer > 0 )
|
|
{
|
|
if ( pszDefault )
|
|
{
|
|
strncpy( pRetBuffer, pszDefault, nRetBuffer );
|
|
pRetBuffer[ nRetBuffer - 1 ] = '\0';
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
save_ini_cache( ret, pszSection, pszEntry, pszDefault, pRetBuffer, nRetBuffer, pszFileName );
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
/*****************************************************
|
|
* GATHER ALL RELEVANT DSN INFORMATION INTO AN hIni
|
|
*****************************************************/
|
|
if ( pszFileName != 0 && pszFileName[0] == '/' )
|
|
{
|
|
#ifdef __OS2__
|
|
if ( iniOpen( &hIni, (char*)pszFileName, "#;", '[', ']', '=', TRUE, 1L )
|
|
!= INI_SUCCESS )
|
|
#else
|
|
if ( iniOpen( &hIni, (char*)pszFileName, "#;", '[', ']', '=', TRUE )
|
|
!= INI_SUCCESS )
|
|
#endif
|
|
{
|
|
inst_logPushMsg( __FILE__, __FILE__, __LINE__, LOG_CRITICAL,
|
|
ODBC_ERROR_COMPONENT_NOT_FOUND, "" );
|
|
return -1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
nConfigMode = __get_config_mode();
|
|
nBufPos = 0;
|
|
szFileName[0] = '\0';
|
|
|
|
switch ( nConfigMode )
|
|
{
|
|
case ODBC_BOTH_DSN:
|
|
if ( _odbcinst_UserINI( szFileName, TRUE ))
|
|
{
|
|
#ifdef __OS2__
|
|
if ( iniOpen( &hIni, (char*) szFileName, "#;", '[', ']', '=', TRUE, 1L )
|
|
== INI_SUCCESS )
|
|
#else
|
|
if ( iniOpen( &hIni, (char*) szFileName, "#;", '[', ']', '=', TRUE )
|
|
== INI_SUCCESS )
|
|
#endif
|
|
{
|
|
ini_done = 1;
|
|
}
|
|
}
|
|
_odbcinst_SystemINI( szFileName, TRUE );
|
|
if ( !ini_done )
|
|
{
|
|
#ifdef __OS2__
|
|
if ( iniOpen( &hIni, szFileName, "#;", '[', ']', '=', TRUE, 1L )
|
|
!= INI_SUCCESS )
|
|
#else
|
|
if ( iniOpen( &hIni, szFileName, "#;", '[', ']', '=', TRUE )
|
|
!= INI_SUCCESS )
|
|
#endif
|
|
{
|
|
inst_logPushMsg( __FILE__, __FILE__, __LINE__,
|
|
LOG_CRITICAL, ODBC_ERROR_COMPONENT_NOT_FOUND, "" );
|
|
return -1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
iniAppend( hIni, szFileName );
|
|
}
|
|
break;
|
|
|
|
case ODBC_USER_DSN:
|
|
_odbcinst_UserINI( szFileName, TRUE );
|
|
#ifdef __OS2__
|
|
if ( iniOpen( &hIni, szFileName, "#;", '[', ']', '=', TRUE, 1L )
|
|
!= INI_SUCCESS )
|
|
#else
|
|
if ( iniOpen( &hIni, szFileName, "#;", '[', ']', '=', TRUE )
|
|
!= INI_SUCCESS )
|
|
#endif
|
|
{
|
|
inst_logPushMsg( __FILE__, __FILE__, __LINE__, LOG_CRITICAL,
|
|
ODBC_ERROR_COMPONENT_NOT_FOUND, "" );
|
|
return -1;
|
|
}
|
|
break;
|
|
|
|
case ODBC_SYSTEM_DSN:
|
|
_odbcinst_SystemINI( szFileName, TRUE );
|
|
#ifdef __OS2__
|
|
if ( iniOpen( &hIni, szFileName, "#;", '[', ']', '=', TRUE, 1L )
|
|
!= INI_SUCCESS )
|
|
#else
|
|
if ( iniOpen( &hIni, szFileName, "#;", '[', ']', '=', TRUE )
|
|
!= INI_SUCCESS )
|
|
#endif
|
|
{
|
|
inst_logPushMsg( __FILE__, __FILE__, __LINE__, LOG_CRITICAL,
|
|
ODBC_ERROR_COMPONENT_NOT_FOUND, "" );
|
|
return -1;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
inst_logPushMsg( __FILE__, __FILE__, __LINE__, LOG_CRITICAL,
|
|
ODBC_ERROR_GENERAL_ERR, "Invalid Config Mode" );
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
/*****************************************************
|
|
* EXTRACT SECTIONS
|
|
*****************************************************/
|
|
if ( pszSection == NULL )
|
|
{
|
|
_odbcinst_GetSections( hIni, pRetBuffer, nRetBuffer, &nBufPos );
|
|
}
|
|
/*****************************************************
|
|
* EXTRACT ENTRIES
|
|
*****************************************************/
|
|
else if ( pszEntry == NULL )
|
|
{
|
|
_odbcinst_GetEntries( hIni, pszSection, pRetBuffer, nRetBuffer, &nBufPos );
|
|
}
|
|
/*****************************************************
|
|
* EXTRACT AN ENTRY
|
|
*****************************************************/
|
|
else
|
|
{
|
|
if ( pszSection == NULL || pszEntry == NULL || pszDefault == NULL )
|
|
{
|
|
inst_logPushMsg( __FILE__, __FILE__, __LINE__, LOG_CRITICAL, ODBC_ERROR_GENERAL_ERR, "" );
|
|
return -1;
|
|
}
|
|
|
|
/* TRY TO GET THE ONE ITEM MATCHING Section & Entry */
|
|
if ( iniPropertySeek( hIni, (char *)pszSection, (char *)pszEntry, "" ) != INI_SUCCESS )
|
|
{
|
|
/*
|
|
* (NG) this seems to be ignoring the length of pRetBuffer !!!
|
|
*/
|
|
/* strncpy( pRetBuffer, pszDefault, INI_MAX_PROPERTY_VALUE ); */
|
|
if ( pRetBuffer && nRetBuffer > 0 && pszDefault )
|
|
{
|
|
strncpy( pRetBuffer, pszDefault, nRetBuffer );
|
|
pRetBuffer[ nRetBuffer - 1 ] = '\0';
|
|
}
|
|
}
|
|
else
|
|
{
|
|
iniValue( hIni, szValue );
|
|
if ( pRetBuffer )
|
|
{
|
|
strncpy( pRetBuffer, szValue, nRetBuffer );
|
|
pRetBuffer[ nRetBuffer - 1 ] = '\0';
|
|
}
|
|
nBufPos = strlen( szValue );
|
|
}
|
|
}
|
|
|
|
iniClose( hIni );
|
|
|
|
ret = strlen( pRetBuffer );
|
|
|
|
save_ini_cache( ret, pszSection, pszEntry, pszDefault, pRetBuffer, nRetBuffer, pszFileName );
|
|
|
|
return ret;
|
|
}
|
|
|
|
int INSTAPI SQLGetPrivateProfileStringW( LPCWSTR lpszSection,
|
|
LPCWSTR lpszEntry,
|
|
LPCWSTR lpszDefault,
|
|
LPWSTR lpszRetBuffer,
|
|
int cbRetBuffer,
|
|
LPCWSTR lpszFilename)
|
|
{
|
|
int ret;
|
|
char *sect;
|
|
char *entry;
|
|
char *def;
|
|
char *buf;
|
|
char *name;
|
|
|
|
inst_logClear();
|
|
|
|
sect = lpszSection ? _single_string_alloc_and_copy( lpszSection ) : (char*)NULL;
|
|
entry = lpszEntry ? _single_string_alloc_and_copy( lpszEntry ) : (char*)NULL;
|
|
def = lpszDefault ? _single_string_alloc_and_copy( lpszDefault ) : (char*)NULL;
|
|
name = lpszFilename ? _single_string_alloc_and_copy( lpszFilename ) : (char*)NULL;
|
|
|
|
if ( lpszRetBuffer )
|
|
{
|
|
if ( cbRetBuffer > 0 )
|
|
{
|
|
buf = calloc( cbRetBuffer + 1, 1 );
|
|
}
|
|
else
|
|
{
|
|
buf = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
buf = NULL;
|
|
}
|
|
|
|
ret = SQLGetPrivateProfileString( sect, entry, def, buf, cbRetBuffer, name );
|
|
|
|
if ( sect )
|
|
free( sect );
|
|
if ( entry )
|
|
free( entry );
|
|
if ( def )
|
|
free( def );
|
|
if ( name )
|
|
free( name );
|
|
|
|
if ( ret > 0 )
|
|
{
|
|
if ( buf && lpszRetBuffer )
|
|
{
|
|
_single_copy_to_wide( lpszRetBuffer, buf, ret + 1 );
|
|
}
|
|
}
|
|
|
|
if ( buf )
|
|
{
|
|
free( buf );
|
|
}
|
|
|
|
return ret;
|
|
}
|