Files
harbour-core/src/rdd/dbf1.c
Przemysław Czerpak ef962484be 2014-10-24 15:15 UTC+0200 Przemyslaw Czerpak (druzus/at/poczta.onet.pl)
* include/hbrddntx.h
  * src/rdd/workarea.c
  * src/rdd/dbf1.c
  * src/rdd/delim1.c
  * src/rdd/sdf1.c
  * src/rdd/dbfcdx/dbfcdx1.c
  * src/rdd/dbfnsx/dbfnsx1.c
  * src/rdd/dbfntx/dbfntx1.c
  * src/rdd/dbffpt/dbffpt1.c
  * contrib/rddads/ads1.c
  * contrib/rddads/adsfunc.c
  * contrib/rddads/adsx.c
  * contrib/rddsql/sqlbase.c
  * contrib/rddsql/sqlmix.c
  * contrib/sddfb/core.c
  * contrib/sddmy/core.c
  * contrib/sddoci/core.c
  * contrib/sddodbc/core.c
  * contrib/sddpg/core.c
  * contrib/sddsqlt3/core.c
    * cleaned AREAP casting
    * unified some variable names
    * cleaned some DBOI_* actions
    * allow to call ORDERINFO() method without itmResult item.
    * few other cleanups
2014-10-24 15:15:39 +02:00

6228 lines
184 KiB
C

/*
* Harbour Project source code:
* DBF RDD module
*
* Copyright 1999 Bruno Cantero <bruno@issnet.net>
* www - http://harbour-project.org
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; see the file COPYING.txt. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/).
*
* As a special exception, the Harbour Project gives permission for
* additional uses of the text contained in its release of Harbour.
*
* The exception is that, if you link the Harbour libraries with other
* files to produce an executable, this does not by itself cause the
* resulting executable to be covered by the GNU General Public License.
* Your use of that executable is in no way restricted on account of
* linking the Harbour library code into it.
*
* This exception does not however invalidate any other reasons why
* the executable file might be covered by the GNU General Public License.
*
* This exception applies only to the code released by the Harbour
* Project under the name Harbour. If you copy code from other
* Harbour Project or Free Software Foundation releases into a copy of
* Harbour, as the General Public License permits, the exception does
* not apply to the code that you add in this way. To avoid misleading
* anyone as to the status of such modified files, you must delete
* this exception notice from them.
*
* If you write modifications of your own for Harbour, it is your choice
* whether to permit this exception to apply to your modifications.
* If you do not wish that, delete this exception notice.
*
*/
#define HB_TRIGVAR_BYREF
#include "hbrdddbf.h"
#include "hbdbsort.h"
#include "hbapiitm.h"
#include "hbapistr.h"
#include "hbapierr.h"
#include "hbapilng.h"
#include "hbset.h"
#include "hbdate.h"
#include "hbsxfunc.h"
#include "hbstack.h"
#include "hbvm.h"
#include "error.ch"
#include "rddsys.ch"
#include "hbsxdef.ch"
#include "hbapicdp.h"
static HB_USHORT s_uiRddId = ( HB_USHORT ) -1;
static RDDFUNCS dbfSuper;
/*
* Common functions.
*/
#define HB_BLANK_APPEND 1
#define HB_BLANK_EOF 2
#define HB_BLANK_ROLLBACK 3
#define HB_BLANK_SKIP 100
#define HB_BLANK_AUTOINC 101
#define HB_BLANK_UNISPACE 102
/*
* generate Run-Time error
*/
static HB_ERRCODE hb_dbfErrorRT( DBFAREAP pArea,
HB_ERRCODE errGenCode, HB_ERRCODE errSubCode,
const char * szFileName, HB_ERRCODE errOsCode,
HB_USHORT uiFlags, PHB_ITEM * pErrorPtr )
{
PHB_ITEM pError;
HB_ERRCODE errCode = HB_FAILURE;
if( hb_vmRequestQuery() == 0 )
{
if( pErrorPtr )
{
if( ! *pErrorPtr )
*pErrorPtr = hb_errNew();
pError = *pErrorPtr;
}
else
pError = hb_errNew();
hb_errPutGenCode( pError, errGenCode );
hb_errPutSubCode( pError, errSubCode );
hb_errPutOsCode( pError, errOsCode );
hb_errPutDescription( pError, hb_langDGetErrorDesc( errGenCode ) );
if( szFileName )
hb_errPutFileName( pError, szFileName );
if( uiFlags )
hb_errPutFlags( pError, uiFlags );
errCode = SELF_ERROR( &pArea->area, pError );
if( ! pErrorPtr )
hb_errRelease( pError );
}
return errCode;
}
static HB_MAXINT hb_dbfGetRowVer( DBFAREAP pArea, HB_USHORT uiField, HB_MAXINT * pValue )
{
DBFFIELD dbField;
HB_BOOL fLck = HB_FALSE;
*pValue = 0;
if( pArea->fShared && ! pArea->fFLocked && ! pArea->fHeaderLocked )
{
if( SELF_RAWLOCK( &pArea->area, HEADER_LOCK, 0 ) != HB_SUCCESS )
return HB_FAILURE;
fLck = HB_TRUE;
}
if( hb_fileReadAt( pArea->pDataFile, &dbField, sizeof( dbField ),
sizeof( DBFHEADER ) + uiField * sizeof( DBFFIELD ) ) ==
sizeof( dbField ) )
{
*pValue = HB_GET_LE_UINT64( dbField.bReserved2 ) + 1;
HB_PUT_LE_UINT64( dbField.bReserved2, *pValue );
hb_fileWriteAt( pArea->pDataFile, &dbField, sizeof( dbField ),
sizeof( DBFHEADER ) + uiField * sizeof( DBFFIELD ) );
}
if( fLck )
{
if( SELF_RAWLOCK( &pArea->area, HEADER_UNLOCK, 0 ) != HB_SUCCESS )
return HB_FAILURE;
}
return HB_SUCCESS;
}
static void hb_dbfSetRowVer( DBFAREAP pArea, HB_USHORT uiField, HB_MAXINT nValue )
{
DBFFIELD dbField;
if( hb_fileReadAt( pArea->pDataFile, &dbField, sizeof( dbField ),
sizeof( DBFHEADER ) + uiField * sizeof( DBFFIELD ) ) ==
sizeof( dbField ) )
{
HB_PUT_LE_UINT64( dbField.bReserved2, nValue );
hb_fileWriteAt( pArea->pDataFile, &dbField, sizeof( dbField ),
sizeof( DBFHEADER ) + uiField * sizeof( DBFFIELD ) );
}
}
static HB_BOOL hb_dbfIsAutoIncField( LPFIELD pField )
{
switch( pField->uiType )
{
case HB_FT_INTEGER:
case HB_FT_DOUBLE:
case HB_FT_LONG:
case HB_FT_FLOAT:
return ( pField->uiFlags & HB_FF_AUTOINC ) != 0;
case HB_FT_AUTOINC:
return HB_TRUE;
}
return HB_FALSE;
}
static HB_MAXINT hb_dbfGetNextValue( DBFAREAP pArea, HB_USHORT uiField, HB_BOOL fUpdate )
{
HB_MAXINT nValue = 0;
DBFFIELD dbField;
if( hb_fileReadAt( pArea->pDataFile, &dbField, sizeof( dbField ),
sizeof( DBFHEADER ) + uiField * sizeof( DBFFIELD ) ) ==
sizeof( dbField ) )
{
nValue = HB_GET_LE_UINT32( dbField.bCounter );
if( fUpdate )
{
HB_PUT_LE_UINT32( dbField.bCounter, nValue + dbField.bStep );
hb_fileWriteAt( pArea->pDataFile, &dbField, sizeof( dbField ),
sizeof( DBFHEADER ) + uiField * sizeof( DBFFIELD ) );
}
}
return nValue;
}
static HB_MAXINT hb_dbfSetNextValue( DBFAREAP pArea, HB_USHORT uiField, HB_MAXINT nValue )
{
DBFFIELD dbField;
HB_MAXINT nPrevValue = 0;
if( hb_fileReadAt( pArea->pDataFile, &dbField, sizeof( dbField ),
sizeof( DBFHEADER ) + uiField * sizeof( DBFFIELD ) ) ==
sizeof( dbField ) )
{
nPrevValue = HB_GET_LE_UINT32( dbField.bCounter );
HB_PUT_LE_UINT32( dbField.bCounter, nValue );
hb_fileWriteAt( pArea->pDataFile, &dbField, sizeof( dbField ),
sizeof( DBFHEADER ) + uiField * sizeof( DBFFIELD ) );
}
return nPrevValue;
}
static int hb_dbfAtoincStep( DBFAREAP pArea, HB_USHORT uiField, int iStep )
{
DBFFIELD dbField;
int iPrevStep = 0;
if( hb_fileReadAt( pArea->pDataFile, &dbField, sizeof( dbField ),
sizeof( DBFHEADER ) + uiField * sizeof( DBFFIELD ) ) ==
sizeof( dbField ) )
{
iPrevStep = dbField.bStep;
if( iStep != 0 )
{
dbField.bStep = ( HB_BYTE ) iStep;
hb_fileWriteAt( pArea->pDataFile, &dbField, sizeof( dbField ),
sizeof( DBFHEADER ) + uiField * sizeof( DBFFIELD ) );
}
}
return iPrevStep;
}
static void hb_dbfUpdateStampFields( DBFAREAP pArea )
{
long lJulian = 0, lMilliSec = 0;
HB_MAXINT nRowVer = 0;
LPFIELD pField;
HB_USHORT uiCount;
for( uiCount = 0, pField = pArea->area.lpFields; uiCount < pArea->area.uiFieldCount; uiCount++, pField++ )
{
switch( pField->uiType )
{
case HB_FT_MODTIME:
{
HB_BYTE * pPtr = pArea->pRecord + pArea->pFieldOffset[ uiCount ];
if( lJulian == 0 )
hb_timeStampGet( &lJulian, &lMilliSec );
HB_PUT_LE_UINT32( pPtr, lJulian );
pPtr += 4;
HB_PUT_LE_UINT32( pPtr, lMilliSec );
break;
}
case HB_FT_ROWVER:
{
HB_BYTE * pPtr = pArea->pRecord + pArea->pFieldOffset[ uiCount ];
if( nRowVer == 0 )
hb_dbfGetRowVer( pArea, uiCount, &nRowVer );
HB_PUT_LE_UINT64( pPtr, nRowVer );
break;
}
}
}
}
static void hb_dbfSetBlankRecord( DBFAREAP pArea, int iType )
{
HB_BYTE * pPtr = pArea->pRecord, bFill = ' ', bNext;
HB_SIZE nSize = 1; /* 1 byte ' ' for DELETE flag */
HB_USHORT uiCount;
LPFIELD pField;
for( uiCount = 0, pField = pArea->area.lpFields; uiCount < pArea->area.uiFieldCount; uiCount++, pField++ )
{
HB_USHORT uiLen = pField->uiLen;
switch( pField->uiType )
{
case HB_FT_MEMO:
case HB_FT_IMAGE:
case HB_FT_BLOB:
case HB_FT_OLE:
bNext = uiLen == 10 ? ' ' : '\0';
break;
case HB_FT_DATE:
bNext = uiLen == 8 ? ' ' : '\0';
break;
case HB_FT_LOGICAL:
bNext = ' ';
break;
case HB_FT_STRING:
bNext = ( pField->uiFlags & HB_FF_UNICODE ) != 0 ?
HB_BLANK_UNISPACE : ' ';
break;
case HB_FT_LONG:
case HB_FT_FLOAT:
if( pField->uiFlags & HB_FF_AUTOINC )
{
if( iType == HB_BLANK_APPEND )
{
bNext = HB_BLANK_AUTOINC;
break;
}
else if( iType == HB_BLANK_ROLLBACK )
{
bNext = HB_BLANK_SKIP;
break;
}
}
bNext = ' ';
break;
case HB_FT_AUTOINC:
if( iType == HB_BLANK_APPEND )
bNext = HB_BLANK_AUTOINC;
else if( iType == HB_BLANK_ROLLBACK )
bNext = HB_BLANK_SKIP;
else
bNext = '\0';
break;
case HB_FT_INTEGER:
case HB_FT_DOUBLE:
if( pField->uiFlags & HB_FF_AUTOINC )
{
if( iType == HB_BLANK_APPEND )
{
bNext = HB_BLANK_AUTOINC;
break;
}
else if( iType == HB_BLANK_ROLLBACK )
{
bNext = HB_BLANK_SKIP;
break;
}
}
bNext = '\0';
break;
default:
bNext = '\0';
break;
}
if( bNext == bFill )
{
nSize += uiLen;
}
else
{
if( nSize )
{
memset( pPtr, bFill, nSize );
pPtr += nSize;
nSize = 0;
}
if( bNext == HB_BLANK_SKIP )
{
pPtr += uiLen;
}
else if( bNext == HB_BLANK_UNISPACE )
{
while( uiLen-- )
{
HB_PUT_LE_UINT16( pPtr, 0x0020 );
pPtr += 2;
}
}
else if( bNext == HB_BLANK_AUTOINC )
{
HB_MAXINT nValue = hb_dbfGetNextValue( pArea, uiCount, HB_TRUE );
if( pField->uiDec )
nValue = ( HB_MAXINT ) hb_numDecConv( ( double ) nValue, -( int ) pField->uiDec );
if( pField->uiType == HB_FT_INTEGER ||
pField->uiType == HB_FT_AUTOINC )
{
if( uiLen == 1 )
*pPtr = ( signed char ) nValue;
else if( uiLen == 2 )
HB_PUT_LE_UINT16( pPtr, nValue );
else if( uiLen == 3 )
HB_PUT_LE_UINT24( pPtr, nValue );
else if( uiLen == 4 )
HB_PUT_LE_UINT32( pPtr, nValue );
else if( uiLen == 8 )
HB_PUT_LE_UINT64( pPtr, nValue );
}
else if( pField->uiType == HB_FT_DOUBLE )
{
HB_PUT_LE_DOUBLE( pPtr, nValue );
}
else
{
HB_USHORT ui = uiLen;
do
{
pPtr[ --ui ] = ( HB_BYTE ) nValue % 10 + '0';
nValue /= 10;
}
while( ui && nValue >= 1 );
}
pPtr += uiLen;
}
else
{
nSize = uiLen;
bFill = bNext;
}
}
}
memset( pPtr, bFill, nSize );
nSize += pPtr - pArea->pRecord;
if( nSize < ( HB_SIZE ) pArea->uiRecordLen )
memset( pArea->pRecord + nSize, '\0', ( HB_SIZE ) pArea->uiRecordLen - nSize );
/* set varlength and nullable bits in _NullFlags */
if( pArea->uiNullCount )
{
memset( pArea->pRecord + pArea->uiNullOffset, 0xff, pArea->uiNullCount >> 3 );
uiCount = pArea->uiNullCount & 0x07;
if( uiCount )
pArea->pRecord[ pArea->uiNullOffset + ( pArea->uiNullCount >> 3 ) ] = ( 1 << uiCount ) - 1;
}
}
static void hb_dbfAllocNullFlag( DBFAREAP pArea, HB_USHORT uiField, HB_BOOL fLength )
{
if( ! pArea->pFieldBits )
{
HB_SIZE nSize = sizeof( HB_DBFFIELDBITS ) * pArea->area.uiFieldExtent;
pArea->pFieldBits = ( PHB_DBFFIELDBITS ) memset( hb_xgrab( nSize ), 0, nSize );
}
if( fLength )
pArea->pFieldBits[ uiField ].uiLengthBit = pArea->uiNullCount++;
else
pArea->pFieldBits[ uiField ].uiNullBit = pArea->uiNullCount++;
}
static HB_BOOL hb_dbfGetNullFlag( DBFAREAP pArea, HB_USHORT uiBit )
{
return ( pArea->pRecord[ pArea->uiNullOffset + ( uiBit >> 3 ) ] &
( 1 << ( uiBit & 0x07 ) ) ) != 0;
}
static void hb_dbfSetNullFlag( HB_BYTE * pRecord, HB_USHORT uiNullOffset, HB_USHORT uiBit )
{
pRecord[ uiNullOffset + ( uiBit >> 3 ) ] |= 1 << ( uiBit & 0x07 );
}
static void hb_dbfClearNullFlag( HB_BYTE * pRecord, HB_USHORT uiNullOffset, HB_USHORT uiBit )
{
pRecord[ uiNullOffset + ( uiBit >> 3 ) ] &= ~( 1 << ( uiBit & 0x07 ) );
}
/*
* Executes user trigger function
*/
static HB_BOOL hb_dbfTriggerDo( DBFAREAP pArea, int iEvent,
int iField, PHB_ITEM pItem )
{
HB_BOOL fResult = HB_TRUE;
HB_TRACE( HB_TR_DEBUG, ( "hb_dbfTriggerDo(%p,%d,%d,%p)", pArea, iEvent, iField, pItem ) );
if( hb_vmRequestQuery() == 0 )
{
if( hb_vmRequestReenter() )
{
hb_vmPushDynSym( pArea->pTriggerSym );
hb_vmPushNil();
/* nEvent */
hb_vmPushInteger( iEvent );
/* nArea */
hb_vmPushInteger( pArea->area.uiArea );
/* nFieldPos (GET/PUT) */
hb_vmPushInteger( iField );
/* xTrigVal (PREUSE/GET/PUT) */
if( pItem )
{
#ifdef HB_TRIGVAR_BYREF
hb_vmPushItemRef( pItem );
#else
hb_vmPush( pItem );
#endif
hb_vmProc( 4 );
}
else
{
/* SIx3 makes: hb_vmPushInteger( 0 ); */
hb_vmProc( 3 );
}
fResult = hb_parl( -1 );
hb_vmRequestRestore();
}
}
return fResult;
}
/*
* Set user trigger function
*/
static void hb_dbfTriggerSet( DBFAREAP pArea, PHB_ITEM pTrigger )
{
const char * szName;
HB_TRACE( HB_TR_DEBUG, ( "hb_dbfTriggerSet(%p,%p)", pArea, pTrigger ) );
szName = hb_itemGetCPtr( pTrigger );
pArea->pTriggerSym = *szName ? hb_dynsymFindName( szName ) : NULL;
if( pArea->pTriggerSym && ! hb_dynsymIsFunction( pArea->pTriggerSym ) )
pArea->pTriggerSym = NULL;
pArea->fTrigger = pArea->pTriggerSym != NULL;
}
/*
* Return the total number of records.
*/
static HB_ULONG hb_dbfCalcRecCount( DBFAREAP pArea )
{
HB_TRACE( HB_TR_DEBUG, ( "hb_dbfCalcRecCount(%p)", pArea ) );
if( ! pArea->pDataFile )
return 0;
else
return ( HB_ULONG ) ( ( hb_fileSize( pArea->pDataFile ) -
pArea->uiHeaderLen ) / pArea->uiRecordLen );
}
/*
* Read current record from file.
*/
static HB_BOOL hb_dbfReadRecord( DBFAREAP pArea )
{
HB_TRACE( HB_TR_DEBUG, ( "hb_dbfReadRecord(%p)", pArea ) );
if( ! pArea->pRecord )
return HB_FALSE;
if( ! pArea->fPositioned )
{
pArea->fValidBuffer = HB_TRUE;
return HB_TRUE;
}
if( pArea->ulRecNo > pArea->ulRecCount )
{
/* Update record count */
if( pArea->fShared )
pArea->ulRecCount = hb_dbfCalcRecCount( pArea );
if( pArea->ulRecNo > pArea->ulRecCount )
{
pArea->area.fEof = pArea->fValidBuffer = HB_TRUE;
return HB_TRUE;
}
}
/* Read data from file */
if( hb_fileReadAt( pArea->pDataFile, pArea->pRecord, pArea->uiRecordLen,
( HB_FOFFSET ) pArea->uiHeaderLen +
( HB_FOFFSET ) ( pArea->ulRecNo - 1 ) *
( HB_FOFFSET ) pArea->uiRecordLen ) !=
( HB_SIZE ) pArea->uiRecordLen )
{
hb_dbfErrorRT( pArea, EG_READ, EDBF_READ,
pArea->szDataFileName, hb_fsError(), 0, NULL );
return HB_FALSE;
}
if( SELF_GETREC( &pArea->area, NULL ) == HB_FAILURE )
return HB_FALSE;
/* Set flags */
pArea->fValidBuffer = pArea->fPositioned = HB_TRUE;
pArea->fDeleted = pArea->pRecord[ 0 ] == '*';
return HB_TRUE;
}
/*
* Write current record to file.
*/
static HB_BOOL hb_dbfWriteRecord( DBFAREAP pArea )
{
HB_TRACE( HB_TR_DEBUG, ( "hb_dbfWriteRecord(%p)", pArea ) );
if( SELF_PUTREC( &pArea->area, NULL ) == HB_FAILURE )
return HB_FALSE;
pArea->fRecordChanged = HB_FALSE;
pArea->fDataFlush = HB_TRUE;
return HB_TRUE;
}
/*
* Set encryption password
*/
static HB_BOOL hb_dbfPasswordSet( DBFAREAP pArea, PHB_ITEM pPasswd, HB_BOOL fRaw )
{
char pKeyBuffer[ 8 ];
HB_SIZE nLen;
HB_BOOL fKeySet = HB_FALSE, fSet;
HB_TRACE( HB_TR_DEBUG, ( "hb_dbfPasswordSet(%p,%p,%d)", pArea, pPasswd, fRaw ) );
nLen = hb_itemGetCLen( pPasswd );
fSet = ! pArea->fHasMemo && HB_IS_STRING( pPasswd ) && ( ! fRaw || nLen == 8 );
if( fSet )
{
if( nLen > 0 )
{
if( nLen < 8 )
{
memcpy( pKeyBuffer, hb_itemGetCPtr( pPasswd ), nLen );
memset( pKeyBuffer + nLen, '\0', 8 - nLen );
}
else
memcpy( pKeyBuffer, hb_itemGetCPtr( pPasswd ), 8 );
}
}
if( pArea->pCryptKey )
hb_itemPutCL( pPasswd, pArea->pCryptKey, 8 );
else
hb_itemClear( pPasswd );
if( fSet )
{
if( pArea->pRecord && pArea->fPositioned )
{
SELF_GOCOLD( &pArea->area );
pArea->fValidBuffer = HB_FALSE;
}
if( pArea->pCryptKey )
{
/* clean the memory with password key - though it's not
* a serious actions in such case ;-)
*/
memset( pArea->pCryptKey, '\0', 8 );
hb_xfree( pArea->pCryptKey );
pArea->pCryptKey = NULL;
}
if( nLen > 0 )
{
/* at this moment only one encryption method is used,
I'll add other later, [druzus] */
pArea->bCryptType = DB_CRYPT_SIX;
pArea->pCryptKey = ( char * ) hb_xgrab( 8 );
/* SIX encode the key with its own value before use */
if( ! fRaw )
hb_sxEnCrypt( pKeyBuffer, pArea->pCryptKey, pKeyBuffer, 8 );
else
memcpy( pArea->pCryptKey, pKeyBuffer, 8 );
fKeySet = HB_TRUE;
}
}
return fKeySet;
}
/*
* Encrypt/Decrypt table
*/
static void hb_dbfTableCrypt( DBFAREAP pArea, PHB_ITEM pPasswd, HB_BOOL fEncrypt )
{
HB_TRACE( HB_TR_DEBUG, ( "hb_dbfTableCrypt(%p,%p,%d)", pArea, pPasswd, fEncrypt ) );
if( ! pArea->fReadonly && ! pArea->fShared &&
fEncrypt ? ! pArea->fTableEncrypted && ! pArea->fHasMemo :
pArea->fTableEncrypted )
{
HB_ULONG ulRecords, ulRecNo;
if( SELF_RECCOUNT( &pArea->area, &ulRecords ) == HB_SUCCESS )
{
HB_ERRCODE errCode = HB_SUCCESS;
char * pOldCryptKey, * pNewCryptKey;
pOldCryptKey = pArea->pCryptKey;
pArea->pCryptKey = NULL;
hb_dbfPasswordSet( pArea, pPasswd, HB_FALSE );
pNewCryptKey = pArea->pCryptKey;
if( ! fEncrypt )
{
if( pNewCryptKey )
{
if( pOldCryptKey )
hb_xfree( pNewCryptKey );
else
pOldCryptKey = pNewCryptKey;
pNewCryptKey = NULL;
}
}
else if( ! pNewCryptKey )
pNewCryptKey = pOldCryptKey;
for( ulRecNo = 1; ulRecNo <= ulRecords; ++ulRecNo )
{
pArea->pCryptKey = pOldCryptKey;
errCode = SELF_GOTO( &pArea->area, ulRecNo );
if( errCode != HB_SUCCESS )
break;
if( ! hb_dbfReadRecord( pArea ) )
{
errCode = HB_FAILURE;
break;
}
pArea->pCryptKey = pNewCryptKey;
/* Buffer is hot? */
if( ! pArea->fRecordChanged )
{
errCode = SELF_GOHOT( &pArea->area );
if( errCode != HB_SUCCESS )
break;
}
/* Force record encryption/decryption */
pArea->fEncrypted = fEncrypt;
/* Save encrypted record */
errCode = SELF_GOCOLD( &pArea->area );
if( errCode != HB_SUCCESS )
break;
}
pArea->pCryptKey = pNewCryptKey;
if( pOldCryptKey && pOldCryptKey != pNewCryptKey )
hb_xfree( pOldCryptKey );
if( errCode == HB_SUCCESS )
{
pArea->fTableEncrypted = fEncrypt;
pArea->fUpdateHeader = HB_TRUE;
SELF_WRITEDBHEADER( &pArea->area );
}
}
}
}
/*
* Unlock all records.
*/
static HB_ERRCODE hb_dbfUnlockAllRecords( DBFAREAP pArea )
{
HB_ERRCODE errCode = HB_SUCCESS;
HB_TRACE( HB_TR_DEBUG, ( "hb_dbfUnlockAllRecords(%p)", pArea ) );
if( pArea->pLocksPos )
{
HB_ULONG ulCount;
errCode = SELF_GOCOLD( &pArea->area );
for( ulCount = 0; ulCount < pArea->ulNumLocksPos; ulCount++ )
SELF_RAWLOCK( &pArea->area, REC_UNLOCK, pArea->pLocksPos[ ulCount ] );
hb_xfree( pArea->pLocksPos );
pArea->pLocksPos = NULL;
}
pArea->ulNumLocksPos = 0;
return errCode;
}
/*
* Unlock a records.
*/
static HB_ERRCODE hb_dbfUnlockRecord( DBFAREAP pArea, HB_ULONG ulRecNo )
{
HB_ERRCODE errCode = HB_SUCCESS;
HB_ULONG ulCount, * pList;
HB_TRACE( HB_TR_DEBUG, ( "hb_dbfUnlockRecord(%p, %lu)", pArea, ulRecNo ) );
/* Search the locked record */
for( ulCount = 0; ulCount < pArea->ulNumLocksPos &&
pArea->pLocksPos[ ulCount ] != ulRecNo; ulCount++ ) {}
if( ulCount < pArea->ulNumLocksPos )
{
errCode = SELF_GOCOLD( &pArea->area );
SELF_RAWLOCK( &pArea->area, REC_UNLOCK, ulRecNo );
if( pArea->ulNumLocksPos == 1 ) /* Delete the list */
{
hb_xfree( pArea->pLocksPos );
pArea->pLocksPos = NULL;
pArea->ulNumLocksPos = 0;
}
else /* Resize the list */
{
pList = pArea->pLocksPos + ulCount;
memmove( pList, pList + 1, ( pArea->ulNumLocksPos - ulCount - 1 ) *
sizeof( HB_ULONG ) );
pArea->pLocksPos = ( HB_ULONG * ) hb_xrealloc( pArea->pLocksPos,
( pArea->ulNumLocksPos - 1 ) *
sizeof( HB_ULONG ) );
pArea->ulNumLocksPos--;
}
}
return errCode;
}
/*
* Lock a record.
*/
static HB_ERRCODE hb_dbfLockRecord( DBFAREAP pArea, HB_ULONG ulRecNo, HB_USHORT * pResult,
HB_BOOL bExclusive )
{
HB_TRACE( HB_TR_DEBUG, ( "hb_dbfLockRecord(%p, %lu, %p, %i)", pArea, ulRecNo,
pResult, ( int ) bExclusive ) );
if( pArea->lpdbPendingRel )
{
if( SELF_FORCEREL( &pArea->area ) != HB_SUCCESS )
return HB_FAILURE;
}
if( pArea->fFLocked )
{
*pResult = HB_TRUE;
return HB_SUCCESS;
}
if( ulRecNo == 0 )
ulRecNo = pArea->ulRecNo;
if( bExclusive )
{
hb_dbfUnlockAllRecords( pArea );
}
else if( pArea->ulNumLocksPos > 0 )
{
HB_ULONG ul;
for( ul = 0; ul < pArea->ulNumLocksPos; ul++ )
{
if( pArea->pLocksPos[ ul ] == ulRecNo )
{
*pResult = HB_TRUE;
return HB_SUCCESS;
}
}
}
if( SELF_RAWLOCK( &pArea->area, REC_LOCK, ulRecNo ) == HB_SUCCESS )
{
if( pArea->ulNumLocksPos == 0 ) /* Create the list */
{
pArea->pLocksPos = ( HB_ULONG * ) hb_xgrab( sizeof( HB_ULONG ) );
}
else /* Resize the list */
{
pArea->pLocksPos = ( HB_ULONG * ) hb_xrealloc( pArea->pLocksPos,
( pArea->ulNumLocksPos + 1 ) *
sizeof( HB_ULONG ) );
}
pArea->pLocksPos[ pArea->ulNumLocksPos++ ] = ulRecNo;
*pResult = HB_TRUE;
if( ulRecNo == pArea->ulRecNo )
{
if( ! pArea->fPositioned )
{
if( SELF_GOTO( &pArea->area, pArea->ulRecNo ) != HB_SUCCESS )
return HB_FAILURE;
}
else if( ! pArea->fRecordChanged )
{
if( SELF_GOCOLD( &pArea->area ) != HB_SUCCESS )
return HB_FAILURE;
pArea->fValidBuffer = HB_FALSE;
}
}
}
else
*pResult = HB_FALSE;
return HB_SUCCESS;
}
/*
* Lock a file.
*/
static HB_ERRCODE hb_dbfLockFile( DBFAREAP pArea, HB_USHORT * pResult )
{
HB_TRACE( HB_TR_DEBUG, ( "hb_dbfLockFile(%p, %p)", pArea, pResult ) );
if( ! pArea->fFLocked )
{
if( pArea->lpdbPendingRel )
{
if( SELF_FORCEREL( &pArea->area ) != HB_SUCCESS )
return HB_FAILURE;
}
hb_dbfUnlockAllRecords( pArea );
SELF_RAWLOCK( &pArea->area, FILE_LOCK, 0 );
*pResult = ( HB_USHORT ) pArea->fFLocked;
if( ! pArea->fPositioned )
{
SELF_GOTO( &pArea->area, pArea->ulRecNo );
}
else if( ! pArea->fRecordChanged )
{
SELF_GOCOLD( &pArea->area );
pArea->fValidBuffer = HB_FALSE;
}
}
else
*pResult = HB_TRUE;
return HB_SUCCESS;
}
/*
* Unlock a file.
*/
static HB_ERRCODE hb_dbfUnlockFile( DBFAREAP pArea )
{
HB_ERRCODE errCode = HB_SUCCESS;
HB_TRACE( HB_TR_DEBUG, ( "hb_dbfUnlockFile(%p)", pArea ) );
if( pArea->fFLocked )
{
errCode = SELF_GOCOLD( &pArea->area );
SELF_RAWLOCK( &pArea->area, FILE_UNLOCK, 0 );
}
return errCode;
}
/*
* Test if a record is locked.
*/
static HB_BOOL hb_dbfIsLocked( DBFAREAP pArea, HB_ULONG ulRecNo )
{
HB_ULONG ulCount;
HB_TRACE( HB_TR_DEBUG, ( "hb_dbfIsLocked(%p)", pArea ) );
ulCount = pArea->ulNumLocksPos;
while( ulCount > 0 )
{
if( pArea->pLocksPos[ ulCount - 1 ] == ulRecNo )
return HB_TRUE;
ulCount--;
}
return HB_FALSE;
}
/*
* Return an array filled all locked records.
*/
static void hb_dbfGetLockArray( DBFAREAP pArea, PHB_ITEM pItem )
{
HB_ULONG ulCount;
HB_TRACE( HB_TR_DEBUG, ( "hb_dbfGetLockArray(%p, %p)", pArea, pItem ) );
hb_arrayNew( pItem, pArea->ulNumLocksPos );
for( ulCount = 0; ulCount < pArea->ulNumLocksPos; ulCount++ )
{
hb_arraySetNInt( pItem, ulCount + 1, pArea->pLocksPos[ ulCount ] );
}
}
/*
* Converts EDBF_* error code into EG_* one.
* This function is common for different DBF based RDD implementation
* so I don't make it static
*/
HB_ERRCODE hb_dbfGetEGcode( HB_ERRCODE errCode )
{
HB_ERRCODE errEGcode;
HB_TRACE( HB_TR_DEBUG, ( "hb_dbfGetEGcode(%u)", errCode ) );
switch( errCode )
{
case EDBF_OPEN_DBF:
errEGcode = EG_OPEN;
break;
case EDBF_CREATE_DBF:
errEGcode = EG_CREATE;
break;
case EDBF_READ:
errEGcode = EG_READ;
break;
case EDBF_WRITE:
errEGcode = EG_WRITE;
break;
case EDBF_CORRUPT:
errEGcode = EG_CORRUPTION;
break;
case EDBF_DATATYPE:
errEGcode = EG_DATATYPE;
break;
case EDBF_DATAWIDTH:
errEGcode = EG_DATAWIDTH;
break;
case EDBF_UNLOCKED:
errEGcode = EG_UNLOCKED;
break;
case EDBF_SHARED:
errEGcode = EG_SHARED;
break;
case EDBF_APPENDLOCK:
errEGcode = EG_APPENDLOCK;
break;
case EDBF_READONLY:
errEGcode = EG_READONLY;
break;
case EDBF_LOCK:
errEGcode = EG_LOCK;
break;
case EDBF_INVALIDKEY:
default:
errEGcode = EG_UNSUPPORTED;
break;
}
return errEGcode;
}
/*
* Converts memo block offset into ASCII.
* This function is common for different MEMO implementation
* so I left it in DBF.
*/
HB_ULONG hb_dbfGetMemoBlock( DBFAREAP pArea, HB_USHORT uiIndex )
{
HB_ULONG ulBlock = 0;
HB_TRACE( HB_TR_DEBUG, ( "hb_dbfGetMemoBlock(%p, %hu)", pArea, uiIndex ) );
if( pArea->area.lpFields[ uiIndex ].uiLen == 4 )
{
ulBlock = HB_GET_LE_UINT32( &pArea->pRecord[ pArea->pFieldOffset[ uiIndex ] ] );
}
else
{
HB_USHORT uiCount;
HB_BYTE bByte;
for( uiCount = 0; uiCount < 10; uiCount++ )
{
bByte = pArea->pRecord[ pArea->pFieldOffset[ uiIndex ] + uiCount ];
if( bByte >= '0' && bByte <= '9' )
{
ulBlock = ulBlock * 10 + ( bByte - '0' );
}
}
}
return ulBlock;
}
/*
* Converts ASCII data into memo block offset.
* This function is common for different MEMO implementation
* so I left it in DBF.
*/
void hb_dbfPutMemoBlock( DBFAREAP pArea, HB_USHORT uiIndex, HB_ULONG ulBlock )
{
HB_TRACE( HB_TR_DEBUG, ( "hb_dbfPutMemoBlock(%p, %hu, %lu)", pArea, uiIndex, ulBlock ) );
if( pArea->area.lpFields[ uiIndex ].uiLen == 4 )
{
HB_PUT_LE_UINT32( &pArea->pRecord[ pArea->pFieldOffset[ uiIndex ] ], ulBlock );
}
else
{
HB_SHORT iCount;
for( iCount = 9; iCount >= 0; iCount-- )
{
if( ulBlock > 0 )
{
pArea->pRecord[ pArea->pFieldOffset[ uiIndex ] + iCount ] = ( HB_BYTE ) ( ulBlock % 10 ) + '0';
ulBlock /= 10;
}
else
{
pArea->pRecord[ pArea->pFieldOffset[ uiIndex ] + iCount ] = ' ';
}
}
}
}
/*
* Retrive memo field information stored in DBF file
* This function is common for different MEMO implementation
* so I left it in DBF.
*/
HB_ERRCODE hb_dbfGetMemoData( DBFAREAP pArea, HB_USHORT uiIndex,
HB_ULONG * pulBlock, HB_ULONG * pulSize,
HB_ULONG * pulType )
{
HB_TRACE( HB_TR_DEBUG, ( "hb_dbfGetMemoData(%p, %hu, %p, %p, %p)", pArea, uiIndex, pulBlock, pulSize, pulType ) );
*pulBlock = *pulSize = *pulType = 0;
if( uiIndex >= pArea->area.uiFieldCount ||
( pArea->area.lpFields[ uiIndex ].uiType != HB_FT_MEMO &&
pArea->area.lpFields[ uiIndex ].uiType != HB_FT_IMAGE &&
pArea->area.lpFields[ uiIndex ].uiType != HB_FT_BLOB &&
pArea->area.lpFields[ uiIndex ].uiType != HB_FT_OLE ) )
return HB_FAILURE;
if( pArea->area.lpFields[ uiIndex ].uiLen == 4 )
{
*pulBlock = HB_GET_LE_UINT32( &pArea->pRecord[ pArea->pFieldOffset[ uiIndex ] ] );
return HB_SUCCESS;
}
else if( pArea->area.lpFields[ uiIndex ].uiLen == 10 )
{
HB_ULONG ulValue;
if( pArea->bMemoType == DB_MEMO_SMT )
{
LPSMTFIELD pSMTFiled = ( LPSMTFIELD ) &pArea->pRecord[ pArea->pFieldOffset[ uiIndex ] ];
ulValue = HB_GET_LE_UINT16( pSMTFiled->type );
if( ulValue != 0x2020 )
{
*pulType = ulValue;
*pulSize = HB_GET_LE_UINT32( pSMTFiled->length );
*pulBlock = HB_GET_LE_UINT32( pSMTFiled->block );
}
}
/*
* check for NULL fields created by Access, they have Chr(0) set
* in the whole memo block address, [druzus]
*/
else if( pArea->pRecord[ pArea->pFieldOffset[ uiIndex ] ] != 0 )
{
HB_USHORT uiCount;
HB_BYTE bByte;
ulValue = 0;
for( uiCount = 0; uiCount < 10; uiCount++ )
{
bByte = pArea->pRecord[ pArea->pFieldOffset[ uiIndex ] + uiCount ];
if( bByte >= '0' && bByte <= '9' )
ulValue = ulValue * 10 + ( bByte - '0' );
else if( bByte != ' ' || ulValue )
return hb_dbfErrorRT( pArea, EG_CORRUPTION, EDBF_CORRUPT,
pArea->szDataFileName, 0,
EF_CANDEFAULT, NULL ) == E_DEFAULT ?
HB_SUCCESS : HB_FAILURE;
}
*pulBlock = ulValue;
}
return HB_SUCCESS;
}
return HB_FAILURE;
}
/*
* Write memo data information into memo field in DBF file
* This function is common for different MEMO implementation
* so I left it in DBF.
*/
HB_ERRCODE hb_dbfSetMemoData( DBFAREAP pArea, HB_USHORT uiIndex,
HB_ULONG ulBlock, HB_ULONG ulSize,
HB_ULONG ulType )
{
HB_TRACE( HB_TR_DEBUG, ( "hb_dbfSetMemoData(%p, %hu, %lu, %lu, %lu)", pArea, uiIndex, ulBlock, ulSize, ulType ) );
if( uiIndex >= pArea->area.uiFieldCount ||
( pArea->area.lpFields[ uiIndex ].uiType != HB_FT_MEMO &&
pArea->area.lpFields[ uiIndex ].uiType != HB_FT_IMAGE &&
pArea->area.lpFields[ uiIndex ].uiType != HB_FT_BLOB &&
pArea->area.lpFields[ uiIndex ].uiType != HB_FT_OLE ) )
return HB_FAILURE;
if( pArea->area.lpFields[ uiIndex ].uiLen == 4 )
{
HB_PUT_LE_UINT32( &pArea->pRecord[ pArea->pFieldOffset[ uiIndex ] ], ulBlock );
return HB_SUCCESS;
}
else if( pArea->area.lpFields[ uiIndex ].uiLen == 10 )
{
if( pArea->bMemoType == DB_MEMO_SMT )
{
LPSMTFIELD pSMTFiled = ( LPSMTFIELD ) &pArea->pRecord[ pArea->pFieldOffset[ uiIndex ] ];
HB_PUT_LE_UINT16( pSMTFiled->type, ulType );
HB_PUT_LE_UINT32( pSMTFiled->length, ulSize );
HB_PUT_LE_UINT32( pSMTFiled->block, ulBlock );
}
else
{
HB_SHORT iCount;
for( iCount = 9; iCount >= 0; iCount-- )
{
if( ulBlock > 0 )
{
pArea->pRecord[ pArea->pFieldOffset[ uiIndex ] + iCount ] = ( HB_BYTE )( ulBlock % 10 ) + '0';
ulBlock /= 10;
}
else
{
pArea->pRecord[ pArea->pFieldOffset[ uiIndex ] + iCount ] = ' ';
}
}
}
return HB_SUCCESS;
}
return HB_FAILURE;
}
/*
* Get information about locking schemes for additional files (MEMO, INDEX)
* This function is common for different MEMO implementation
* so I left it in DBF.
*/
HB_BOOL hb_dbfLockIdxGetData( HB_BYTE bScheme, PHB_DBFLOCKDATA pLockData )
{
pLockData->next = pLockData->tolock = 0;
pLockData->type = 0;
switch( bScheme )
{
case DB_DBFLOCK_CLIPPER:
pLockData->offset = IDX_LOCKPOS_CLIPPER;
pLockData->size = IDX_LOCKPOOL_CLIPPER;
break;
case DB_DBFLOCK_CLIPPER2:
pLockData->offset = IDX_LOCKPOS_CLIPPER2;
pLockData->size = IDX_LOCKPOOL_CLIPPER2;
break;
case DB_DBFLOCK_COMIX:
pLockData->offset = IDX_LOCKPOS_COMIX;
pLockData->size = IDX_LOCKPOOL_COMIX;
break;
case DB_DBFLOCK_VFP:
pLockData->offset = IDX_LOCKPOS_VFP;
pLockData->size = IDX_LOCKPOOL_VFP;
break;
case DB_DBFLOCK_HB32:
pLockData->offset = IDX_LOCKPOS_HB32;
pLockData->size = IDX_LOCKPOOL_HB32;
break;
#ifndef HB_LONG_LONG_OFF
case DB_DBFLOCK_HB64:
pLockData->offset = IDX_LOCKPOS_HB64;
pLockData->size = IDX_LOCKPOOL_HB64;
break;
#endif
default:
pLockData->offset = pLockData->size = 0;
return HB_FALSE;
}
return HB_TRUE;
}
static HB_BOOL hb_dbfLockIdxRepeatFail( DBFAREAP pArea, PHB_DBFLOCKDATA pLockData )
{
HB_SYMBOL_UNUSED( pArea );
HB_SYMBOL_UNUSED( pLockData );
/* TODO: call special error handler (LOCKHANDLER) here */
return HB_TRUE;
}
/*
* Set lock using current locking schemes in additional files (MEMO, INDEX)
* This function is common for different MEMO implementation
* so I left it in DBF.
*/
HB_BOOL hb_dbfLockIdxFile( DBFAREAP pArea, PHB_FILE pFile,
int iType, HB_BOOL fLateWrlck,
PHB_DBFLOCKDATA pLockData )
{
HB_FOFFSET offset, size, tolock;
HB_BOOL fOK;
switch( iType & FL_MASK )
{
case FL_LOCK:
if( ! hb_dbfLockIdxGetData( pArea->bLockType, pLockData ) )
return HB_FALSE;
if( pLockData->size && ( iType & FLX_SHARED ) != 0 )
{
if( ++pLockData->count >= 16 )
{
pLockData->size = 0;
pLockData->count = 0;
iType &= ~FLX_SHARED;
}
}
else
pLockData->count = 0;
tolock = 0;
for( ;; )
{
size = 1;
offset = pLockData->offset;
if( pLockData->count != 0 )
offset += ( HB_FOFFSET ) ( hb_random_num() * pLockData->size ) + 1;
else if( pLockData->size != 0 )
size = pLockData->size + 1;
if( hb_fileLock( pFile, offset, size,
size > 1 ? iType & ~FLX_WAIT : iType ) )
{
pLockData->offset = offset;
pLockData->size = size;
pLockData->tolock = tolock;
pLockData->type = iType;
if( ! fLateWrlck && tolock != 0 )
{
if( ! hb_dbfLockIdxWrite( pArea, pFile, pLockData ) )
{
hb_fileLock( pFile, offset, size, FL_UNLOCK );
break;
}
}
return HB_TRUE;
}
if( ( iType & FLX_WAIT ) == 0 )
break;
else if( size > 1 )
{
tolock = size - 1;
pLockData->size = 0;
}
else if( ! hb_dbfLockIdxRepeatFail( pArea, pLockData ) )
break;
else
hb_releaseCPU();
}
pLockData->offset = pLockData->size =
pLockData->next = pLockData->tolock = 0;
pLockData->type = 0;
break;
case FL_UNLOCK:
fOK = hb_fileLock( pFile, pLockData->offset, pLockData->size, iType );
if( pLockData->next )
{
if( ! hb_fileLock( pFile, pLockData->offset + pLockData->size,
pLockData->next, iType ) )
fOK = HB_FALSE;
}
if( fOK )
{
pLockData->offset = pLockData->size =
pLockData->next = pLockData->tolock = 0;
pLockData->type = 0;
return HB_TRUE;
}
}
return HB_FALSE;
}
HB_BOOL hb_dbfLockIdxWrite( DBFAREAP pArea, PHB_FILE pFile,
PHB_DBFLOCKDATA pLockData )
{
if( pLockData->tolock )
{
/* FL_LOCK | FLX_EXCLUSIVE | FLX_WAIT */
while( ! hb_fileLock( pFile, pLockData->offset + pLockData->size,
pLockData->tolock, pLockData->type ) )
{
if( ! hb_dbfLockIdxRepeatFail( pArea, pLockData ) )
return HB_FALSE;
hb_releaseCPU();
}
pLockData->next = pLockData->tolock;
pLockData->tolock = 0;
}
return HB_TRUE;
}
/*
* Get DBF locking parameters
*/
static HB_ERRCODE hb_dbfLockData( DBFAREAP pArea,
HB_FOFFSET * pnPos, HB_FOFFSET * pnFlSize,
HB_FOFFSET * pnRlSize, int * iDir )
{
switch( pArea->bLockType )
{
case DB_DBFLOCK_CLIPPER:
*pnPos = DBF_LOCKPOS_CLIPPER;
*iDir = DBF_LOCKDIR_CLIPPER;
*pnFlSize = DBF_FLCKSIZE_CLIPPER;
*pnRlSize = DBF_RLCKSIZE_CLIPPER;
break;
case DB_DBFLOCK_CLIPPER2:
*pnPos = DBF_LOCKPOS_CLIPPER2;
*iDir = DBF_LOCKDIR_CLIPPER2;
*pnFlSize = DBF_FLCKSIZE_CLIPPER2;
*pnRlSize = DBF_RLCKSIZE_CLIPPER2;
break;
case DB_DBFLOCK_COMIX:
*pnPos = DBF_LOCKPOS_COMIX;
*iDir = DBF_LOCKDIR_COMIX;
*pnFlSize = DBF_FLCKSIZE_COMIX;
*pnRlSize = DBF_RLCKSIZE_COMIX;
break;
case DB_DBFLOCK_VFP:
if( pArea->fHasTags )
{
*pnPos = DBF_LOCKPOS_VFPX;
*iDir = DBF_LOCKDIR_VFPX;
*pnFlSize = DBF_FLCKSIZE_VFPX;
*pnRlSize = DBF_RLCKSIZE_VFPX;
}
else
{
*pnPos = DBF_LOCKPOS_VFP;
*iDir = DBF_LOCKDIR_VFP;
*pnFlSize = DBF_FLCKSIZE_VFP;
*pnRlSize = DBF_RLCKSIZE_VFP;
}
break;
case DB_DBFLOCK_HB32:
*pnPos = DBF_LOCKPOS_HB32;
*iDir = DBF_LOCKDIR_HB32;
*pnFlSize = DBF_FLCKSIZE_HB32;
*pnRlSize = DBF_RLCKSIZE_HB32;
break;
#ifndef HB_LONG_LONG_OFF
case DB_DBFLOCK_HB64:
*pnPos = DBF_LOCKPOS_HB64;
*iDir = DBF_LOCKDIR_HB64;
*pnFlSize = DBF_FLCKSIZE_HB64;
*pnRlSize = DBF_RLCKSIZE_HB64;
break;
#endif
default:
*pnPos = *pnFlSize = *pnRlSize = 0;
*iDir = 0;
return HB_FAILURE;
}
return HB_SUCCESS;
}
static int hb_dbfLockTest( DBFAREAP pArea, HB_USHORT uiAction, HB_ULONG ulRecNo )
{
int iResult = -1;
HB_TRACE( HB_TR_DEBUG, ( "hb_dbfLockTest(%p, %hu, %lu)", pArea, uiAction, ulRecNo ) );
if( ! pArea->fShared || pArea->fFLocked ||
( uiAction == REC_LOCK && hb_dbfIsLocked( pArea, ulRecNo ) ) )
iResult = 0;
else
{
HB_FOFFSET nPos, nFlSize, nRlSize;
int iDir;
if( hb_dbfLockData( pArea, &nPos, &nFlSize, &nRlSize, &iDir ) == HB_SUCCESS )
{
switch( uiAction )
{
case FILE_LOCK:
if( iDir < 0 )
nPos -= nFlSize;
else
nPos++;
iResult = hb_fileLockTest( pArea->pDataFile, nPos, nFlSize, FL_LOCK );
break;
case REC_LOCK:
if( iDir < 0 )
nPos -= ulRecNo;
else if( iDir == 2 )
nPos += ( ulRecNo - 1 ) * pArea->uiRecordLen + pArea->uiHeaderLen;
else
nPos += ulRecNo;
iResult = hb_fileLockTest( pArea->pDataFile, nPos, nRlSize, FL_LOCK );
break;
}
}
}
return iResult;
}
/*
* -- DBF METHODS --
*/
/*
* Determine logical beginning of file.
*/
static HB_ERRCODE hb_dbfBof( DBFAREAP pArea, HB_BOOL * pBof )
{
HB_TRACE( HB_TR_DEBUG, ( "hb_dbfBof(%p, %p)", pArea, pBof ) );
if( pArea->lpdbPendingRel )
{
if( SELF_FORCEREL( &pArea->area ) != HB_SUCCESS )
return HB_FAILURE;
}
*pBof = pArea->area.fBof;
return HB_SUCCESS;
}
/*
* Determine logical end of file.
*/
static HB_ERRCODE hb_dbfEof( DBFAREAP pArea, HB_BOOL * pEof )
{
HB_TRACE( HB_TR_DEBUG, ( "hb_dbfEof(%p, %p)", pArea, pEof ) );
if( pArea->lpdbPendingRel )
{
if( SELF_FORCEREL( &pArea->area ) != HB_SUCCESS )
return HB_FAILURE;
}
*pEof = pArea->area.fEof;
return HB_SUCCESS;
}
/*
* Determine outcome of the last search operation.
*/
static HB_ERRCODE hb_dbfFound( DBFAREAP pArea, HB_BOOL * pFound )
{
HB_TRACE( HB_TR_DEBUG, ( "hb_dbfFound(%p, %p)", pArea, pFound ) );
if( pArea->lpdbPendingRel )
{
if( SELF_FORCEREL( &pArea->area ) != HB_SUCCESS )
return HB_FAILURE;
}
*pFound = pArea->area.fFound;
return HB_SUCCESS;
}
/*
* Position cursor at the last record.
*/
static HB_ERRCODE hb_dbfGoBottom( DBFAREAP pArea )
{
HB_TRACE( HB_TR_DEBUG, ( "hb_dbfGoBottom(%p)", pArea ) );
if( SELF_GOCOLD( &pArea->area ) == HB_FAILURE )
return HB_FAILURE;
/* Update record count */
if( pArea->fShared )
pArea->ulRecCount = hb_dbfCalcRecCount( pArea );
pArea->area.fTop = HB_FALSE;
pArea->area.fBottom = HB_TRUE;
if( SELF_GOTO( &pArea->area, pArea->ulRecCount ) != HB_SUCCESS )
return HB_FAILURE;
return SELF_SKIPFILTER( &pArea->area, -1 );
}
/*
* Position cursor at a specific physical record.
*/
static HB_ERRCODE hb_dbfGoTo( DBFAREAP pArea, HB_ULONG ulRecNo )
{
HB_TRACE( HB_TR_DEBUG, ( "hb_dbfGoTo(%p, %lu)", pArea, ulRecNo ) );
if( SELF_GOCOLD( &pArea->area ) == HB_FAILURE )
return HB_FAILURE;
if( pArea->lpdbPendingRel )
{
if( pArea->lpdbPendingRel->isScoped )
{
if( SELF_FORCEREL( &pArea->area ) != HB_SUCCESS )
return HB_FAILURE;
}
else /* Reset parent rel struct */
pArea->lpdbPendingRel = NULL;
}
/* Update record count */
if( ulRecNo > pArea->ulRecCount && pArea->fShared )
pArea->ulRecCount = hb_dbfCalcRecCount( pArea );
if( ulRecNo <= pArea->ulRecCount && ulRecNo >= 1 )
{
pArea->ulRecNo = ulRecNo;
pArea->area.fBof = pArea->area.fEof = pArea->fValidBuffer = HB_FALSE;
pArea->fPositioned = HB_TRUE;
}
else /* Out of space */
{
pArea->ulRecNo = pArea->ulRecCount + 1;
pArea->area.fBof = pArea->area.fEof = pArea->fValidBuffer = HB_TRUE;
pArea->fPositioned = pArea->fDeleted = pArea->fEncrypted = HB_FALSE;
/* Clear record buffer */
hb_dbfSetBlankRecord( pArea, HB_BLANK_EOF );
}
pArea->area.fFound = HB_FALSE;
/* Force relational movement in child WorkAreas */
if( pArea->area.lpdbRelations )
return SELF_SYNCCHILDREN( &pArea->area );
else
return HB_SUCCESS;
}
/*
* Position the cursor to a specific, physical identity.
*/
static HB_ERRCODE hb_dbfGoToId( DBFAREAP pArea, PHB_ITEM pItem )
{
HB_TRACE( HB_TR_DEBUG, ( "hb_dbfGoToId(%p, %p)", pArea, pItem ) );
if( HB_IS_NUMERIC( pItem ) )
return SELF_GOTO( &pArea->area, hb_itemGetNL( pItem ) );
else
{
hb_dbfErrorRT( pArea, EG_DATATYPE, EDBF_DATATYPE, NULL, 0, 0, NULL );
return HB_FAILURE;
}
}
/*
* Position cursor at the first record.
*/
static HB_ERRCODE hb_dbfGoTop( DBFAREAP pArea )
{
HB_TRACE( HB_TR_DEBUG, ( "hb_dbfGoTop(%p)", pArea ) );
pArea->area.fTop = HB_TRUE;
pArea->area.fBottom = HB_FALSE;
if( SELF_GOTO( &pArea->area, 1 ) == HB_FAILURE )
return HB_FAILURE;
return SELF_SKIPFILTER( &pArea->area, 1 );
}
#define hb_dbfSeek NULL
/*
* Reposition cursor relative to current position.
*/
static HB_ERRCODE hb_dbfSkip( DBFAREAP pArea, HB_LONG lToSkip )
{
HB_ERRCODE errCode;
HB_TRACE( HB_TR_DEBUG, ( "hb_dbfSkip(%p, %ld)", pArea, lToSkip ) );
if( pArea->lpdbPendingRel )
{
if( SELF_FORCEREL( &pArea->area ) != HB_SUCCESS )
return HB_FAILURE;
}
pArea->area.fTop = pArea->area.fBottom = HB_FALSE;
if( lToSkip == 0 || pArea->area.dbfi.itmCobExpr || pArea->area.dbfi.fFilter ||
hb_setGetDeleted() )
return SUPER_SKIP( &pArea->area, lToSkip );
errCode = SELF_SKIPRAW( &pArea->area, lToSkip );
/* TODO: remove this hack - it's not necessary if SKIPRAW works
as it should, Druzus */
/* Move first record and set Bof flag */
if( errCode == HB_SUCCESS && pArea->area.fBof && lToSkip < 0 )
{
errCode = SELF_GOTOP( &pArea->area );
pArea->area.fBof = HB_TRUE;
}
/* Update Bof and Eof flags */
if( lToSkip < 0 )
pArea->area.fEof = HB_FALSE;
else /* if( lToSkip > 0 ) */
pArea->area.fBof = HB_FALSE;
return errCode;
}
#define hb_dbfSkipFilter NULL
/*
* Reposition cursor, regardless of filter.
*/
static HB_ERRCODE hb_dbfSkipRaw( DBFAREAP pArea, HB_LONG lToSkip )
{
HB_ERRCODE errCode;
HB_TRACE( HB_TR_DEBUG, ( "hb_dbfSkipRaw(%p, %ld)", pArea, lToSkip ) );
if( pArea->lpdbPendingRel )
{
if( SELF_FORCEREL( &pArea->area ) != HB_SUCCESS )
return HB_FAILURE;
}
if( lToSkip == 0 )
{
HB_BOOL bBof, bEof;
/* Save flags */
bBof = pArea->area.fBof;
bEof = pArea->area.fEof;
errCode = SELF_GOTO( &pArea->area, pArea->ulRecNo );
/* Restore flags */
pArea->area.fBof = bBof;
pArea->area.fEof = bEof;
}
else if( lToSkip < 0 && ( HB_ULONG ) ( -lToSkip ) >= pArea->ulRecNo )
{
errCode = SELF_GOTO( &pArea->area, 1 );
pArea->area.fBof = HB_TRUE;
}
else
{
errCode = SELF_GOTO( &pArea->area, pArea->ulRecNo + lToSkip );
}
return errCode;
}
/*
* Add a field to the WorkArea.
*/
static HB_ERRCODE hb_dbfAddField( DBFAREAP pArea, LPDBFIELDINFO pFieldInfo )
{
HB_TRACE( HB_TR_DEBUG, ( "hb_dbfAddField(%p, %p)", pArea, pFieldInfo ) );
switch( pFieldInfo->uiType )
{
case HB_FT_IMAGE:
case HB_FT_BLOB:
case HB_FT_OLE:
pFieldInfo->uiFlags |= HB_FF_BINARY;
/* no break */
case HB_FT_MEMO:
if( pArea->bMemoType == DB_MEMO_SMT )
pFieldInfo->uiLen = 10;
break;
}
/* Update field offset */
pArea->pFieldOffset[ pArea->area.uiFieldCount ] = pArea->uiRecordLen;
pArea->uiRecordLen += pFieldInfo->uiLen;
if( ( pFieldInfo->uiFlags & HB_FF_UNICODE ) != 0 )
{
if( pFieldInfo->uiType == HB_FT_STRING )
pArea->uiRecordLen += pFieldInfo->uiLen;
else if( pFieldInfo->uiType == HB_FT_VARLENGTH )
pArea->uiRecordLen += pFieldInfo->uiLen + 2;
}
if( pArea->pFieldOffset[ pArea->area.uiFieldCount ] > pArea->uiRecordLen )
return HB_FAILURE;
else
return SUPER_ADDFIELD( &pArea->area, pFieldInfo );
}
/*
* Append a record to the WorkArea.
*/
static HB_ERRCODE hb_dbfAppend( DBFAREAP pArea, HB_BOOL bUnLockAll )
{
HB_ULONG ulNewRecord;
HB_USHORT fLocked;
HB_ERRCODE errCode;
HB_TRACE( HB_TR_DEBUG, ( "hb_dbfAppend(%p, %d)", pArea, ( int ) bUnLockAll ) );
if( SELF_GOCOLD( &pArea->area ) == HB_FAILURE )
return HB_FAILURE;
if( pArea->fTrigger )
{
if( ! hb_dbfTriggerDo( pArea, EVENT_APPEND, 0, NULL ) )
return HB_FAILURE;
}
if( pArea->fReadonly )
{
hb_dbfErrorRT( pArea, EG_READONLY, EDBF_READONLY, NULL, 0, 0, NULL );
return HB_FAILURE;
}
if( pArea->lpdbPendingRel )
{
if( pArea->lpdbPendingRel->isScoped )
{
if( SELF_FORCEREL( &pArea->area ) != HB_SUCCESS )
return HB_FAILURE;
}
else /* Reset parent rel struct */
pArea->lpdbPendingRel = NULL;
}
if( pArea->fShared )
{
fLocked = HB_FALSE;
if( SELF_RAWLOCK( &pArea->area, APPEND_LOCK, 0 ) == HB_SUCCESS )
{
/* Update RecCount */
pArea->ulRecCount = hb_dbfCalcRecCount( pArea );
ulNewRecord = pArea->ulRecCount + 1;
if( pArea->fFLocked || hb_dbfIsLocked( pArea, ulNewRecord ) )
fLocked = HB_TRUE;
else if( hb_dbfLockRecord( pArea, ulNewRecord, &fLocked, bUnLockAll ) != HB_SUCCESS )
{
if( fLocked )
hb_dbfUnlockRecord( pArea, ulNewRecord );
SELF_RAWLOCK( &pArea->area, APPEND_UNLOCK, 0 );
return HB_FAILURE;
}
}
if( ! fLocked )
{
SELF_RAWLOCK( &pArea->area, APPEND_UNLOCK, 0 );
hb_dbfErrorRT( pArea, EG_APPENDLOCK, EDBF_APPENDLOCK, NULL, 0,
EF_CANDEFAULT, NULL );
return HB_FAILURE;
}
}
/* Clear record buffer and update pArea */
hb_dbfSetBlankRecord( pArea, HB_BLANK_APPEND );
pArea->fValidBuffer = pArea->fUpdateHeader = pArea->fRecordChanged =
pArea->fAppend = pArea->fPositioned = HB_TRUE;
pArea->ulRecCount ++;
pArea->ulRecNo = pArea->ulRecCount;
pArea->fDeleted = pArea->area.fBof = pArea->area.fEof =
pArea->area.fFound = HB_FALSE;
pArea->fEncrypted = pArea->pCryptKey != NULL && ! pArea->fHasMemo;
if( pArea->fShared )
{
errCode = SELF_GOCOLD( &pArea->area );
SELF_RAWLOCK( &pArea->area, APPEND_UNLOCK, 0 );
return errCode;
}
return HB_SUCCESS;
}
#define hb_dbfCreateFields NULL
/*
* Delete a record.
*/
static HB_ERRCODE hb_dbfDeleteRec( DBFAREAP pArea )
{
HB_TRACE( HB_TR_DEBUG, ( "hb_dbfDeleteRec(%p)", pArea ) );
if( pArea->fTrigger )
{
if( ! hb_dbfTriggerDo( pArea, EVENT_DELETE, 0, NULL ) )
return HB_FAILURE;
}
if( pArea->lpdbPendingRel )
{
if( SELF_FORCEREL( &pArea->area ) != HB_SUCCESS )
return HB_FAILURE;
}
/* Read record */
if( ! pArea->fValidBuffer && ! hb_dbfReadRecord( pArea ) )
return HB_FAILURE;
if( ! pArea->fPositioned )
return HB_SUCCESS;
/* Buffer is hot? */
if( ! pArea->fRecordChanged && SELF_GOHOT( &pArea->area ) == HB_FAILURE )
return HB_FAILURE;
pArea->pRecord[ 0 ] = '*';
pArea->fDeleted = HB_TRUE;
return HB_SUCCESS;
}
/*
* Determine deleted status for a record.
*/
static HB_ERRCODE hb_dbfDeleted( DBFAREAP pArea, HB_BOOL * pDeleted )
{
HB_TRACE( HB_TR_DEBUG, ( "hb_dbfDeleted(%p, %p)", pArea, pDeleted ) );
if( pArea->lpdbPendingRel )
{
if( SELF_FORCEREL( &pArea->area ) != HB_SUCCESS )
return HB_FAILURE;
}
/* Read record */
if( ! pArea->fValidBuffer && ! hb_dbfReadRecord( pArea ) )
return HB_FAILURE;
*pDeleted = pArea->fDeleted;
return HB_SUCCESS;
}
#define hb_dbfFieldCount NULL
#define hb_dbfFieldDisplay NULL
#define hb_dbfFieldName NULL
/*
* Write data buffer to the data store.
*/
static HB_ERRCODE hb_dbfFlush( DBFAREAP pArea )
{
HB_ERRCODE errCode;
HB_TRACE( HB_TR_DEBUG, ( "hb_dbfFlush(%p)", pArea ) );
errCode = SELF_GOCOLD( &pArea->area );
if( errCode == HB_SUCCESS )
{
if( pArea->fUpdateHeader )
errCode = SELF_WRITEDBHEADER( &pArea->area );
}
if( hb_setGetHardCommit() && errCode == HB_SUCCESS )
{
if( pArea->fDataFlush )
{
hb_fileCommit( pArea->pDataFile );
pArea->fDataFlush = HB_FALSE;
}
if( pArea->fHasMemo && pArea->pMemoFile && pArea->fMemoFlush )
{
hb_fileCommit( pArea->pMemoFile );
pArea->fMemoFlush = HB_FALSE;
}
}
return errCode;
}
/*
* Retrieve current record buffer
*/
static HB_ERRCODE hb_dbfGetRec( DBFAREAP pArea, HB_BYTE ** pBuffer )
{
HB_TRACE( HB_TR_DEBUG, ( "hb_dbfGetRec(%p, %p)", pArea, pBuffer ) );
if( pBuffer != NULL )
{
/* Read record */
if( ! pArea->fValidBuffer && ! hb_dbfReadRecord( pArea ) )
return HB_FAILURE;
*pBuffer = pArea->pRecord;
}
else
{
if( pArea->pRecord[ 0 ] == 'D' || pArea->pRecord[ 0 ] == 'E' )
{
pArea->fEncrypted = HB_TRUE;
pArea->pRecord[ 0 ] = pArea->pRecord[ 0 ] == 'D' ? '*' : ' ';
if( pArea->pCryptKey && pArea->bCryptType == DB_CRYPT_SIX )
{
hb_sxDeCrypt( ( const char * ) pArea->pRecord + 1,
( char * ) pArea->pRecord + 1,
pArea->pCryptKey, pArea->uiRecordLen - 1 );
}
}
else
{
pArea->fEncrypted = HB_FALSE;
}
}
return HB_SUCCESS;
}
/*
* Obtain the current value of a field.
*/
static HB_ERRCODE hb_dbfGetValue( DBFAREAP pArea, HB_USHORT uiIndex, PHB_ITEM pItem )
{
LPFIELD pField;
PHB_ITEM pError;
HB_BOOL fError;
char * pszVal;
HB_SIZE nLen;
HB_MAXINT lVal;
double dVal;
HB_BOOL fDbl;
int iLen;
HB_TRACE( HB_TR_DEBUG, ( "hb_dbfGetValue(%p, %hu, %p)", pArea, uiIndex, pItem ) );
if( pArea->lpdbPendingRel )
{
if( SELF_FORCEREL( &pArea->area ) != HB_SUCCESS )
return HB_FAILURE;
}
if( --uiIndex >= pArea->area.uiFieldCount )
return HB_FAILURE;
/* Read record */
if( ! pArea->fValidBuffer && ! hb_dbfReadRecord( pArea ) )
return HB_FAILURE;
fError = HB_FALSE;
pField = pArea->area.lpFields + uiIndex;
switch( pField->uiType )
{
case HB_FT_STRING:
nLen = pField->uiLen;
if( ( pField->uiFlags & HB_FF_UNICODE ) != 0 )
{
hb_itemPutStrLenU16( pItem, HB_CDP_ENDIAN_LITTLE,
( const HB_WCHAR * ) &pArea->pRecord[ pArea->pFieldOffset[ uiIndex ] ],
nLen );
}
else if( ( pField->uiFlags & HB_FF_BINARY ) == 0 )
{
pszVal = hb_cdpnDup( ( const char * ) pArea->pRecord + pArea->pFieldOffset[ uiIndex ],
&nLen, pArea->area.cdPage, hb_vmCDP() );
hb_itemPutCLPtr( pItem, pszVal, nLen );
}
else
{
pszVal = ( char * ) pArea->pRecord + pArea->pFieldOffset[ uiIndex ];
hb_itemPutCL( pItem, pszVal, nLen );
}
break;
case HB_FT_VARLENGTH:
nLen = pField->uiLen;
if( ( pField->uiFlags & HB_FF_UNICODE ) != 0 )
{
nLen = HB_GET_LE_UINT16( &pArea->pRecord[ pArea->pFieldOffset[ uiIndex ] + ( nLen << 1 ) ] );
if( nLen == 0xFFFF )
nLen = 0;
hb_itemPutStrLenU16( pItem, HB_CDP_ENDIAN_LITTLE,
( const HB_WCHAR * ) &pArea->pRecord[ pArea->pFieldOffset[ uiIndex ] ],
nLen );
}
else
{
if( hb_dbfGetNullFlag( pArea, pArea->pFieldBits[ uiIndex ].uiLengthBit ) )
{
nLen = ( HB_UCHAR ) pArea->pRecord[ pArea->pFieldOffset[ uiIndex ] + nLen - 1 ];
/* protection against corrupted files */
if( nLen > ( HB_SIZE ) pField->uiLen )
nLen = pField->uiLen;
}
if( ( pField->uiFlags & HB_FF_BINARY ) == 0 )
pszVal = hb_cdpnDup( ( const char * ) pArea->pRecord + pArea->pFieldOffset[ uiIndex ],
&nLen, pArea->area.cdPage, hb_vmCDP() );
else
pszVal = ( char * ) pArea->pRecord + pArea->pFieldOffset[ uiIndex ];
hb_itemPutCLPtr( pItem, pszVal, nLen );
}
break;
case HB_FT_LOGICAL:
hb_itemPutL( pItem, pArea->pRecord[ pArea->pFieldOffset[ uiIndex ] ] == 'T' ||
pArea->pRecord[ pArea->pFieldOffset[ uiIndex ] ] == 't' ||
pArea->pRecord[ pArea->pFieldOffset[ uiIndex ] ] == 'Y' ||
pArea->pRecord[ pArea->pFieldOffset[ uiIndex ] ] == 'y' );
break;
case HB_FT_DATE:
if( pField->uiLen == 3 )
hb_itemPutDL( pItem, HB_GET_LE_UINT24( pArea->pRecord + pArea->pFieldOffset[ uiIndex ] ) );
else if( pField->uiLen == 4 )
hb_itemPutDL( pItem, HB_GET_LE_UINT32( pArea->pRecord + pArea->pFieldOffset[ uiIndex ] ) );
else
hb_itemPutDS( pItem, ( char * ) pArea->pRecord + pArea->pFieldOffset[ uiIndex ] );
break;
case HB_FT_TIME:
if( pField->uiLen == 4 )
{
hb_itemPutTDT( pItem, 0, HB_GET_LE_INT32( pArea->pRecord + pArea->pFieldOffset[ uiIndex ] ) );
break;
}
/* no break */
case HB_FT_MODTIME:
case HB_FT_TIMESTAMP:
hb_itemPutTDT( pItem, HB_GET_LE_INT32( pArea->pRecord + pArea->pFieldOffset[ uiIndex ] ),
HB_GET_LE_INT32( pArea->pRecord + pArea->pFieldOffset[ uiIndex ] + 4 ) );
break;
case HB_FT_INTEGER:
case HB_FT_CURRENCY:
case HB_FT_AUTOINC:
case HB_FT_ROWVER:
if( pField->uiDec )
{
switch( pField->uiLen )
{
case 1:
dVal = ( HB_SCHAR ) pArea->pRecord[ pArea->pFieldOffset[ uiIndex ] ];
iLen = 4;
break;
case 2:
dVal = HB_GET_LE_INT16( pArea->pRecord + pArea->pFieldOffset[ uiIndex ] );
iLen = 6;
break;
case 3:
dVal = HB_GET_LE_INT24( pArea->pRecord + pArea->pFieldOffset[ uiIndex ] );
iLen = 10;
break;
case 4:
dVal = HB_GET_LE_INT32( pArea->pRecord + pArea->pFieldOffset[ uiIndex ] );
iLen = 10;
break;
case 8:
dVal = ( double ) HB_GET_LE_INT64( pArea->pRecord + pArea->pFieldOffset[ uiIndex ] );
iLen = 20;
break;
default:
dVal = 0;
iLen = 0;
fError = HB_TRUE;
break;
}
hb_itemPutNDLen( pItem, hb_numDecConv( dVal, ( int ) pField->uiDec ),
iLen, ( int ) pField->uiDec );
}
else
{
switch( pField->uiLen )
{
case 1:
hb_itemPutNILen( pItem, ( HB_SCHAR ) pArea->pRecord[ pArea->pFieldOffset[ uiIndex ] ], 4 );
break;
case 2:
hb_itemPutNILen( pItem, ( int ) HB_GET_LE_INT16( pArea->pRecord + pArea->pFieldOffset[ uiIndex ] ), 6 );
break;
case 3:
hb_itemPutNIntLen( pItem, ( HB_MAXINT ) HB_GET_LE_INT24( pArea->pRecord + pArea->pFieldOffset[ uiIndex ] ), 10 );
break;
case 4:
hb_itemPutNIntLen( pItem, ( HB_MAXINT ) HB_GET_LE_INT32( pArea->pRecord + pArea->pFieldOffset[ uiIndex ] ), 10 );
break;
case 8:
#ifndef HB_LONG_LONG_OFF
hb_itemPutNIntLen( pItem, ( HB_MAXINT ) HB_GET_LE_INT64( pArea->pRecord + pArea->pFieldOffset[ uiIndex ] ), 20 );
#else
hb_itemPutNLen( pItem, ( double ) HB_GET_LE_INT64( pArea->pRecord + pArea->pFieldOffset[ uiIndex ] ), 20, 0 );
#endif
break;
default:
fError = HB_TRUE;
break;
}
}
break;
case HB_FT_DOUBLE:
case HB_FT_CURDOUBLE:
hb_itemPutNDLen( pItem, HB_GET_LE_DOUBLE( pArea->pRecord + pArea->pFieldOffset[ uiIndex ] ),
20 - ( pField->uiDec > 0 ? ( pField->uiDec + 1 ) : 0 ),
( int ) pField->uiDec );
break;
case HB_FT_LONG:
/* DBASE documentation defines maximum numeric field size as 20
* but Clipper allows to create longer fields so I remove this
* limit, Druzus
*/
#if 0
if( pField->uiLen > 20 )
{
fError = HB_TRUE;
break;
}
#endif
fDbl = hb_strnToNum( ( const char * ) pArea->pRecord + pArea->pFieldOffset[ uiIndex ],
pField->uiLen, &lVal, &dVal );
if( pField->uiDec )
hb_itemPutNDLen( pItem, fDbl ? dVal : ( double ) lVal,
( int ) ( pField->uiLen - pField->uiDec - 1 ),
( int ) pField->uiDec );
else if( fDbl )
hb_itemPutNDLen( pItem, dVal, ( int ) pField->uiLen, 0 );
else
hb_itemPutNIntLen( pItem, lVal, ( int ) pField->uiLen );
break;
case HB_FT_FLOAT:
pszVal = ( char * ) pArea->pRecord + pArea->pFieldOffset[ uiIndex ];
dVal = hb_strVal( pszVal, pField->uiLen );
nLen = pField->uiLen;
while( --nLen && HB_ISDIGIT( pszVal[ nLen ] ) )
;
if( nLen && ( pszVal[ nLen ] == '+' || pszVal[ nLen ] == '-' ) &&
( pszVal[ nLen - 1 ] == 'e' || pszVal[ nLen - 1 ] == 'E' ) )
{
HB_USHORT uiLen = ( HB_USHORT ) nLen;
int iExp = 0;
while( ++uiLen < pField->uiLen )
iExp = iExp * 10 + ( pszVal[ uiLen ] - '0' );
if( pszVal[ nLen ] == '-' )
iExp = -iExp;
dVal = hb_numExpConv( dVal, -iExp );
}
hb_itemPutNDLen( pItem, dVal,
( int ) ( pField->uiLen - pField->uiDec - 1 ),
( int ) pField->uiDec );
break;
case HB_FT_ANY:
if( pField->uiLen == 3 )
hb_itemPutDL( pItem, hb_sxPtoD( ( char * ) pArea->pRecord + pArea->pFieldOffset[ uiIndex ] ) );
else if( pField->uiLen == 4 )
hb_itemPutNIntLen( pItem, ( HB_MAXINT ) HB_GET_LE_INT32( pArea->pRecord + pArea->pFieldOffset[ uiIndex ] ), 10 );
else
fError = HB_TRUE;
break;
case HB_FT_MEMO:
default:
fError = HB_TRUE;
break;
}
/* Any error? */
if( fError )
{
pError = hb_errNew();
hb_errPutGenCode( pError, EG_DATATYPE );
hb_errPutDescription( pError, hb_langDGetErrorDesc( EG_DATATYPE ) );
hb_errPutOperation( pError, hb_dynsymName( ( PHB_DYNS ) pField->sym ) );
hb_errPutSubCode( pError, EDBF_DATATYPE );
SELF_ERROR( &pArea->area, pError );
hb_itemRelease( pError );
return HB_FAILURE;
}
if( pArea->fTrigger )
{
if( ! hb_dbfTriggerDo( pArea, EVENT_GET, uiIndex + 1, pItem ) )
return HB_FAILURE;
}
return HB_SUCCESS;
}
/*
* Obtain the length of a field value.
*/
static HB_ERRCODE hb_dbfGetVarLen( DBFAREAP pArea, HB_USHORT uiIndex, HB_SIZE * pLength )
{
HB_TRACE( HB_TR_DEBUG, ( "hb_dbfGetVarLen(%p, %hu, %p)", pArea, uiIndex, pLength ) );
*pLength = pArea->area.lpFields[ uiIndex - 1 ].uiLen;
return HB_SUCCESS;
}
/*
* Perform a write of WorkArea memory to the data store.
*/
static HB_ERRCODE hb_dbfGoCold( DBFAREAP pArea )
{
HB_TRACE( HB_TR_DEBUG, ( "hb_dbfGoCold(%p)", pArea ) );
if( pArea->fRecordChanged )
{
if( pArea->fTrigger )
{
/* The pending relation may move the record pointer so we should
disable them for trigger evaluation */
LPDBRELINFO lpdbPendingRel = pArea->lpdbPendingRel;
pArea->lpdbPendingRel = NULL;
hb_dbfTriggerDo( pArea, EVENT_UPDATE, 0, NULL );
/* Restore disabled pending relation */
pArea->lpdbPendingRel = lpdbPendingRel;
}
if( pArea->fModStamp )
hb_dbfUpdateStampFields( pArea );
/* Write current record */
if( ! hb_dbfWriteRecord( pArea ) )
return HB_FAILURE;
if( pArea->fAppend )
{
pArea->fUpdateHeader = HB_TRUE;
pArea->fAppend = HB_FALSE;
}
/* Update header */
if( pArea->fShared && pArea->fUpdateHeader )
return SELF_WRITEDBHEADER( &pArea->area );
}
return HB_SUCCESS;
}
/*
* Mark the WorkArea data buffer as hot.
*/
static HB_ERRCODE hb_dbfGoHot( DBFAREAP pArea )
{
HB_TRACE( HB_TR_DEBUG, ( "hb_dbfGoHot(%p)", pArea ) );
if( pArea->fReadonly )
{
hb_dbfErrorRT( pArea, EG_READONLY, EDBF_READONLY, NULL, 0, 0, NULL );
return HB_FAILURE;
}
else if( pArea->fShared && ! pArea->fFLocked &&
! hb_dbfIsLocked( pArea, pArea->ulRecNo ) )
{
hb_dbfErrorRT( pArea, EG_UNLOCKED, EDBF_UNLOCKED, NULL, 0, 0, NULL );
return HB_FAILURE;
}
pArea->fRecordChanged = HB_TRUE;
return HB_SUCCESS;
}
/*
* Replace the current record.
*/
static HB_ERRCODE hb_dbfPutRec( DBFAREAP pArea, const HB_BYTE * pBuffer )
{
HB_TRACE( HB_TR_DEBUG, ( "hb_dbfPutRec(%p, %p)", pArea, pBuffer ) );
if( pBuffer != NULL )
{
if( pArea->lpdbPendingRel )
{
if( SELF_FORCEREL( &pArea->area ) != HB_SUCCESS )
return HB_FAILURE;
}
if( ! pArea->fPositioned )
return HB_SUCCESS;
if( ! pArea->fRecordChanged && SELF_GOHOT( &pArea->area ) != HB_SUCCESS )
return HB_FAILURE;
/* Copy data to buffer */
memcpy( pArea->pRecord, pBuffer, pArea->uiRecordLen );
/*
* TODO: such operation should be forbidden
* maybe it will be good to return HB_FAILURE when
* pArea->pRecord[ 0 ] != '*' && pArea->pRecord[ 0 ] != ' '
*/
if( pArea->pRecord[ 0 ] == 'D' || pArea->pRecord[ 0 ] == 'E' )
{
if( ! pArea->fHasMemo )
pArea->fEncrypted = HB_TRUE;
pArea->pRecord[ 0 ] = pArea->pRecord[ 0 ] == 'D' ? '*' : ' ';
}
pArea->fDeleted = pArea->pRecord[ 0 ] == '*';
}
else /* if( pArea->fRecordChanged ) */
{
HB_BYTE * pRecord = pArea->pRecord;
HB_SIZE nWritten;
if( pArea->pCryptKey )
{
/* This enables record encryption in update operation */
if( pArea->bCryptType == DB_CRYPT_SIX && ! pArea->fHasMemo )
pArea->fEncrypted = HB_TRUE;
if( pArea->bCryptType == DB_CRYPT_SIX && pArea->fEncrypted )
{
pRecord = ( HB_BYTE * ) hb_xgrab( pArea->uiRecordLen );
pRecord[ 0 ] = pArea->fDeleted ? 'D' : 'E';
hb_sxEnCrypt( ( const char * ) pArea->pRecord + 1,
( char * ) pRecord + 1,
pArea->pCryptKey, pArea->uiRecordLen - 1 );
}
}
/* Write data to file */
nWritten = hb_fileWriteAt( pArea->pDataFile, pRecord, pArea->uiRecordLen,
( HB_FOFFSET ) pArea->uiHeaderLen +
( HB_FOFFSET ) ( pArea->ulRecNo - 1 ) *
( HB_FOFFSET ) pArea->uiRecordLen );
if( pRecord != pArea->pRecord )
hb_xfree( pRecord );
if( nWritten != ( HB_SIZE ) pArea->uiRecordLen )
{
hb_dbfErrorRT( pArea, EG_WRITE, EDBF_WRITE, pArea->szDataFileName,
hb_fsError(), 0, NULL );
return HB_FAILURE;
}
}
return HB_SUCCESS;
}
/*
* Assign a value to a field.
*/
static HB_ERRCODE hb_dbfPutValue( DBFAREAP pArea, HB_USHORT uiIndex, PHB_ITEM pItem )
{
LPFIELD pField;
/* this buffer is for varlength, date and number conversions,
* DBASE documentation defines maximum numeric field size as 20
* but Clipper allows to create longer fields so I removed this
* limit [druzus]
*/
char szBuffer[ 256 ];
const char * pszPtr;
HB_SIZE nSize, nLen;
HB_BYTE * ptr;
HB_ERRCODE errCode;
HB_TRACE( HB_TR_DEBUG, ( "hb_dbfPutValue(%p, %hu, %p)", pArea, uiIndex, pItem ) );
if( pArea->fTrigger )
{
if( ! hb_dbfTriggerDo( pArea, EVENT_PUT, uiIndex, pItem ) )
return HB_FAILURE;
}
if( pArea->lpdbPendingRel )
{
if( SELF_FORCEREL( &pArea->area ) != HB_SUCCESS )
return HB_FAILURE;
}
/* Read record */
if( ! pArea->fValidBuffer && ! hb_dbfReadRecord( pArea ) )
return HB_FAILURE;
if( --uiIndex >= pArea->area.uiFieldCount )
return HB_FAILURE;
if( ! pArea->fPositioned )
return HB_SUCCESS;
/* Buffer is hot? */
if( ! pArea->fRecordChanged && SELF_GOHOT( &pArea->area ) == HB_FAILURE )
return HB_FAILURE;
errCode = HB_SUCCESS;
pField = pArea->area.lpFields + uiIndex;
if( pField->uiType == HB_FT_MEMO ||
pField->uiType == HB_FT_IMAGE ||
pField->uiType == HB_FT_BLOB ||
pField->uiType == HB_FT_OLE )
errCode = EDBF_DATATYPE;
else
{
if( HB_IS_MEMO( pItem ) || HB_IS_STRING( pItem ) )
{
nLen = pField->uiLen;
if( pField->uiType == HB_FT_STRING )
{
if( ( pField->uiFlags & HB_FF_UNICODE ) != 0 )
{
HB_WCHAR * pwBuffer = ( HB_WCHAR * ) &pArea->pRecord[ pArea->pFieldOffset[ uiIndex ] ];
nLen = hb_itemCopyStrU16( pItem, HB_CDP_ENDIAN_LITTLE,
pwBuffer, nLen );
while( nLen < ( HB_SIZE ) pField->uiLen )
{
HB_PUT_LE_UINT16( &pwBuffer[ nLen ], ' ' );
++nLen;
}
}
else
{
pszPtr = hb_itemGetCPtr( pItem );
nSize = hb_itemGetCLen( pItem );
if( ( pField->uiFlags & HB_FF_BINARY ) == 0 )
{
hb_cdpnDup2( pszPtr, nSize,
( char * ) pArea->pRecord + pArea->pFieldOffset[ uiIndex ],
&nLen, hb_vmCDP(), pArea->area.cdPage );
}
else
{
if( nLen > nSize )
nLen = nSize;
memcpy( pArea->pRecord + pArea->pFieldOffset[ uiIndex ],
hb_itemGetCPtr( pItem ), nLen );
}
if( nLen < ( HB_SIZE ) pField->uiLen )
memset( pArea->pRecord + pArea->pFieldOffset[ uiIndex ] + nLen,
' ', pField->uiLen - nLen );
}
}
else if( pField->uiType == HB_FT_VARLENGTH )
{
if( ( pField->uiFlags & HB_FF_UNICODE ) != 0 )
{
HB_WCHAR * pwBuffer = ( HB_WCHAR * ) &pArea->pRecord[ pArea->pFieldOffset[ uiIndex ] ];
nLen = hb_itemCopyStrU16( pItem, HB_CDP_ENDIAN_LITTLE,
pwBuffer, nLen );
HB_PUT_LE_UINT16( &pwBuffer[ pField->uiLen ], nLen );
}
else
{
pszPtr = hb_itemGetCPtr( pItem );
nSize = hb_itemGetCLen( pItem );
if( ( pField->uiFlags & HB_FF_BINARY ) == 0 )
{
if( nLen > ( HB_SIZE ) sizeof( szBuffer ) )
nLen = sizeof( szBuffer );
pszPtr = hb_cdpnDup2( pszPtr, nSize, szBuffer, &nLen,
hb_vmCDP(), pArea->area.cdPage );
}
else
{
if( nLen > nSize )
nLen = nSize;
}
memcpy( pArea->pRecord + pArea->pFieldOffset[ uiIndex ], pszPtr, nLen );
if( nLen < ( HB_SIZE ) pField->uiLen )
{
pArea->pRecord[ pArea->pFieldOffset[ uiIndex ] + pField->uiLen - 1 ] = ( HB_BYTE ) nLen;
hb_dbfSetNullFlag( pArea->pRecord, pArea->uiNullOffset, pArea->pFieldBits[ uiIndex ].uiLengthBit );
}
else
hb_dbfClearNullFlag( pArea->pRecord, pArea->uiNullOffset, pArea->pFieldBits[ uiIndex ].uiLengthBit );
}
}
else
errCode = EDBF_DATATYPE;
}
else if( HB_IS_DATETIME( pItem ) )
{
if( pField->uiType == HB_FT_DATE )
{
if( pField->uiLen == 3 )
{
HB_PUT_LE_UINT24( pArea->pRecord + pArea->pFieldOffset[ uiIndex ],
hb_itemGetDL( pItem ) );
}
else if( pField->uiLen == 4 )
{
HB_PUT_LE_UINT32( pArea->pRecord + pArea->pFieldOffset[ uiIndex ],
hb_itemGetDL( pItem ) );
}
else
{
hb_itemGetDS( pItem, szBuffer );
memcpy( pArea->pRecord + pArea->pFieldOffset[ uiIndex ], szBuffer, 8 );
}
}
else if( pField->uiType == HB_FT_TIMESTAMP ||
pField->uiType == HB_FT_TIME )
{
long lDate, lTime;
hb_itemGetTDT( pItem, &lDate, &lTime );
ptr = pArea->pRecord + pArea->pFieldOffset[ uiIndex ];
if( pField->uiType == HB_FT_TIMESTAMP )
{
HB_PUT_LE_UINT32( ptr, lDate );
ptr += 4;
}
HB_PUT_LE_UINT32( ptr, lTime );
}
else if( pField->uiType == HB_FT_ANY && pField->uiLen == 3 )
{
hb_sxDtoP( ( char * ) pArea->pRecord + pArea->pFieldOffset[ uiIndex ],
hb_itemGetDL( pItem ) );
}
else
errCode = EDBF_DATATYPE;
}
else if( HB_IS_NUMBER( pItem ) )
{
if( pField->uiType == HB_FT_LONG || pField->uiType == HB_FT_FLOAT )
{
if( hb_itemStrBuf( szBuffer, pItem, pField->uiLen, pField->uiDec ) )
{
memcpy( pArea->pRecord + pArea->pFieldOffset[ uiIndex ],
szBuffer, pField->uiLen );
}
else
{
errCode = EDBF_DATAWIDTH;
memset( pArea->pRecord + pArea->pFieldOffset[ uiIndex ],
'*', pField->uiLen );
}
}
else if( pField->uiType == HB_FT_INTEGER )
{
HB_MAXINT lVal;
double dVal;
int iSize;
if( pField->uiDec || HB_IS_DOUBLE( pItem ) )
{
#if 0 /* this version rounds double values to nearest integer */
dVal = hb_numDecConv( hb_itemGetND( pItem ), -( int ) pField->uiDec );
#else /* this one truncates double value to integer dropping fractional part */
dVal = hb_itemGetND( pItem );
if( pField->uiDec )
dVal = hb_numDecConv( dVal, -( int ) pField->uiDec );
#endif
lVal = ( HB_MAXINT ) dVal;
if( ! HB_DBL_LIM_INT64( dVal ) )
iSize = pField->uiLen + 1;
else
#ifndef HB_LONG_LONG_OFF
iSize = HB_LIM_INT8( lVal ) ? 1 :
( HB_LIM_INT16( lVal ) ? 2 :
( HB_LIM_INT24( lVal ) ? 3 :
( HB_LIM_INT32( lVal ) ? 4 : 8 ) ) );
#else
iSize = HB_DBL_LIM_INT8( dVal ) ? 1 :
( HB_DBL_LIM_INT16( dVal ) ? 2 :
( HB_DBL_LIM_INT24( dVal ) ? 3 :
( HB_DBL_LIM_INT32( dVal ) ? 4 : 8 ) ) );
#endif
}
else
{
lVal = ( HB_MAXINT ) hb_itemGetNInt( pItem );
#ifdef HB_LONG_LONG_OFF
dVal = ( double ) lVal;
#endif
iSize = HB_LIM_INT8( lVal ) ? 1 :
( HB_LIM_INT16( lVal ) ? 2 :
( HB_LIM_INT24( lVal ) ? 3 :
( HB_LIM_INT32( lVal ) ? 4 : 8 ) ) );
}
if( iSize > pField->uiLen )
{
errCode = EDBF_DATAWIDTH;
}
else
{
switch( pField->uiLen )
{
case 1:
pArea->pRecord[ pArea->pFieldOffset[ uiIndex ] ] = ( signed char ) lVal;
break;
case 2:
HB_PUT_LE_UINT16( pArea->pRecord + pArea->pFieldOffset[ uiIndex ], ( HB_U16 ) lVal );
break;
case 3:
HB_PUT_LE_UINT24( pArea->pRecord + pArea->pFieldOffset[ uiIndex ], ( HB_U32 ) lVal );
break;
case 4:
HB_PUT_LE_UINT32( pArea->pRecord + pArea->pFieldOffset[ uiIndex ], ( HB_U32 ) lVal );
break;
case 8:
#ifndef HB_LONG_LONG_OFF
HB_PUT_LE_UINT64( pArea->pRecord + pArea->pFieldOffset[ uiIndex ], ( HB_U64 ) lVal );
#else
HB_PUT_LE_UINT64( pArea->pRecord + pArea->pFieldOffset[ uiIndex ], dVal );
#endif
break;
default:
errCode = EDBF_DATATYPE;
break;
}
}
}
else if( pField->uiType == HB_FT_DOUBLE )
{
HB_PUT_LE_DOUBLE( pArea->pRecord + pArea->pFieldOffset[ uiIndex ], hb_itemGetND( pItem ) );
}
else if( pField->uiType == HB_FT_ANY && pField->uiLen == 4 )
{
HB_MAXINT lVal = hb_itemGetNInt( pItem );
if( HB_IS_DOUBLE( pItem ) ?
HB_DBL_LIM_INT32( hb_itemGetND( pItem ) ) :
HB_LIM_INT32( lVal ) )
{
HB_PUT_LE_UINT32( pArea->pRecord + pArea->pFieldOffset[ uiIndex ], ( HB_U32 ) lVal );
}
else
{
errCode = EDBF_DATAWIDTH;
}
}
else
{
errCode = EDBF_DATATYPE;
}
}
else if( HB_IS_LOGICAL( pItem ) )
{
if( pField->uiType == HB_FT_LOGICAL )
pArea->pRecord[ pArea->pFieldOffset[ uiIndex ] ] = hb_itemGetL( pItem ) ? 'T' : 'F';
else
errCode = EDBF_DATATYPE;
}
else
errCode = EDBF_DATATYPE;
}
/* Exit if any error */
if( errCode != HB_SUCCESS )
{
PHB_ITEM pError = hb_errNew();
hb_errPutGenCode( pError, hb_dbfGetEGcode( errCode ) );
hb_errPutDescription( pError, hb_langDGetErrorDesc( hb_dbfGetEGcode( errCode ) ) );
hb_errPutOperation( pError, hb_dynsymName( ( PHB_DYNS ) pField->sym ) );
hb_errPutSubCode( pError, errCode );
hb_errPutFlags( pError, EF_CANDEFAULT );
errCode = SELF_ERROR( &pArea->area, pError );
hb_itemRelease( pError );
return errCode == E_DEFAULT ? HB_SUCCESS : HB_FAILURE;
}
else if( pArea->bTableType == DB_DBF_VFP &&
( pField->uiFlags & HB_FF_NULLABLE ) != 0 )
{
hb_dbfClearNullFlag( pArea->pRecord, pArea->uiNullOffset, pArea->pFieldBits[ uiIndex ].uiNullBit );
}
return HB_SUCCESS;
}
/*
* Undelete the current record.
*/
static HB_ERRCODE hb_dbfRecall( DBFAREAP pArea )
{
HB_TRACE( HB_TR_DEBUG, ( "hb_dbfRecall(%p)", pArea ) );
if( pArea->fTrigger )
{
if( ! hb_dbfTriggerDo( pArea, EVENT_RECALL, 0, NULL ) )
return HB_FAILURE;
}
if( pArea->lpdbPendingRel )
{
if( SELF_FORCEREL( &pArea->area ) != HB_SUCCESS )
return HB_FAILURE;
}
/* Read record */
if( ! pArea->fValidBuffer && ! hb_dbfReadRecord( pArea ) )
return HB_FAILURE;
if( ! pArea->fPositioned )
return HB_SUCCESS;
/* Buffer is hot? */
if( ! pArea->fRecordChanged && SELF_GOHOT( &pArea->area ) != HB_SUCCESS )
return HB_FAILURE;
pArea->pRecord[ 0 ] = ' ';
pArea->fDeleted = HB_FALSE;
return HB_SUCCESS;
}
/*
* Obtain number of records in WorkArea.
*/
static HB_ERRCODE hb_dbfRecCount( DBFAREAP pArea, HB_ULONG * pRecCount )
{
HB_TRACE( HB_TR_DEBUG, ( "hb_dbfRecCount(%p, %p)", pArea, pRecCount ) );
/* Update record count */
if( pArea->fShared )
pArea->ulRecCount = hb_dbfCalcRecCount( pArea );
*pRecCount = pArea->ulRecCount;
return HB_SUCCESS;
}
/*
* Obtain physical row number at current WorkArea cursor position.
*/
static HB_ERRCODE hb_dbfRecNo( DBFAREAP pArea, HB_ULONG * pulRecNo )
{
HB_TRACE( HB_TR_DEBUG, ( "hb_dbfRecNo(%p, %p)", pArea, pulRecNo ) );
if( pArea->lpdbPendingRel )
{
if( SELF_FORCEREL( &pArea->area ) != HB_SUCCESS )
return HB_FAILURE;
}
*pulRecNo = pArea->ulRecNo;
return HB_SUCCESS;
}
/*
* Obtain physical row ID at current WorkArea cursor position.
*/
static HB_ERRCODE hb_dbfRecId( DBFAREAP pArea, PHB_ITEM pRecNo )
{
HB_ERRCODE errCode;
HB_ULONG ulRecNo = 0;
HB_TRACE( HB_TR_DEBUG, ( "hb_dbfRecId(%p, %p)", pArea, pRecNo ) );
errCode = SELF_RECNO( &pArea->area, &ulRecNo );
#ifdef HB_CLP_STRICT
/* this is for strict Clipper compatibility but IMHO Clipper should not
do that and always set fixed size independent to the record number */
if( ulRecNo < 10000000 )
{
hb_itemPutNLLen( pRecNo, ulRecNo, 7 );
}
else
{
hb_itemPutNLLen( pRecNo, ulRecNo, 10 );
}
#else
hb_itemPutNInt( pRecNo, ulRecNo );
#endif
return errCode;
}
/*
* Establish the extent of the array of fields for a WorkArea.
*/
static HB_ERRCODE hb_dbfSetFieldExtent( DBFAREAP pArea, HB_USHORT uiFieldExtent )
{
HB_TRACE( HB_TR_DEBUG, ( "hb_dbfSetFieldExtent(%p, %hu)", pArea, uiFieldExtent ) );
if( SUPER_SETFIELDEXTENT( &pArea->area, uiFieldExtent ) == HB_FAILURE )
return HB_FAILURE;
/* Alloc field offsets array */
if( uiFieldExtent )
{
pArea->pFieldOffset = ( HB_USHORT * ) hb_xgrab( uiFieldExtent * sizeof( HB_USHORT ) );
memset( pArea->pFieldOffset, 0, uiFieldExtent * sizeof( HB_USHORT ) );
}
return HB_SUCCESS;
}
#define hb_dbfAlias NULL
/*
* Close the table in the WorkArea.
*/
static HB_ERRCODE hb_dbfClose( DBFAREAP pArea )
{
HB_TRACE( HB_TR_DEBUG, ( "hb_dbfClose(%p)", pArea ) );
if( pArea->fTrigger )
{
if( ! hb_dbfTriggerDo( pArea, EVENT_PRECLOSE, 0, NULL ) )
return HB_FAILURE;
}
/* Reset parent rel struct */
pArea->lpdbPendingRel = NULL;
/* Update record and unlock records */
if( pArea->pDataFile )
{
/* update buffers */
SELF_GOCOLD( &pArea->area );
/* Unlock all records */
SELF_UNLOCK( &pArea->area, NULL );
/* Update header */
if( pArea->fUpdateHeader )
SELF_WRITEDBHEADER( &pArea->area );
/* It's not Clipper compatible but it reduces the problem with
buggy Windows network setting */
if( hb_setGetHardCommit() )
SELF_FLUSH( &pArea->area );
}
SUPER_CLOSE( &pArea->area );
if( pArea->pDataFile )
{
hb_fileClose( pArea->pDataFile );
pArea->pDataFile = NULL;
if( pArea->fTemporary )
hb_fileDelete( pArea->szDataFileName );
}
/* Close the memo file */
if( pArea->fHasMemo && pArea->pMemoFile )
{
hb_fileClose( pArea->pMemoFile );
pArea->pMemoFile = NULL;
if( pArea->fTemporary )
hb_fileDelete( pArea->szMemoFileName );
}
pArea->fTemporary = HB_FALSE;
/* Free field offset array */
if( pArea->pFieldOffset )
{
hb_xfree( pArea->pFieldOffset );
pArea->pFieldOffset = NULL;
}
/* Free field bits array */
if( pArea->pFieldBits )
{
hb_xfree( pArea->pFieldBits );
pArea->pFieldBits = NULL;
}
/* Free buffer */
if( pArea->pRecord )
{
hb_xfree( pArea->pRecord );
pArea->pRecord = NULL;
}
/* Free encryption password key */
if( pArea->pCryptKey )
{
memset( pArea->pCryptKey, '\0', 8 );
hb_xfree( pArea->pCryptKey );
pArea->pCryptKey = NULL;
}
/* Free all filenames */
if( pArea->szDataFileName )
{
hb_xfree( pArea->szDataFileName );
pArea->szDataFileName = NULL;
}
if( pArea->szMemoFileName )
{
hb_xfree( pArea->szMemoFileName );
pArea->szMemoFileName = NULL;
}
if( pArea->fTrigger )
{
hb_dbfTriggerDo( pArea, EVENT_POSTCLOSE, 0, NULL );
pArea->fTrigger = HB_FALSE;
}
return HB_SUCCESS;
}
/*
* Create a data store in the specified WorkArea.
*/
static HB_ERRCODE hb_dbfCreate( DBFAREAP pArea, LPDBOPENINFO pCreateInfo )
{
HB_ERRCODE errCode = HB_SUCCESS;
HB_SIZE nSize;
HB_USHORT uiCount, uiLen;
HB_BOOL fError, fRawBlob;
DBFFIELD * pThisField;
HB_BYTE * pBuffer;
PHB_FNAME pFileName;
PHB_ITEM pItem = NULL, pError;
char szFileName[ HB_PATH_MAX ];
HB_TRACE( HB_TR_DEBUG, ( "hb_dbfCreate(%p, %p)", pArea, pCreateInfo ) );
pArea->lpdbOpenInfo = pCreateInfo;
if( ! pArea->fTemporary )
{
pFileName = hb_fsFNameSplit( pCreateInfo->abName );
if( ! pFileName->szExtension && hb_setGetDefExtension() )
{
pItem = hb_itemPutC( pItem, NULL );
if( SELF_INFO( &pArea->area, DBI_TABLEEXT, pItem ) != HB_SUCCESS )
{
hb_itemRelease( pItem );
hb_xfree( pFileName );
pArea->lpdbOpenInfo = NULL;
return HB_FAILURE;
}
pFileName->szExtension = hb_itemGetCPtr( pItem );
hb_fsFNameMerge( szFileName, pFileName );
}
else
{
hb_strncpy( szFileName, pCreateInfo->abName, sizeof( szFileName ) - 1 );
}
hb_xfree( pFileName );
}
pItem = hb_itemPutL( pItem, HB_FALSE );
fRawBlob = SELF_RDDINFO( SELF_RDDNODE( &pArea->area ), RDDI_BLOB_SUPPORT, pCreateInfo->ulConnection, pItem ) == HB_SUCCESS &&
hb_itemGetL( pItem );
if( pArea->bLockType == 0 )
{
pItem = hb_itemPutNI( pItem, 0 );
if( SELF_INFO( &pArea->area, DBI_LOCKSCHEME, pItem ) != HB_SUCCESS )
{
hb_itemRelease( pItem );
pArea->lpdbOpenInfo = NULL;
return HB_FAILURE;
}
pArea->bLockType = ( HB_BYTE ) hb_itemGetNI( pItem );
if( pArea->bLockType == 0 )
{
pArea->bLockType = DB_DBFLOCK_CLIPPER;
}
}
if( pArea->bTableType == DB_DBF_VFP && ! fRawBlob )
{
pArea->bMemoType = DB_MEMO_FPT;
}
else if( pArea->bMemoType == 0 )
{
/* get memo type */
pItem = hb_itemPutNI( pItem, 0 );
if( SELF_INFO( &pArea->area, DBI_MEMOTYPE, pItem ) != HB_SUCCESS )
{
hb_itemRelease( pItem );
pArea->lpdbOpenInfo = NULL;
return HB_FAILURE;
}
pArea->bMemoType = ( HB_BYTE ) hb_itemGetNI( pItem );
}
pArea->bCryptType = DB_CRYPT_NONE;
if( pItem )
hb_itemRelease( pItem );
if( pArea->area.uiFieldCount * sizeof( DBFFIELD ) + sizeof( DBFHEADER ) +
( pArea->bTableType == DB_DBF_VFP ? 1 : 2 ) > UINT16_MAX )
{
hb_dbfErrorRT( pArea, EG_CREATE, EDBF_DATAWIDTH, pCreateInfo->abName, 0, 0, NULL );
pArea->lpdbOpenInfo = NULL;
return HB_FAILURE;
}
if( ! fRawBlob )
{
pError = NULL;
/* Try create */
do
{
if( pArea->fTemporary )
pArea->pDataFile = hb_fileCreateTempEx( szFileName, NULL, NULL, NULL, FC_NORMAL );
else
pArea->pDataFile = hb_fileExtOpen( szFileName, NULL,
FO_READWRITE | FO_EXCLUSIVE | FXO_TRUNCATE |
FXO_DEFAULTS | FXO_SHARELOCK | FXO_COPYNAME |
FXO_NOSEEKPOS, NULL, pError );
if( pArea->pDataFile )
break;
}
while( hb_dbfErrorRT( pArea, EG_CREATE, EDBF_CREATE_DBF, szFileName, hb_fsError(),
EF_CANRETRY | EF_CANDEFAULT, &pError ) == E_RETRY );
if( pError )
hb_itemRelease( pError );
if( ! pArea->pDataFile )
{
pArea->lpdbOpenInfo = NULL;
return HB_FAILURE;
}
}
pArea->szDataFileName = hb_strdup( szFileName );
nSize = ( HB_SIZE ) pArea->area.uiFieldCount * sizeof( DBFFIELD ) +
( pArea->bTableType == DB_DBF_VFP ? 1 : 2 );
pBuffer = ( HB_BYTE * ) hb_xgrab( nSize + sizeof( DBFFIELD ) + 1 );
memset( pBuffer, 0, nSize + sizeof( DBFFIELD ) + 1 );
pThisField = ( DBFFIELD * ) pBuffer;
pArea->fHasMemo = fError = HB_FALSE;
/* Size for deleted flag */
pArea->uiRecordLen = 1;
pArea->uiNullCount = 0;
for( uiCount = 0; uiCount < pArea->area.uiFieldCount; uiCount++ )
{
LPFIELD pField = pArea->area.lpFields + uiCount;
hb_strncpy( ( char * ) pThisField->bName,
hb_dynsymName( ( PHB_DYNS ) pField->sym ), sizeof( pThisField->bName ) - 1 );
pArea->pFieldOffset[ uiCount ] = pArea->uiRecordLen;
/* field offset */
if( pArea->bTableType == DB_DBF_VFP )
HB_PUT_LE_UINT16( pThisField->bReserved1, pArea->uiRecordLen );
pThisField->bFieldFlags = ( HB_BYTE ) pField->uiFlags;
switch( pField->uiType )
{
case HB_FT_STRING:
uiLen = pField->uiLen;
if( ( pField->uiFlags & HB_FF_UNICODE ) != 0 )
{
pThisField->bType = '\x1A';
uiLen <<= 1;
}
else
{
pThisField->bType = 'C';
}
pThisField->bLen = ( HB_BYTE ) uiLen;
pThisField->bDec = ( HB_BYTE ) ( uiLen >> 8 );
pArea->uiRecordLen += uiLen;
break;
case HB_FT_LOGICAL:
pThisField->bType = 'L';
pThisField->bLen = 1;
pArea->uiRecordLen++;
break;
case HB_FT_MEMO:
pThisField->bType = ( pField->uiFlags & HB_FF_UNICODE ) ? '\x1C' : 'M';
if( pField->uiLen != 4 || pArea->bMemoType == DB_MEMO_SMT )
pField->uiLen = 10;
pThisField->bLen = ( HB_BYTE ) pField->uiLen;
pArea->uiRecordLen += pField->uiLen;
pArea->fHasMemo = HB_TRUE;
break;
case HB_FT_BLOB:
pThisField->bType = 'W';
if( pField->uiLen != 4 || pArea->bMemoType == DB_MEMO_SMT )
pField->uiLen = 10;
pThisField->bLen = ( HB_BYTE ) pField->uiLen;
pThisField->bFieldFlags |= HB_FF_BINARY;
pArea->uiRecordLen += pField->uiLen;
pArea->fHasMemo = HB_TRUE;
break;
case HB_FT_IMAGE:
pThisField->bType = 'P';
if( pField->uiLen != 4 || pArea->bMemoType == DB_MEMO_SMT )
pField->uiLen = 10;
pThisField->bLen = ( HB_BYTE ) pField->uiLen;
pThisField->bFieldFlags |= HB_FF_BINARY;
pArea->uiRecordLen += pField->uiLen;
pArea->fHasMemo = HB_TRUE;
break;
case HB_FT_OLE:
pThisField->bType = 'G';
if( pField->uiLen != 4 || pArea->bMemoType == DB_MEMO_SMT )
pField->uiLen = 10;
pThisField->bLen = ( HB_BYTE ) pField->uiLen;
pThisField->bFieldFlags |= HB_FF_BINARY;
pArea->uiRecordLen += pField->uiLen;
pArea->fHasMemo = HB_TRUE;
break;
case HB_FT_ANY:
if( pArea->bTableType == DB_DBF_VFP )
fError = HB_TRUE;
else
{
pThisField->bType = 'V';
if( pField->uiLen < 3 || pField->uiLen == 5 )
{
pField->uiLen = 6;
}
pThisField->bLen = ( HB_BYTE ) pField->uiLen;
pThisField->bDec = ( HB_BYTE ) ( pField->uiLen >> 8 );
pArea->uiRecordLen += pField->uiLen;
if( pThisField->bLen >= 6 )
{
pArea->uiMemoVersion = DB_MEMOVER_SIX;
pArea->fHasMemo = HB_TRUE;
}
}
break;
case HB_FT_DATE:
pThisField->bType = 'D';
if( pField->uiLen != 3 && pField->uiLen != 4 )
{
pField->uiLen = pThisField->bLen = 8;
}
pThisField->bLen = ( HB_BYTE ) pField->uiLen;
pArea->uiRecordLen += pField->uiLen;
break;
case HB_FT_LONG:
pThisField->bType = 'N';
pThisField->bLen = ( HB_BYTE ) pField->uiLen;
pThisField->bDec = ( HB_BYTE ) pField->uiDec;
pArea->uiRecordLen += pField->uiLen;
break;
case HB_FT_FLOAT:
pThisField->bType = 'F';
pThisField->bLen = ( HB_BYTE ) pField->uiLen;
pThisField->bDec = ( HB_BYTE ) pField->uiDec;
pArea->uiRecordLen += pField->uiLen;
break;
case HB_FT_DOUBLE:
case HB_FT_CURDOUBLE:
pThisField->bType = 'B';
pField->uiLen = 8;
pThisField->bLen = ( HB_BYTE ) pField->uiLen;
pThisField->bDec = ( HB_BYTE ) pField->uiDec;
pArea->uiRecordLen += pField->uiLen;
break;
case HB_FT_INTEGER:
case HB_FT_CURRENCY:
pThisField->bType = ( pArea->bTableType == DB_DBF_VFP &&
pField->uiLen == 8 && pField->uiDec == 4 ) ?
'Y' : 'I';
if( ( pField->uiLen > 4 && pField->uiLen != 8 ) ||
pField->uiLen == 0 )
{
pField->uiLen = 4;
}
pThisField->bLen = ( HB_BYTE ) pField->uiLen;
pThisField->bDec = ( HB_BYTE ) pField->uiDec;
pArea->uiRecordLen += pField->uiLen;
break;
case HB_FT_VARLENGTH:
if( pField->uiLen == 0 )
pField->uiLen = 1;
if( ( pField->uiFlags & HB_FF_UNICODE ) != 0 )
{
if( pField->uiLen > 32766 )
pField->uiLen = 32766;
pThisField->bType = '\x1B';
uiLen = ( pField->uiLen + 1 ) << 1;
}
else
{
if( pField->uiLen > 255 )
pField->uiLen = 255;
if( pArea->bTableType == DB_DBF_VFP && ( pField->uiFlags & HB_FF_BINARY ) == 0 )
pThisField->bType = 'V';
else
pThisField->bType = 'Q';
uiLen = pField->uiLen;
}
pThisField->bLen = ( HB_BYTE ) uiLen;
pThisField->bDec = ( HB_BYTE ) ( uiLen >> 8 );
pArea->uiRecordLen += uiLen;
hb_dbfAllocNullFlag( pArea, uiCount, HB_TRUE );
break;
case HB_FT_TIME:
pThisField->bType = 'T';
pField->uiLen = 4;
pThisField->bLen = ( HB_BYTE ) pField->uiLen;
pArea->uiRecordLen += pField->uiLen;
break;
case HB_FT_TIMESTAMP:
pThisField->bType = pArea->bTableType == DB_DBF_VFP ? 'T' : '@';
pField->uiLen = 8;
pThisField->bLen = ( HB_BYTE ) pField->uiLen;
pThisField->bFieldFlags |= HB_FF_BINARY;
pArea->uiRecordLen += pField->uiLen;
break;
case HB_FT_MODTIME:
pThisField->bType = '=';
pField->uiLen = 8;
pThisField->bLen = ( HB_BYTE ) pField->uiLen;
pArea->uiRecordLen += pField->uiLen;
pArea->fModStamp = HB_TRUE;
break;
case HB_FT_ROWVER:
pThisField->bType = '^';
pField->uiLen = 8;
pThisField->bLen = ( HB_BYTE ) pField->uiLen;
HB_PUT_LE_UINT32( pThisField->bCounter, 1 );
pThisField->bStep = 1;
/* HB_PUT_LE_UINT64( pThisField->bReserved2, 0 ); */
pArea->uiRecordLen += pField->uiLen;
pArea->fModStamp = HB_TRUE;
break;
case HB_FT_AUTOINC:
pThisField->bType = '+';
pField->uiLen = 4;
pThisField->bLen = ( HB_BYTE ) pField->uiLen;
HB_PUT_LE_UINT32( pThisField->bCounter, 1 );
pThisField->bStep = 1;
pArea->uiRecordLen += pField->uiLen;
pArea->fAutoInc = HB_TRUE;
break;
default:
fError = HB_TRUE;
}
if( fError || pArea->pFieldOffset[ uiCount ] > pArea->uiRecordLen )
{
hb_xfree( pBuffer );
SELF_CLOSE( &pArea->area );
hb_dbfErrorRT( pArea, EG_CREATE, fError ? EDBF_DATATYPE : EDBF_DATAWIDTH,
pCreateInfo->abName, 0, 0, NULL );
pArea->lpdbOpenInfo = NULL;
return HB_FAILURE;
}
if( pArea->bTableType == DB_DBF_VFP &&
( pThisField->bFieldFlags & HB_FF_NULLABLE ) != 0 )
{
hb_dbfAllocNullFlag( pArea, uiCount, HB_FALSE );
}
pThisField++;
}
if( pArea->uiNullCount )
{
hb_strncpy( ( char * ) pThisField->bName, "_NullFlags", sizeof( pThisField->bName ) - 1 );
HB_PUT_LE_UINT16( pThisField->bReserved1, pArea->uiRecordLen );
pThisField->bType = '0';
pThisField->bFieldFlags = HB_FF_HIDDEN;
uiCount = ( pArea->uiNullCount + 7 ) >> 3;
pThisField->bLen = ( HB_BYTE ) uiCount;
pThisField->bDec = ( HB_BYTE ) ( uiCount >> 8 );
pArea->uiNullOffset = pArea->uiRecordLen;
pArea->uiRecordLen += uiCount;
nSize += sizeof( DBFFIELD );
}
pArea->fShared = HB_FALSE; /* pCreateInfo->fShared */
pArea->fReadonly = HB_FALSE; /* pCreateInfo->fReadonly */
pArea->ulRecCount = 0;
pArea->uiHeaderLen = ( HB_USHORT ) ( sizeof( DBFHEADER ) + nSize );
if( fRawBlob )
{
pArea->fHasMemo = HB_TRUE;
}
if( ! pArea->fHasMemo )
{
pArea->bMemoType = DB_MEMO_NONE;
}
pArea->ulMemoBlockSize = 0;
if( pCreateInfo->cdpId )
{
pArea->area.cdPage = hb_cdpFindExt( pCreateInfo->cdpId );
if( ! pArea->area.cdPage )
pArea->area.cdPage = hb_vmCDP();
}
else
pArea->area.cdPage = hb_vmCDP();
pItem = hb_itemNew( NULL );
if( SELF_RDDINFO( SELF_RDDNODE( &pArea->area ), RDDI_PENDINGPASSWORD,
pCreateInfo->ulConnection, pItem ) == HB_SUCCESS )
{
if( hb_dbfPasswordSet( pArea, pItem, HB_FALSE ) )
pArea->fTableEncrypted = HB_TRUE;
}
else
{
hb_itemClear( pItem );
if( SELF_RDDINFO( SELF_RDDNODE( &pArea->area ), RDDI_PASSWORD,
pCreateInfo->ulConnection, pItem ) == HB_SUCCESS )
{
if( hb_dbfPasswordSet( pArea, pItem, HB_FALSE ) )
pArea->fTableEncrypted = HB_TRUE;
}
}
hb_itemRelease( pItem );
if( ! fRawBlob )
{
/* Force write new header */
pArea->fUpdateHeader = HB_TRUE;
/* Write header */
errCode = SELF_WRITEDBHEADER( &pArea->area );
if( errCode != HB_SUCCESS )
{
hb_xfree( pBuffer );
SELF_CLOSE( &pArea->area );
pArea->lpdbOpenInfo = NULL;
return errCode;
}
/* Write fields and eof mark */
if( pArea->bTableType == DB_DBF_VFP )
pBuffer[ nSize - 1 ] = '\r';
else
{
pBuffer[ nSize - 2 ] = '\r';
pBuffer[ nSize - 1 ] = '\0';
}
pBuffer[ nSize ] = '\032';
if( hb_fileWriteAt( pArea->pDataFile, pBuffer, nSize + 1,
sizeof( DBFHEADER ) ) != nSize + 1 )
{
hb_xfree( pBuffer );
hb_dbfErrorRT( pArea, EG_WRITE, EDBF_WRITE, pArea->szDataFileName,
hb_fsError(), 0, NULL );
SELF_CLOSE( &pArea->area );
pArea->lpdbOpenInfo = NULL;
return HB_FAILURE;
}
pArea->fDataFlush = HB_TRUE;
}
hb_xfree( pBuffer );
/* Create memo file */
if( pArea->fHasMemo )
{
pFileName = hb_fsFNameSplit( szFileName );
pFileName->szExtension = NULL;
hb_fsFNameMerge( szFileName, pFileName );
hb_xfree( pFileName );
pCreateInfo->abName = szFileName;
errCode = SELF_CREATEMEMFILE( &pArea->area, pCreateInfo );
}
/* If successful call SUPER_CREATE to finish system jobs */
if( errCode == HB_SUCCESS )
errCode = SUPER_CREATE( &pArea->area, pCreateInfo );
if( errCode != HB_SUCCESS )
{
SELF_CLOSE( &pArea->area );
pArea->lpdbOpenInfo = NULL;
return errCode;
}
/* Alloc buffer */
pArea->pRecord = ( HB_BYTE * ) hb_xgrab( pArea->uiRecordLen );
pArea->fValidBuffer = HB_FALSE;
/* Update the number of record for corrupted headers */
pArea->ulRecCount = hb_dbfCalcRecCount( pArea );
pArea->lpdbOpenInfo = NULL;
/* Position cursor at the first record */
return SELF_GOTOP( &pArea->area );
}
/*
* Retrieve information about the current driver.
*/
static HB_ERRCODE hb_dbfInfo( DBFAREAP pArea, HB_USHORT uiIndex, PHB_ITEM pItem )
{
HB_ERRCODE errCode = HB_SUCCESS;
HB_TRACE( HB_TR_DEBUG, ( "hb_dbfInfo(%p, %hu, %p)", pArea, uiIndex, pItem ) );
switch( uiIndex )
{
case DBI_ISDBF:
case DBI_CANPUTREC:
hb_itemPutL( pItem, HB_TRUE );
break;
case DBI_GETHEADERSIZE:
hb_itemPutNL( pItem, pArea->uiHeaderLen );
break;
case DBI_LASTUPDATE:
hb_itemPutD( pItem, 1900 + pArea->dbfHeader.bYear,
pArea->dbfHeader.bMonth,
pArea->dbfHeader.bDay );
break;
case DBI_GETRECSIZE:
hb_itemPutNL( pItem, pArea->uiRecordLen );
break;
case DBI_GETLOCKARRAY:
hb_dbfGetLockArray( pArea, pItem );
break;
case DBI_TABLEEXT:
hb_itemClear( pItem );
return SELF_RDDINFO( SELF_RDDNODE( &pArea->area ), RDDI_TABLEEXT, 0, pItem );
case DBI_FULLPATH:
hb_itemPutC( pItem, pArea->szDataFileName );
break;
case DBI_MEMOTYPE:
hb_itemPutNI( pItem, DB_MEMO_NONE );
break;
case DBI_TABLETYPE:
if( ! pArea->pDataFile )
{
hb_itemClear( pItem );
return SELF_RDDINFO( SELF_RDDNODE( &pArea->area ), RDDI_TABLETYPE, 0, pItem );
}
hb_itemPutNI( pItem, pArea->bTableType );
break;
case DBI_FILEHANDLE:
hb_itemPutNInt( pItem, ! pArea->pDataFile ? FS_ERROR :
( HB_MAXINT ) ( HB_NHANDLE ) hb_fileHandle( pArea->pDataFile ) );
break;
case DBI_MEMOHANDLE:
hb_itemPutNInt( pItem, ! pArea->pMemoFile ? FS_ERROR :
( HB_MAXINT ) ( HB_NHANDLE ) hb_fileHandle( pArea->pMemoFile ) );
break;
case DBI_SHARED:
{
HB_BOOL fShared = pArea->fShared;
if( HB_IS_LOGICAL( pItem ) )
{
pArea->fShared = hb_itemGetL( pItem );
}
hb_itemPutL( pItem, fShared );
break;
}
case DBI_ISFLOCK:
hb_itemPutL( pItem, pArea->fFLocked );
break;
case DBI_ISREADONLY:
hb_itemPutL( pItem, pArea->fReadonly );
break;
case DBI_ISTEMPORARY:
if( ! pArea->pDataFile && ! pArea->pMemoFile && HB_IS_LOGICAL( pItem ) )
pArea->fTemporary = hb_itemGetL( pItem );
else
hb_itemPutL( pItem, pArea->fTemporary );
break;
case DBI_VALIDBUFFER:
hb_itemPutL( pItem, pArea->fValidBuffer );
break;
case DBI_POSITIONED:
hb_itemPutL( pItem, pArea->fPositioned );
break;
case DBI_ISENCRYPTED:
hb_itemPutL( pItem, pArea->fTableEncrypted );
break;
case DBI_DECRYPT:
hb_dbfTableCrypt( pArea, pItem, HB_FALSE );
hb_itemPutL( pItem, ! pArea->fTableEncrypted );
break;
case DBI_ENCRYPT:
hb_dbfTableCrypt( pArea, pItem, HB_TRUE );
hb_itemPutL( pItem, pArea->fTableEncrypted );
break;
case DBI_LOCKCOUNT:
hb_itemPutNL( pItem, pArea->ulNumLocksPos );
break;
case DBI_LOCKOFFSET:
{
HB_FOFFSET nPos, nFlSize, nRlSize;
int iDir;
hb_dbfLockData( pArea, &nPos, &nFlSize, &nRlSize, &iDir );
hb_itemPutNInt( pItem, nPos );
break;
}
case DBI_LOCKTEST:
if( HB_IS_NUMERIC( pItem ) )
hb_itemPutNI( pItem, hb_dbfLockTest( pArea, REC_LOCK, hb_itemGetNL( pItem ) ) );
else
hb_itemPutNI( pItem, hb_dbfLockTest( pArea, FILE_LOCK, 0 ) );
break;
case DBI_LOCKSCHEME:
{
int iScheme = hb_itemGetNI( pItem );
if( pArea->bLockType )
{
hb_itemPutNI( pItem, pArea->bLockType );
}
else
{
hb_itemClear( pItem );
errCode = SELF_RDDINFO( SELF_RDDNODE( &pArea->area ), RDDI_LOCKSCHEME, 0, pItem );
}
switch( iScheme )
{
case DB_DBFLOCK_CLIPPER:
case DB_DBFLOCK_CLIPPER2:
case DB_DBFLOCK_COMIX:
case DB_DBFLOCK_VFP:
case DB_DBFLOCK_HB32:
#ifndef HB_LONG_LONG_OFF
case DB_DBFLOCK_HB64:
#endif
pArea->bLockType = ( HB_BYTE ) iScheme;
}
break;
}
case DBI_ROLLBACK:
if( pArea->fRecordChanged )
{
if( pArea->fAppend )
{
hb_dbfSetBlankRecord( pArea, HB_BLANK_ROLLBACK );
pArea->fDeleted = HB_FALSE;
}
else
{
pArea->fRecordChanged = pArea->fValidBuffer = HB_FALSE;
}
}
break;
case DBI_PASSWORD:
hb_dbfPasswordSet( pArea, pItem, HB_FALSE );
break;
case DBI_TRIGGER:
if( HB_IS_LOGICAL( pItem ) )
pArea->fTrigger = pArea->pTriggerSym && hb_itemGetL( pItem );
else
{
PHB_DYNS pTriggerSym = pArea->pTriggerSym;
if( HB_IS_STRING( pItem ) )
hb_dbfTriggerSet( pArea, pItem );
hb_itemPutC( pItem, pTriggerSym ? hb_dynsymName( pTriggerSym ) : NULL );
}
break;
case DBI_OPENINFO:
hb_itemPutPtr( pItem, pArea->lpdbOpenInfo );
break;
case DBI_DIRTYREAD:
{
HB_BOOL fDirty = HB_DIRTYREAD( pArea );
if( HB_IS_LOGICAL( pItem ) )
pArea->uiDirtyRead = hb_itemGetL( pItem ) ?
HB_IDXREAD_DIRTY : HB_IDXREAD_CLEAN;
else if( ! HB_IS_NIL( pItem ) )
pArea->uiDirtyRead = HB_IDXREAD_DEFAULT;
hb_itemPutL( pItem, fDirty );
break;
}
case DBI_DB_VERSION:
case DBI_RDD_VERSION:
{
char szBuf[ 64 ];
int iSub = hb_itemGetNI( pItem );
if( iSub == 1 )
hb_snprintf( szBuf, sizeof( szBuf ), "%d.%d (%s)", 0, 1, "DBF" );
else if( iSub == 2 )
hb_snprintf( szBuf, sizeof( szBuf ), "%d.%d (%s:%d)", 0, 1, "DBF", pArea->area.rddID );
/*
hb_snprintf( szBuf, sizeof( szBuf ), "%d.%d (%s:%d)", 0, 1, pArea->pRddNode->szName, pArea->area.rddID );
*/
else
hb_snprintf( szBuf, sizeof( szBuf ), "%d.%d", 0, 1 );
hb_itemPutC( pItem, szBuf );
break;
}
default:
return SUPER_INFO( &pArea->area, uiIndex, pItem );
}
return errCode;
}
static HB_ERRCODE hb_dbfFieldInfo( DBFAREAP pArea, HB_USHORT uiIndex, HB_USHORT uiType, PHB_ITEM pItem )
{
LPFIELD pField;
HB_BOOL fLck;
HB_MAXINT nValue;
int iValue;
HB_TRACE( HB_TR_DEBUG, ( "hb_dbfFieldInfo(%p, %hu, %hu, %p)", pArea, uiIndex, uiType, pItem ) );
if( uiIndex > pArea->area.uiFieldCount )
return HB_FAILURE;
switch( uiType )
{
case DBS_ISNULL:
pField = pArea->area.lpFields + uiIndex - 1;
hb_itemPutL( pItem,
pArea->bTableType == DB_DBF_VFP &&
( pField->uiFlags & HB_FF_NULLABLE ) != 0 &&
hb_dbfGetNullFlag( pArea, pArea->pFieldBits[ uiIndex ].uiNullBit ) );
return HB_SUCCESS;
case DBS_COUNTER:
nValue = 0;
if( hb_dbfIsAutoIncField( pArea->area.lpFields + uiIndex - 1 ) )
{
fLck = HB_FALSE;
if( pArea->fShared && ! pArea->fFLocked && ! pArea->fHeaderLocked )
{
if( SELF_RAWLOCK( &pArea->area, HEADER_LOCK, 0 ) != HB_SUCCESS )
return HB_FAILURE;
fLck = HB_TRUE;
}
if( HB_IS_NUMERIC( pItem ) )
nValue = hb_dbfSetNextValue( pArea, uiIndex - 1,
hb_itemGetNInt( pItem ) );
else
nValue = hb_dbfGetNextValue( pArea, uiIndex - 1, HB_FALSE );
if( fLck )
SELF_RAWLOCK( &pArea->area, HEADER_UNLOCK, 0 );
}
hb_itemPutNInt( pItem, nValue );
return HB_SUCCESS;
case DBS_STEP:
iValue = 0;
if( hb_dbfIsAutoIncField( pArea->area.lpFields + uiIndex - 1 ) )
{
if( HB_IS_NUMERIC( pItem ) )
{
fLck = HB_FALSE;
if( pArea->fShared && ! pArea->fFLocked && ! pArea->fHeaderLocked )
{
if( SELF_RAWLOCK( &pArea->area, HEADER_LOCK, 0 ) != HB_SUCCESS )
return HB_FAILURE;
fLck = HB_TRUE;
}
iValue = hb_dbfAtoincStep( pArea, uiIndex - 1,
hb_itemGetNI( pItem ) );
if( fLck )
SELF_RAWLOCK( &pArea->area, HEADER_UNLOCK, 0 );
}
else
iValue = hb_dbfAtoincStep( pArea, uiIndex - 1, 0 );
}
hb_itemPutNI( pItem, iValue );
return HB_SUCCESS;
default:
return SUPER_FIELDINFO( &pArea->area, uiIndex, uiType, pItem );
}
}
/*
* Retrieve information about a raw
*/
static HB_ERRCODE hb_dbfRecInfo( DBFAREAP pArea, PHB_ITEM pRecID, HB_USHORT uiInfoType, PHB_ITEM pInfo )
{
HB_ULONG ulRecNo = hb_itemGetNL( pRecID ), ulPrevRec = 0;
HB_ERRCODE errResult = HB_SUCCESS;
HB_BOOL bDeleted;
HB_TRACE( HB_TR_DEBUG, ( "hb_dbfRecInfo(%p, %p, %hu, %p)", pArea, pRecID, uiInfoType, pInfo ) );
if( pArea->lpdbPendingRel )
{
if( SELF_FORCEREL( &pArea->area ) != HB_SUCCESS )
return HB_FAILURE;
}
if( ulRecNo == 0 )
{
ulRecNo = pArea->ulRecNo;
}
else if( ulRecNo != pArea->ulRecNo )
{
switch( uiInfoType )
{
case DBRI_DELETED:
case DBRI_ENCRYPTED:
case DBRI_RAWRECORD:
case DBRI_RAWMEMOS:
case DBRI_RAWDATA:
ulPrevRec = pArea->ulRecNo;
errResult = SELF_GOTO( &pArea->area, ulRecNo );
if( errResult != HB_SUCCESS )
return errResult;
break;
}
}
switch( uiInfoType )
{
case DBRI_DELETED:
errResult = SELF_DELETED( &pArea->area, &bDeleted );
if( errResult == HB_SUCCESS )
hb_itemPutL( pInfo, bDeleted );
break;
case DBRI_LOCKED:
/* Clipper also checks only fShared and RLOCK and ignore FLOCK */
hb_itemPutL( pInfo, ! pArea->fShared || /* pArea->fFLocked || */
hb_dbfIsLocked( pArea, ulRecNo ) );
break;
case DBRI_RECSIZE:
hb_itemPutNL( pInfo, pArea->uiRecordLen );
break;
case DBRI_RECNO:
hb_itemPutNInt( pInfo, ulRecNo );
break;
case DBRI_UPDATED:
hb_itemPutL( pInfo, ulRecNo == pArea->ulRecNo && pArea->fRecordChanged );
break;
case DBRI_ENCRYPTED:
if( ! pArea->fValidBuffer && ! hb_dbfReadRecord( pArea ) )
errResult = HB_FAILURE;
else
hb_itemPutL( pInfo, pArea->fEncrypted );
break;
case DBRI_RAWRECORD:
if( ! pArea->fValidBuffer && ! hb_dbfReadRecord( pArea ) )
errResult = HB_FAILURE;
else
hb_itemPutCL( pInfo, ( char * ) pArea->pRecord, pArea->uiRecordLen );
break;
case DBRI_RAWMEMOS:
case DBRI_RAWDATA:
{
HB_USHORT uiFields;
HB_BYTE * pResult;
HB_SIZE nLength, nLen;
if( ! pArea->fValidBuffer && ! hb_dbfReadRecord( pArea ) )
{
errResult = HB_FAILURE;
break;
}
nLength = uiInfoType == DBRI_RAWDATA ? pArea->uiRecordLen : 0;
pResult = ( HB_BYTE * ) hb_xgrab( nLength + 1 );
if( nLength )
{
memcpy( pResult, pArea->pRecord, nLength );
}
if( pArea->fHasMemo )
{
for( uiFields = 0; uiFields < pArea->area.uiFieldCount; uiFields++ )
{
if( pArea->area.lpFields[ uiFields ].uiType == HB_FT_MEMO ||
pArea->area.lpFields[ uiFields ].uiType == HB_FT_IMAGE ||
pArea->area.lpFields[ uiFields ].uiType == HB_FT_BLOB ||
pArea->area.lpFields[ uiFields ].uiType == HB_FT_OLE )
{
errResult = SELF_GETVALUE( &pArea->area, uiFields + 1, pInfo );
if( errResult != HB_SUCCESS )
break;
nLen = hb_itemGetCLen( pInfo );
if( nLen > 0 )
{
pResult = ( HB_BYTE * ) hb_xrealloc( pResult, nLength + nLen + 1 );
memcpy( pResult + nLength, hb_itemGetCPtr( pInfo ), nLen );
nLength += nLen;
}
}
}
}
hb_itemPutCLPtr( pInfo, ( char * ) pResult, nLength );
break;
}
default:
errResult = SUPER_RECINFO( &pArea->area, pRecID, uiInfoType, pInfo );
}
if( ulPrevRec != 0 )
{
if( SELF_GOTO( &pArea->area, ulPrevRec ) != HB_SUCCESS &&
errResult == HB_SUCCESS )
errResult = HB_FAILURE;
}
return errResult;
}
/*
* Clear the WorkArea for use.
*/
static HB_ERRCODE hb_dbfNewArea( DBFAREAP pArea )
{
HB_TRACE( HB_TR_DEBUG, ( "hb_dbfNewArea(%p)", pArea ) );
if( SUPER_NEW( &pArea->area ) == HB_FAILURE )
return HB_FAILURE;
/* set maximum fieldname length to 10 characters */
pArea->area.uiMaxFieldNameLength = 10;
pArea->pDataFile = pArea->pMemoFile = pArea->pMemoTmpFile = NULL;
pArea->fDataFlush = pArea->fMemoFlush = HB_FALSE;
/* Index dirty read flag initialized to global RDD setting */
pArea->uiDirtyRead = HB_IDXREAD_DEFAULT;
/* Size for deleted records flag */
pArea->uiRecordLen = 1;
{
PHB_ITEM pItem = hb_itemPutNI( NULL, 0 );
if( SELF_RDDINFO( SELF_RDDNODE( &pArea->area ), RDDI_TABLETYPE, 0, pItem ) == HB_SUCCESS )
pArea->bTableType = ( HB_BYTE ) hb_itemGetNI( pItem );
hb_itemRelease( pItem );
}
return HB_SUCCESS;
}
/*
* Open a data store in the WorkArea.
*/
static HB_ERRCODE hb_dbfOpen( DBFAREAP pArea, LPDBOPENINFO pOpenInfo )
{
HB_ERRCODE errCode, errOsCode;
HB_USHORT uiFlags, uiFields, uiCount, uiSkip;
HB_SIZE nSize;
HB_BOOL fRawBlob;
PHB_ITEM pError, pItem;
PHB_FNAME pFileName;
HB_BYTE * pBuffer;
LPDBFFIELD pField;
DBFIELDINFO dbFieldInfo;
char szFileName[ HB_PATH_MAX ];
char szAlias[ HB_RDD_MAX_ALIAS_LEN + 1 ];
HB_TRACE( HB_TR_DEBUG, ( "hb_dbfOpen(%p, %p)", pArea, pOpenInfo ) );
pArea->lpdbOpenInfo = pOpenInfo;
pItem = hb_itemNew( NULL );
if( SELF_RDDINFO( SELF_RDDNODE( &pArea->area ), RDDI_PENDINGTRIGGER,
pOpenInfo->ulConnection, pItem ) == HB_SUCCESS )
{
if( HB_IS_STRING( pItem ) )
hb_dbfTriggerSet( pArea, pItem );
}
if( ! pArea->fTrigger )
{
if( SELF_RDDINFO( SELF_RDDNODE( &pArea->area ), RDDI_TRIGGER,
pOpenInfo->ulConnection, pItem ) == HB_SUCCESS )
{
if( HB_IS_STRING( pItem ) )
hb_dbfTriggerSet( pArea, pItem );
}
}
if( pArea->fTrigger )
{
hb_itemPutC( pItem, pOpenInfo->abName );
if( ! hb_dbfTriggerDo( pArea, EVENT_PREUSE, 0, pItem ) )
{
hb_itemRelease( pItem );
pArea->lpdbOpenInfo = NULL;
return HB_FAILURE;
}
hb_strncpy( szFileName, hb_itemGetCPtr( pItem ), sizeof( szFileName ) - 1 );
}
else
hb_strncpy( szFileName, pOpenInfo->abName, sizeof( szFileName ) - 1 );
if( ! pArea->bLockType )
{
hb_itemClear( pItem );
if( SELF_INFO( &pArea->area, DBI_LOCKSCHEME, pItem ) != HB_SUCCESS )
{
hb_itemRelease( pItem );
pArea->lpdbOpenInfo = NULL;
return HB_FAILURE;
}
pArea->bLockType = ( HB_BYTE ) hb_itemGetNI( pItem );
if( ! pArea->bLockType )
pArea->bLockType = DB_DBFLOCK_CLIPPER;
}
if( pOpenInfo->cdpId )
{
pArea->area.cdPage = hb_cdpFindExt( pOpenInfo->cdpId );
if( ! pArea->area.cdPage )
pArea->area.cdPage = hb_vmCDP();
}
else
pArea->area.cdPage = hb_vmCDP();
pArea->fShared = pOpenInfo->fShared;
pArea->fReadonly = pOpenInfo->fReadonly;
/* Force exclusive mode
* 0: AUTOSHARE disabled.
* 1: AUTOSHARE enabled.
* 2: force exclusive mode.
* */
if( hb_setGetAutoShare() == 2 )
pArea->fShared = HB_FALSE;
uiFlags = ( pArea->fReadonly ? FO_READ : FO_READWRITE ) |
( pArea->fShared ? FO_DENYNONE : FO_EXCLUSIVE );
pError = NULL;
pFileName = hb_fsFNameSplit( szFileName );
/* Add default file name extension if necessary */
if( ! pFileName->szExtension && hb_setGetDefExtension() )
{
hb_itemClear( pItem );
if( SELF_INFO( &pArea->area, DBI_TABLEEXT, pItem ) != HB_SUCCESS )
{
hb_xfree( pFileName );
hb_itemRelease( pItem );
pArea->lpdbOpenInfo = NULL;
return HB_FAILURE;
}
pFileName->szExtension = hb_itemGetCPtr( pItem );
hb_fsFNameMerge( szFileName, pFileName );
}
/* Create default alias if necessary */
if( ! pOpenInfo->atomAlias && pFileName->szName )
{
const char * szName = strrchr( pFileName->szName, ':' );
if( szName == NULL )
szName = pFileName->szName;
else
++szName;
hb_strncpyUpperTrim( szAlias, szName, sizeof( szAlias ) - 1 );
pOpenInfo->atomAlias = szAlias;
}
hb_xfree( pFileName );
hb_itemClear( pItem );
fRawBlob = SELF_RDDINFO( SELF_RDDNODE( &pArea->area ), RDDI_BLOB_SUPPORT, pOpenInfo->ulConnection, pItem ) == HB_SUCCESS &&
hb_itemGetL( pItem );
hb_itemRelease( pItem );
if( fRawBlob )
{
uiFields = uiSkip = 0;
pBuffer = NULL;
pArea->fHasMemo = HB_TRUE;
}
else
{
/* Try open */
do
{
pArea->pDataFile = hb_fileExtOpen( szFileName, NULL, uiFlags |
FXO_DEFAULTS | FXO_SHARELOCK |
FXO_COPYNAME | FXO_NOSEEKPOS,
NULL, pError );
if( pArea->pDataFile )
break;
}
while( hb_dbfErrorRT( pArea, EG_OPEN, EDBF_OPEN_DBF, szFileName, hb_fsError(),
EF_CANRETRY | EF_CANDEFAULT, &pError ) == E_RETRY );
if( pError )
{
hb_itemRelease( pError );
pError = NULL;
}
/* Exit if error */
if( ! pArea->pDataFile )
{
SELF_CLOSE( &pArea->area );
pArea->lpdbOpenInfo = NULL;
return HB_FAILURE;
}
/* Allocate only after succesfully open file */
pArea->szDataFileName = hb_strdup( szFileName );
/* Read file header and exit if error */
errCode = SELF_READDBHEADER( &pArea->area );
if( errCode != HB_SUCCESS )
{
SELF_CLOSE( &pArea->area );
pArea->lpdbOpenInfo = NULL;
return errCode;
}
/* Add fields */
uiSkip = 0;
uiFields = ( pArea->uiHeaderLen - sizeof( DBFHEADER ) ) / sizeof( DBFFIELD );
nSize = ( HB_SIZE ) uiFields * sizeof( DBFFIELD );
pBuffer = uiFields ? ( HB_BYTE * ) hb_xgrab( nSize ) : NULL;
/* Read fields and exit if error */
do
{
if( hb_fileReadAt( pArea->pDataFile, pBuffer, nSize,
sizeof( DBFHEADER ) ) == nSize )
{
errCode = HB_SUCCESS;
break;
}
errOsCode = hb_fsError();
errCode = HB_FAILURE;
}
while( hb_dbfErrorRT( pArea, errOsCode == 0 ? EG_CORRUPTION : EG_READ,
errOsCode == 0 ? EDBF_CORRUPT : EDBF_READ,
pArea->szDataFileName, errOsCode,
EF_CANRETRY | EF_CANDEFAULT, &pError ) == E_RETRY );
if( pError )
hb_itemRelease( pError );
/* Exit if error */
if( errCode != HB_SUCCESS )
{
if( pBuffer )
hb_xfree( pBuffer );
SELF_CLOSE( &pArea->area );
pArea->lpdbOpenInfo = NULL;
return errCode;
}
/* some RDDs use the additional space in the header after field arrray
for private data we should check for 0x0D marker to not use this
data as fields description */
for( uiCount = 0; uiCount < uiFields; uiCount++ )
{
pField = ( LPDBFFIELD ) ( pBuffer + uiCount * sizeof( DBFFIELD ) );
if( pField->bName[ 0 ] == 0x0d )
{
uiFields = uiCount;
break;
}
else if( pArea->bTableType == DB_DBF_VFP &&
pField->bFieldFlags & 0x01 )
{
uiSkip++;
}
}
uiFields -= uiSkip;
}
/* CL5.3 allow to create and open DBFs without fields */
#ifdef HB_CLP_STRICT
if( uiFields == 0 )
{
errCode = HB_FAILURE;
}
else
#endif
{
errCode = SELF_SETFIELDEXTENT( &pArea->area, uiFields );
if( errCode != HB_SUCCESS )
{
SELF_CLOSE( &pArea->area );
pArea->lpdbOpenInfo = NULL;
return errCode;
}
}
/* Clear dbFieldInfo structure */
memset( &dbFieldInfo, 0, sizeof( dbFieldInfo ) );
/* Size for deleted flag */
pArea->uiRecordLen = 1;
pArea->uiNullCount = 0;
for( uiCount = 0; uiCount < uiFields + uiSkip; uiCount++ )
{
pField = ( LPDBFFIELD ) ( pBuffer + uiCount * sizeof( DBFFIELD ) );
pField->bName[ 10 ] = '\0';
/* hb_strupp( ( char * ) pField->bName ); */
dbFieldInfo.atomName = ( const char * ) pField->bName;
dbFieldInfo.uiLen = pField->bLen;
dbFieldInfo.uiDec = 0;
dbFieldInfo.uiTypeExtended = 0;
/* We cannot accept bFieldFlags as is because Clipper
* creates tables where this field is random so we have to
* try to guess the flags ourself. But if we know that table
* was created by VFP which uses field flags then we can
* retrive information from bFieldFlags.
*/
if( pArea->bTableType == DB_DBF_VFP )
dbFieldInfo.uiFlags = pField->bFieldFlags;
else
dbFieldInfo.uiFlags = 0;
switch( pField->bType )
{
case 'C':
dbFieldInfo.uiType = HB_FT_STRING;
dbFieldInfo.uiLen = pField->bLen + pField->bDec * 256;
break;
case 'L':
dbFieldInfo.uiType = HB_FT_LOGICAL;
dbFieldInfo.uiLen = 1;
break;
case 'D':
dbFieldInfo.uiType = HB_FT_DATE;
if( dbFieldInfo.uiLen != 3 && dbFieldInfo.uiLen != 4 )
dbFieldInfo.uiLen = 8;
break;
case 'I':
dbFieldInfo.uiType = HB_FT_INTEGER;
if( ( dbFieldInfo.uiLen > 4 && dbFieldInfo.uiLen != 8 ) ||
dbFieldInfo.uiLen == 0 )
dbFieldInfo.uiLen = 4;
dbFieldInfo.uiDec = pField->bDec;
break;
case 'Y':
dbFieldInfo.uiType = HB_FT_CURRENCY;
if( ( dbFieldInfo.uiLen > 4 && dbFieldInfo.uiLen != 8 ) ||
dbFieldInfo.uiLen == 0 )
dbFieldInfo.uiLen = 8;
dbFieldInfo.uiDec = pField->bDec;
break;
case '2':
case '4':
dbFieldInfo.uiType = HB_FT_INTEGER;
dbFieldInfo.uiLen = pField->bType - '0';
break;
case 'N':
dbFieldInfo.uiType = HB_FT_LONG;
dbFieldInfo.uiDec = pField->bDec;
/* DBASE documentation defines maximum numeric field size as 20
* but Clipper allows to create longer fields so I removed this
* limit, Druzus
*/
#if 0
if( pField->bLen > 20 )
errCode = HB_FAILURE;
#endif
break;
case 'F':
dbFieldInfo.uiType = HB_FT_FLOAT;
dbFieldInfo.uiDec = pField->bDec;
/* See note above */
break;
case '8':
case 'B':
dbFieldInfo.uiType = HB_FT_DOUBLE;
dbFieldInfo.uiDec = pField->bDec;
if( dbFieldInfo.uiLen != 8 )
errCode = HB_FAILURE;
break;
/* types which are not supported by VM - mapped to different ones */
case 'T':
if( dbFieldInfo.uiLen == 8 )
dbFieldInfo.uiType = HB_FT_TIMESTAMP;
else if( dbFieldInfo.uiLen == 4 )
dbFieldInfo.uiType = HB_FT_TIME;
else
errCode = HB_FAILURE;
break;
case '@':
dbFieldInfo.uiType = HB_FT_TIMESTAMP;
if( dbFieldInfo.uiLen != 8 )
errCode = HB_FAILURE;
break;
case '=':
dbFieldInfo.uiType = HB_FT_MODTIME;
if( dbFieldInfo.uiLen != 8 )
errCode = HB_FAILURE;
pArea->fModStamp = HB_TRUE;
break;
case '^':
dbFieldInfo.uiType = HB_FT_ROWVER;
if( dbFieldInfo.uiLen != 8 )
errCode = HB_FAILURE;
pArea->fModStamp = HB_TRUE;
break;
case '+':
dbFieldInfo.uiType = HB_FT_AUTOINC;
if( dbFieldInfo.uiLen != 4 )
errCode = HB_FAILURE;
pArea->fAutoInc = HB_TRUE;
break;
case 'Q':
dbFieldInfo.uiType = HB_FT_VARLENGTH;
if( pArea->bTableType == DB_DBF_VFP )
dbFieldInfo.uiFlags |= HB_FF_BINARY;
else
dbFieldInfo.uiFlags |= HB_FF_BINARY & pField->bFieldFlags;
hb_dbfAllocNullFlag( pArea, uiCount, HB_TRUE );
break;
case 'V':
if( pArea->bTableType == DB_DBF_VFP )
{
dbFieldInfo.uiType = HB_FT_VARLENGTH;
/* dbFieldInfo.uiFlags &= ~HB_FF_BINARY; */
hb_dbfAllocNullFlag( pArea, uiCount, HB_TRUE );
}
else
{
dbFieldInfo.uiType = HB_FT_ANY;
if( dbFieldInfo.uiLen >= 6 )
{
pArea->uiMemoVersion = DB_MEMOVER_SIX;
pArea->fHasMemo = HB_TRUE;
}
}
break;
case 'M':
dbFieldInfo.uiType = HB_FT_MEMO;
pArea->fHasMemo = HB_TRUE;
break;
case 'P':
dbFieldInfo.uiType = HB_FT_IMAGE;
dbFieldInfo.uiFlags |= HB_FF_BINARY;
pArea->fHasMemo = HB_TRUE;
break;
case 'W':
dbFieldInfo.uiType = HB_FT_BLOB;
dbFieldInfo.uiFlags |= HB_FF_BINARY;
pArea->fHasMemo = HB_TRUE;
break;
case 'G':
dbFieldInfo.uiType = HB_FT_OLE;
dbFieldInfo.uiFlags |= HB_FF_BINARY;
pArea->fHasMemo = HB_TRUE;
break;
case '\x1A':
dbFieldInfo.uiType = HB_FT_STRING;
dbFieldInfo.uiFlags |= HB_FF_UNICODE;
dbFieldInfo.uiLen = ( pField->bLen + pField->bDec * 256 ) >> 1;
break;
case '\x1B':
dbFieldInfo.uiType = HB_FT_VARLENGTH;
dbFieldInfo.uiFlags |= HB_FF_UNICODE;
dbFieldInfo.uiLen = ( ( pField->bLen + pField->bDec * 256 ) >> 1 ) - 1;
break;
case '\x1C':
dbFieldInfo.uiType = HB_FT_MEMO;
dbFieldInfo.uiFlags |= HB_FF_UNICODE;
pArea->fHasMemo = HB_TRUE;
break;
case '0':
if( /* pArea->bTableType == DB_DBF_VFP && */
( pField->bFieldFlags & HB_FF_HIDDEN ) != 0 )
{
if( memcmp( dbFieldInfo.atomName, "_NullFlags", 10 ) == 0 )
pArea->uiNullOffset = pArea->uiRecordLen;
pArea->uiRecordLen += dbFieldInfo.uiLen;
if( pArea->uiRecordLen >= dbFieldInfo.uiLen )
continue;
}
default:
errCode = HB_FAILURE;
break;
}
if( errCode == HB_SUCCESS )
{
if( pArea->bTableType == DB_DBF_VFP &&
( pField->bFieldFlags & HB_FF_NULLABLE ) != 0 )
{
hb_dbfAllocNullFlag( pArea, uiCount, HB_FALSE );
}
/* Add field */
errCode = SELF_ADDFIELD( &pArea->area, &dbFieldInfo );
}
/* Exit if error */
if( errCode != HB_SUCCESS )
break;
}
if( pBuffer )
hb_xfree( pBuffer );
/* Exit if error */
if( errCode != HB_SUCCESS )
{
hb_dbfErrorRT( pArea, EG_CORRUPTION, EDBF_CORRUPT, pArea->szDataFileName,
0, EF_CANDEFAULT, NULL );
SELF_CLOSE( &pArea->area );
pArea->lpdbOpenInfo = NULL;
return errCode;
}
pItem = hb_itemNew( NULL );
if( SELF_RDDINFO( SELF_RDDNODE( &pArea->area ), RDDI_PENDINGPASSWORD,
pOpenInfo->ulConnection, pItem ) == HB_SUCCESS )
{
hb_dbfPasswordSet( pArea, pItem, HB_FALSE );
}
else
{
hb_itemClear( pItem );
if( SELF_RDDINFO( SELF_RDDNODE( &pArea->area ), RDDI_PASSWORD,
pOpenInfo->ulConnection, pItem ) == HB_SUCCESS )
{
hb_dbfPasswordSet( pArea, pItem, HB_FALSE );
}
}
hb_itemRelease( pItem );
/* Open memo file if exists */
if( pArea->fHasMemo )
{
pFileName = hb_fsFNameSplit( szFileName );
pFileName->szExtension = NULL;
hb_fsFNameMerge( szFileName, pFileName );
hb_xfree( pFileName );
pOpenInfo->abName = szFileName;
errCode = SELF_OPENMEMFILE( &pArea->area, pOpenInfo );
}
if( errCode == HB_SUCCESS )
{
/* If successful call SUPER_OPEN to finish system jobs */
errCode = SUPER_OPEN( &pArea->area, pOpenInfo );
}
if( errCode != HB_SUCCESS )
{
SELF_CLOSE( &pArea->area );
pArea->lpdbOpenInfo = NULL;
return HB_FAILURE;
}
/* Alloc buffer */
pArea->pRecord = ( HB_BYTE * ) hb_xgrab( pArea->uiRecordLen );
pArea->fValidBuffer = HB_FALSE;
/* Update the number of record for corrupted headers */
pArea->ulRecCount = hb_dbfCalcRecCount( pArea );
/* Position cursor at the first record */
errCode = SELF_GOTOP( &pArea->area );
if( pArea->fTrigger )
hb_dbfTriggerDo( pArea, EVENT_POSTUSE, 0, NULL );
pArea->lpdbOpenInfo = NULL;
return errCode;
}
#define hb_dbfRelease NULL
/*
* Retrieve the size of the WorkArea structure.
*/
static HB_ERRCODE hb_dbfStructSize( DBFAREAP pArea, HB_USHORT * uiSize )
{
HB_TRACE( HB_TR_DEBUG, ( "hb_dbfStrucSize(%p, %p)", pArea, uiSize ) );
HB_SYMBOL_UNUSED( pArea );
*uiSize = sizeof( DBFAREA );
return HB_SUCCESS;
}
#define hb_dbfSysName NULL
#define hb_dbfEval NULL
/*
* Pack helper function called for each packed record
*/
static HB_ERRCODE hb_dbfPackRec( DBFAREAP pArea, HB_ULONG ulRecNo, HB_BOOL * fWritten )
{
HB_TRACE( HB_TR_DEBUG, ( "hb_dbfPackRec(%p, %lu, %p)", pArea, ulRecNo, fWritten ) );
HB_SYMBOL_UNUSED( ulRecNo );
*fWritten = ! pArea->fDeleted;
return HB_SUCCESS;
}
/*
* Remove records marked for deletion from a database.
*/
static HB_ERRCODE hb_dbfPack( DBFAREAP pArea )
{
HB_ULONG ulRecIn, ulRecOut, ulEvery, ulUserEvery;
PHB_ITEM pBlock;
HB_BOOL fWritten;
HB_TRACE( HB_TR_DEBUG, ( "hb_dbfPack(%p)", pArea ) );
if( pArea->fReadonly )
{
hb_dbfErrorRT( pArea, EG_READONLY, EDBF_READONLY, NULL, 0, 0, NULL );
return HB_FAILURE;
}
if( pArea->fShared )
{
hb_dbfErrorRT( pArea, EG_SHARED, EDBF_SHARED, NULL, 0, 0, NULL );
return HB_FAILURE;
}
if( pArea->fTrigger )
{
if( ! hb_dbfTriggerDo( pArea, EVENT_PACK, 0, NULL ) )
return HB_FAILURE;
}
if( SELF_GOCOLD( &pArea->area ) != HB_SUCCESS )
return HB_FAILURE;
/* This is bad hack but looks that people begins to use it :-(
* so I'll add workaround to make it m ore safe
*/
if( pArea->area.valResult && HB_IS_ARRAY( pArea->area.valResult ) &&
hb_arrayLen( pArea->area.valResult ) == 2 &&
( hb_arrayGetType( pArea->area.valResult, 1 ) & HB_IT_BLOCK ) != 0 &&
( hb_arrayGetType( pArea->area.valResult, 2 ) & HB_IT_NUMERIC ) != 0 )
{
pBlock = hb_itemNew( NULL );
hb_arrayGet( pArea->area.valResult, 1, pBlock );
if( hb_arrayGetND( pArea->area.valResult, 2 ) >= 1 )
ulUserEvery = hb_arrayGetNL( pArea->area.valResult, 2 );
else
ulUserEvery = 1;
}
else
{
pBlock = NULL;
ulUserEvery = 0;
}
ulRecOut = ulEvery = 0;
ulRecIn = 1;
while( ulRecIn <= pArea->ulRecCount )
{
if( SELF_GOTO( &pArea->area, ulRecIn ) != HB_SUCCESS )
{
if( pBlock )
hb_itemRelease( pBlock );
return HB_FAILURE;
}
if( ! hb_dbfReadRecord( pArea ) )
{
if( pBlock )
hb_itemRelease( pBlock );
return HB_FAILURE;
}
/* Execute the Code Block */
if( pBlock )
{
if( ++ulEvery >= ulUserEvery )
{
ulEvery = 0;
if( SELF_EVALBLOCK( &pArea->area, pBlock ) != HB_SUCCESS )
{
hb_itemRelease( pBlock );
return HB_FAILURE;
}
}
}
if( SELF_PACKREC( &pArea->area, ulRecOut + 1, &fWritten ) != HB_SUCCESS )
{
if( pBlock )
hb_itemRelease( pBlock );
return HB_FAILURE;
}
if( fWritten )
{
ulRecOut++;
if( pArea->ulRecNo != ulRecOut || pArea->fRecordChanged )
{
pArea->ulRecNo = ulRecOut;
pArea->fRecordChanged = HB_TRUE;
if( ! hb_dbfWriteRecord( pArea ) )
{
if( pBlock )
hb_itemRelease( pBlock );
return HB_FAILURE;
}
}
}
ulRecIn++;
}
/* Execute the Code Block for pending record */
if( pBlock )
{
if( ulEvery > 0 )
{
if( SELF_EVALBLOCK( &pArea->area, pBlock ) != HB_SUCCESS )
{
hb_itemRelease( pBlock );
return HB_FAILURE;
}
}
hb_itemRelease( pBlock );
}
if( pArea->ulRecCount != ulRecOut )
{
pArea->ulRecCount = ulRecOut;
/* Force write new header */
pArea->fUpdateHeader = HB_TRUE;
if( SELF_WRITEDBHEADER( &pArea->area ) != HB_SUCCESS )
return HB_FAILURE;
}
return SELF_GOTO( &pArea->area, 1 );
}
void hb_dbfTranslateRec( DBFAREAP pArea, HB_BYTE * pBuffer, PHB_CODEPAGE cdp_src, PHB_CODEPAGE cdp_dest )
{
char * pTmpBuf = NULL;
HB_SIZE nLen;
LPFIELD pField;
HB_USHORT uiIndex;
for( uiIndex = 0, pField = pArea->area.lpFields; uiIndex < pArea->area.uiFieldCount; uiIndex++, pField++ )
{
if( ( pField->uiFlags & ( HB_FF_BINARY | HB_FF_UNICODE ) ) == 0 &&
( pField->uiType == HB_FT_STRING || pField->uiType == HB_FT_VARLENGTH ) )
{
if( pTmpBuf == NULL )
pTmpBuf = ( char * ) hb_xgrab( pArea->uiRecordLen );
nLen = pField->uiLen;
hb_cdpnDup2( ( char * ) pBuffer + pArea->pFieldOffset[ uiIndex ], nLen,
pTmpBuf, &nLen, cdp_src, cdp_dest );
memcpy( pBuffer + pArea->pFieldOffset[ uiIndex ], pTmpBuf, nLen );
if( pField->uiType == HB_FT_STRING )
{
if( nLen < ( HB_SIZE ) pField->uiLen )
memset( pBuffer + pArea->pFieldOffset[ uiIndex ] + nLen,
' ', pField->uiLen - nLen );
}
else
{
if( nLen < ( HB_SIZE ) pField->uiLen )
{
pBuffer[ pArea->pFieldOffset[ uiIndex ] + pField->uiLen - 1 ] = ( HB_BYTE ) nLen;
hb_dbfSetNullFlag( pBuffer, pArea->uiNullOffset, pArea->pFieldBits[ uiIndex ].uiLengthBit );
}
else
hb_dbfClearNullFlag( pBuffer, pArea->uiNullOffset, pArea->pFieldBits[ uiIndex ].uiLengthBit );
}
}
}
if( pTmpBuf != NULL )
hb_xfree( pTmpBuf );
}
/*
* Physically reorder a database.
*/
static HB_ERRCODE hb_dbfSort( DBFAREAP pArea, LPDBSORTINFO pSortInfo )
{
HB_ULONG ulRecNo;
HB_USHORT uiCount;
HB_BOOL bMoreRecords, bLimited, bValidRecord;
HB_ERRCODE errCode;
DBQUICKSORT dbQuickSort;
HB_BYTE * pBuffer;
HB_TRACE( HB_TR_DEBUG, ( "hb_dbfSort(%p, %p)", pArea, pSortInfo ) );
if( SELF_GOCOLD( &pArea->area ) != HB_SUCCESS )
return HB_FAILURE;
if( ! hb_dbQSortInit( &dbQuickSort, pSortInfo, pArea->uiRecordLen ) )
return HB_FAILURE;
errCode = HB_SUCCESS;
uiCount = 0;
pBuffer = dbQuickSort.pBuffer;
ulRecNo = 1;
if( pSortInfo->dbtri.dbsci.itmRecID )
{
errCode = SELF_GOTOID( &pArea->area, pSortInfo->dbtri.dbsci.itmRecID );
bMoreRecords = bLimited = HB_TRUE;
}
else if( pSortInfo->dbtri.dbsci.lNext )
{
ulRecNo = hb_itemGetNL( pSortInfo->dbtri.dbsci.lNext );
bLimited = HB_TRUE;
bMoreRecords = ( ulRecNo > 0 );
}
else
{
if( ! pSortInfo->dbtri.dbsci.itmCobWhile &&
( ! pSortInfo->dbtri.dbsci.fRest ||
! hb_itemGetLX( pSortInfo->dbtri.dbsci.fRest ) ) )
errCode = SELF_GOTOP( &pArea->area );
bMoreRecords = HB_TRUE;
bLimited = HB_FALSE;
}
while( errCode == HB_SUCCESS && ! pArea->area.fEof && bMoreRecords )
{
if( pSortInfo->dbtri.dbsci.itmCobWhile )
{
if( SELF_EVALBLOCK( &pArea->area, pSortInfo->dbtri.dbsci.itmCobWhile ) != HB_SUCCESS )
{
hb_dbQSortExit( &dbQuickSort );
return HB_FAILURE;
}
bMoreRecords = hb_itemGetLX( pArea->area.valResult );
}
if( bMoreRecords && pSortInfo->dbtri.dbsci.itmCobFor )
{
if( SELF_EVALBLOCK( &pArea->area, pSortInfo->dbtri.dbsci.itmCobFor ) != HB_SUCCESS )
{
hb_dbQSortExit( &dbQuickSort );
return HB_FAILURE;
}
bValidRecord = hb_itemGetLX( pArea->area.valResult );
}
else
bValidRecord = bMoreRecords;
if( bValidRecord )
{
if( uiCount == dbQuickSort.uiMaxRecords )
{
if( ! hb_dbQSortAdvance( &dbQuickSort, uiCount ) )
{
hb_dbQSortExit( &dbQuickSort );
return HB_FAILURE;
}
pBuffer = dbQuickSort.pBuffer;
uiCount = 0;
}
/* Read record */
if( ! pArea->fValidBuffer && ! hb_dbfReadRecord( pArea ) )
{
hb_dbQSortExit( &dbQuickSort );
return HB_FAILURE;
}
/* Copy data */
memcpy( pBuffer, pArea->pRecord, pArea->uiRecordLen );
if( pArea->area.cdPage != hb_vmCDP() )
{
hb_dbfTranslateRec( pArea, pBuffer, pArea->area.cdPage, hb_vmCDP() );
}
pBuffer += pArea->uiRecordLen;
uiCount++;
}
if( bMoreRecords && bLimited )
bMoreRecords = ( --ulRecNo > 0 );
if( bMoreRecords )
errCode = SELF_SKIP( &pArea->area, 1 );
}
/* Copy last records */
if( uiCount > 0 )
{
if( ! hb_dbQSortAdvance( &dbQuickSort, uiCount ) )
{
hb_dbQSortExit( &dbQuickSort );
return HB_FAILURE;
}
}
/* Sort records */
hb_dbQSortComplete( &dbQuickSort );
return HB_SUCCESS;
}
/*
* Copy one or more records from one WorkArea to another.
*/
static HB_ERRCODE hb_dbfTrans( DBFAREAP pArea, LPDBTRANSINFO pTransInfo )
{
HB_TRACE( HB_TR_DEBUG, ( "hb_dbfTrans(%p, %p)", pArea, pTransInfo ) );
if( pTransInfo->uiFlags & DBTF_MATCH )
{
if( pArea->fHasMemo || pArea->area.cdPage != pTransInfo->lpaDest->cdPage )
pTransInfo->uiFlags &= ~DBTF_PUTREC;
else if( pArea->area.rddID == pTransInfo->lpaDest->rddID )
pTransInfo->uiFlags |= DBTF_PUTREC;
else
{
PHB_ITEM pPutRec = hb_itemPutL( NULL, HB_FALSE );
if( SELF_INFO( pTransInfo->lpaDest, DBI_CANPUTREC, pPutRec ) != HB_SUCCESS )
{
hb_itemRelease( pPutRec );
return HB_FAILURE;
}
if( hb_itemGetL( pPutRec ) )
pTransInfo->uiFlags |= DBTF_PUTREC;
else
pTransInfo->uiFlags &= ~DBTF_PUTREC;
hb_itemRelease( pPutRec );
}
}
return SUPER_TRANS( &pArea->area, pTransInfo );
}
#define hb_dbfTransRec NULL
/*
* Physically remove all records from data store.
*/
static HB_ERRCODE hb_dbfZap( DBFAREAP pArea )
{
HB_USHORT uiField;
HB_TRACE( HB_TR_DEBUG, ( "hb_dbfZap(%p)", pArea ) );
if( pArea->fReadonly )
{
hb_dbfErrorRT( pArea, EG_READONLY, EDBF_READONLY, NULL, 0, 0, NULL );
return HB_FAILURE;
}
if( pArea->fShared )
{
hb_dbfErrorRT( pArea, EG_SHARED, EDBF_SHARED, NULL, 0, 0, NULL );
return HB_FAILURE;
}
if( pArea->fTrigger )
{
if( ! hb_dbfTriggerDo( pArea, EVENT_ZAP, 0, NULL ) )
return HB_FAILURE;
}
if( SELF_GOCOLD( &pArea->area ) != HB_SUCCESS )
return HB_FAILURE;
pArea->fUpdateHeader = HB_TRUE;
pArea->ulRecCount = 0;
if( SELF_WRITEDBHEADER( &pArea->area ) != HB_SUCCESS )
return HB_FAILURE;
if( SELF_GOTO( &pArea->area, 0 ) != HB_SUCCESS )
return HB_FAILURE;
/* reset autoincrement and row version fields */
for( uiField = 0; uiField < pArea->area.uiFieldCount; uiField++ )
{
if( hb_dbfIsAutoIncField( &pArea->area.lpFields[ uiField ] ) )
hb_dbfSetNextValue( pArea, uiField, 1 );
else if( pArea->area.lpFields[ uiField ].uiType == HB_FT_ROWVER )
hb_dbfSetRowVer( pArea, uiField, 0 );
}
/* Zap memo file */
if( pArea->fHasMemo )
{
if( SELF_CREATEMEMFILE( &pArea->area, NULL ) != HB_SUCCESS )
return HB_FAILURE;
}
return HB_SUCCESS;
}
/*
* Report end of relation.
*/
static HB_ERRCODE hb_dbfChildEnd( DBFAREAP pArea, LPDBRELINFO pRelInfo )
{
HB_ERRCODE errCode;
HB_TRACE( HB_TR_DEBUG, ( "hb_dbfChildEnd(%p, %p)", pArea, pRelInfo ) );
if( pArea->lpdbPendingRel == pRelInfo )
errCode = SELF_FORCEREL( &pArea->area );
else
errCode = HB_SUCCESS;
SUPER_CHILDEND( &pArea->area, pRelInfo );
return errCode;
}
/*
* Report initialization of a relation.
*/
static HB_ERRCODE hb_dbfChildStart( DBFAREAP pArea, LPDBRELINFO pRelInfo )
{
HB_TRACE( HB_TR_DEBUG, ( "hb_dbfChildStart(%p, %p)", pArea, pRelInfo ) );
if( SELF_CHILDSYNC( &pArea->area, pRelInfo ) != HB_SUCCESS )
return HB_FAILURE;
return SUPER_CHILDSTART( &pArea->area, pRelInfo );
}
/*
* Post a pending relational movement.
*/
static HB_ERRCODE hb_dbfChildSync( DBFAREAP pArea, LPDBRELINFO pRelInfo )
{
HB_TRACE( HB_TR_DEBUG, ( "hb_dbfChildSync(%p, %p)", pArea, pRelInfo ) );
/*
* !!! The side effect of calling GOCOLD() inside CHILDSYNC() is
* evaluation of index expressions (index KEY and FOR condition)
* when the pArea is not the current one - it means that the
* used RDD has to set proper work area before eval.
* IMHO GOCOLD() could be safely removed from this place but I'm not
* sure it's Clipper compatible - I will have to check it, Druzus.
*/
/*
* I've checked in CL5.3 Technical Reference Guide that only
* FORCEREL() should ensure that the work area buffer is not HOT
* and then call RELEVAL() - I hope it describes the CL5.3 DBF* RDDs
* behavior so I replicate it - the GOCOLD() is moved from CHILDSYNC()
* to FORCEREL(), Druzus.
*/
/*
* After some cleanups, the core DBF* code can work with GOCOLD() here
* and in FORCEREL() without any problems. Because calling GOCOLD() in
* FORCEREL() may interacts with badly written users RDD which inherits
* from DBF* RDDs and/or user triggers then I decided to keep it here,
* Druzus.
*/
if( SELF_GOCOLD( &pArea->area ) != HB_SUCCESS )
return HB_FAILURE;
pArea->lpdbPendingRel = pRelInfo;
if( pArea->area.lpdbRelations )
return SELF_SYNCCHILDREN( &pArea->area );
return HB_SUCCESS;
}
#define hb_dbfSyncChildren NULL
#define hb_dbfClearRel NULL
/*
* Force relational seeks in the specified WorkArea.
*/
static HB_ERRCODE hb_dbfForceRel( DBFAREAP pArea )
{
HB_TRACE( HB_TR_DEBUG, ( "hb_dbfForceRel(%p)", pArea ) );
if( pArea->lpdbPendingRel )
{
LPDBRELINFO lpdbPendingRel;
lpdbPendingRel = pArea->lpdbPendingRel;
pArea->lpdbPendingRel = NULL;
/* update buffers */
/* commented out - see comment above in CHILDSYNC() method, Druzus */
/* SELF_GOCOLD( &pArea->area ); */
return SELF_RELEVAL( &pArea->area, lpdbPendingRel );
}
return HB_SUCCESS;
}
#define hb_dbfRelArea NULL
#define hb_dbfRelEval NULL
#define hb_dbfRelText NULL
#define hb_dbfSetRel NULL
#define hb_dbfOrderListAdd NULL
#define hb_dbfOrderListClear NULL
#define hb_dbfOrderListDelete NULL
#define hb_dbfOrderListFocus NULL
#define hb_dbfOrderListRebuild NULL
#define hb_dbfOrderCondition NULL
#define hb_dbfOrderCreate NULL
#define hb_dbfOrderDestroy NULL
#define hb_dbfOrderInfo NULL
/*
* Clear the filter condition for the specified WorkArea.
*/
static HB_ERRCODE hb_dbfClearFilter( DBFAREAP pArea )
{
HB_TRACE( HB_TR_DEBUG, ( "hb_dbfClearFilter(%p)", pArea ) );
if( pArea->lpdbPendingRel )
SELF_FORCEREL( &pArea->area );
return SUPER_CLEARFILTER( &pArea->area );
}
#define hb_dbfClearLocate NULL
#define hb_dbfClearScope NULL
#define hb_dbfCountScope NULL
#define hb_dbfFilterText NULL
#define hb_dbfScopeInfo NULL
/*
* Set the filter condition for the specified WorkArea.
*/
static HB_ERRCODE hb_dbfSetFilter( DBFAREAP pArea, LPDBFILTERINFO pFilterInfo )
{
HB_TRACE( HB_TR_DEBUG, ( "hb_dbfSetFilter(%p, %p)", pArea, pFilterInfo ) );
if( pArea->lpdbPendingRel )
SELF_FORCEREL( &pArea->area );
return SUPER_SETFILTER( &pArea->area, pFilterInfo );
}
#define hb_dbfSetLocate NULL
#define hb_dbfSetScope NULL
#define hb_dbfSkipScope NULL
#define hb_dbfLocate NULL
#define hb_dbfCompile NULL
#define hb_dbfError NULL
#define hb_dbfEvalBlock NULL
/*
* Perform a network lowlevel lock in the specified WorkArea.
*/
static HB_ERRCODE hb_dbfRawLock( DBFAREAP pArea, HB_USHORT uiAction, HB_ULONG ulRecNo )
{
HB_ERRCODE errCode = HB_SUCCESS;
HB_FOFFSET nPos, nFlSize, nRlSize;
int iDir;
HB_BOOL fLck;
HB_TRACE( HB_TR_DEBUG, ( "hb_dbfRawLock(%p, %hu, %lu)", pArea, uiAction, ulRecNo ) );
if( pArea->fShared )
{
if( hb_dbfLockData( pArea, &nPos, &nFlSize, &nRlSize, &iDir ) == HB_FAILURE )
return HB_FAILURE;
switch( uiAction )
{
case FILE_LOCK:
if( ! pArea->fFLocked )
{
if( iDir < 0 )
nPos -= nFlSize;
else
nPos++;
fLck = hb_fileLock( pArea->pDataFile, nPos, nFlSize, FL_LOCK );
if( ! fLck )
errCode = HB_FAILURE;
else
pArea->fFLocked = HB_TRUE;
}
break;
case FILE_UNLOCK:
if( pArea->fFLocked )
{
if( iDir < 0 )
nPos -= nFlSize;
else
nPos++;
fLck = hb_fileLock( pArea->pDataFile, nPos, nFlSize, FL_UNLOCK );
if( ! fLck )
errCode = HB_FAILURE;
pArea->fFLocked = HB_FALSE;
}
break;
case REC_LOCK:
if( ! pArea->fFLocked )
{
if( iDir < 0 )
nPos -= ulRecNo;
else if( iDir == 2 )
nPos += ( ulRecNo - 1 ) * pArea->uiRecordLen + pArea->uiHeaderLen;
else
nPos += ulRecNo;
fLck = hb_fileLock( pArea->pDataFile, nPos, nRlSize, FL_LOCK );
if( ! fLck )
errCode = HB_FAILURE;
}
break;
case REC_UNLOCK:
if( ! pArea->fFLocked )
{
if( iDir < 0 )
nPos -= ulRecNo;
else if( iDir == 2 )
nPos += ( ulRecNo - 1 ) * pArea->uiRecordLen + pArea->uiHeaderLen;
else
nPos += ulRecNo;
fLck = hb_fileLock( pArea->pDataFile, nPos, nRlSize, FL_UNLOCK );
if( ! fLck )
errCode = HB_FAILURE;
}
break;
case APPEND_LOCK:
case HEADER_LOCK:
if( ! pArea->fHeaderLocked )
{
for( ;; )
{
fLck = hb_fileLock( pArea->pDataFile, nPos, 1, FL_LOCK | FLX_WAIT );
/* TODO: call special error handler (LOCKHANDLER) if ! fLck */
if( fLck )
break;
hb_releaseCPU();
}
if( ! fLck )
errCode = HB_FAILURE;
else
pArea->fHeaderLocked = HB_TRUE;
}
break;
case APPEND_UNLOCK:
case HEADER_UNLOCK:
if( pArea->fHeaderLocked )
{
if( ! hb_fileLock( pArea->pDataFile, nPos, 1, FL_UNLOCK ) )
errCode = HB_FAILURE;
pArea->fHeaderLocked = HB_FALSE;
}
break;
}
}
return errCode;
}
/*
* Perform a network lock in the specified WorkArea.
*/
static HB_ERRCODE hb_dbfLock( DBFAREAP pArea, LPDBLOCKINFO pLockInfo )
{
HB_TRACE( HB_TR_DEBUG, ( "hb_dbfLock(%p, %p)", pArea, pLockInfo ) );
if( pArea->fShared )
{
switch( pLockInfo->uiMethod )
{
case DBLM_EXCLUSIVE:
return hb_dbfLockRecord( pArea, 0, &pLockInfo->fResult, HB_TRUE );
case DBLM_MULTIPLE:
return hb_dbfLockRecord( pArea, hb_itemGetNL( pLockInfo->itmRecID ),
&pLockInfo->fResult, HB_FALSE );
case DBLM_FILE:
return hb_dbfLockFile( pArea, &pLockInfo->fResult );
default:
pLockInfo->fResult = HB_FALSE;
}
}
else
pLockInfo->fResult = HB_TRUE;
return HB_SUCCESS;
}
/*
* Release network locks in the specified WorkArea.
*/
static HB_ERRCODE hb_dbfUnLock( DBFAREAP pArea, PHB_ITEM pRecNo )
{
HB_ERRCODE errCode = HB_SUCCESS;
HB_TRACE( HB_TR_DEBUG, ( "dbfUnLock(%p, %p)", pArea, pRecNo ) );
if( pArea->fShared )
{
if( pArea->ulNumLocksPos > 0 )
{
HB_ULONG ulRecNo = hb_itemGetNL( pRecNo );
/* Unlock all records? */
if( ulRecNo == 0 )
errCode = hb_dbfUnlockAllRecords( pArea );
else if( hb_dbfIsLocked( pArea, ulRecNo ) )
errCode = hb_dbfUnlockRecord( pArea, ulRecNo );
}
if( pArea->fFLocked )
{
errCode = hb_dbfUnlockFile( pArea );
}
}
return errCode;
}
#define hb_dbfCloseMemFile NULL
/*
* Create a memo file in the WorkArea.
*/
static HB_ERRCODE hb_dbfCreateMemFile( DBFAREAP pArea, LPDBOPENINFO pCreateInfo )
{
HB_TRACE( HB_TR_DEBUG, ( "hb_dbfCreateMemFile(%p, %p)", pArea, pCreateInfo ) );
if( pCreateInfo )
hb_dbfErrorRT( pArea, EG_CREATE, EDBF_DATATYPE, pCreateInfo->abName, 0, 0, NULL );
pArea->fHasMemo = HB_FALSE;
return HB_FAILURE;
}
/*
* BLOB2FILE - retrieve memo contents into file
*/
static HB_ERRCODE hb_dbfGetValueFile( DBFAREAP pArea, HB_USHORT uiIndex, const char * szFile, HB_USHORT uiMode )
{
HB_ERRCODE errCode = HB_SUCCESS;
LPFIELD pField;
HB_TRACE( HB_TR_DEBUG, ( "hb_dbfGetValueFile(%p, %hu, %s, %hu)", pArea, uiIndex, szFile, uiMode ) );
if( pArea->lpdbPendingRel )
{
if( SELF_FORCEREL( &pArea->area ) != HB_SUCCESS )
return HB_FAILURE;
}
/* Read record */
if( ! pArea->fValidBuffer && ! hb_dbfReadRecord( pArea ) )
return HB_FAILURE;
if( --uiIndex >= pArea->area.uiFieldCount )
return HB_FAILURE;
pField = pArea->area.lpFields + uiIndex;
if( pField->uiType == HB_FT_STRING )
{
PHB_FILE pFile;
pFile = hb_fileExtOpen( szFile, NULL, FO_WRITE | FO_EXCLUSIVE |
FXO_DEFAULTS | FXO_SHARELOCK | FXO_NOSEEKPOS |
( uiMode == FILEGET_APPEND ? FXO_APPEND : FXO_TRUNCATE ),
NULL, NULL );
if( ! pFile )
{
errCode = uiMode != FILEGET_APPEND ? EDBF_CREATE : EDBF_OPEN_DBF;
}
else
{
if( hb_fileWriteAt( pFile, pArea->pRecord + pArea->pFieldOffset[ uiIndex ],
pField->uiLen, hb_fileSize( pFile ) ) !=
( HB_SIZE ) pField->uiLen )
{
errCode = EDBF_WRITE;
}
hb_fileClose( pFile );
}
}
else
{
errCode = EDBF_DATATYPE;
}
/* Exit if any error */
if( errCode != HB_SUCCESS )
{
hb_dbfErrorRT( pArea, hb_dbfGetEGcode( errCode ), errCode,
errCode != EDBF_DATATYPE ? szFile : NULL,
errCode != EDBF_DATATYPE ? hb_fsError() : 0,
EF_CANDEFAULT, NULL );
return HB_FAILURE;
}
return HB_SUCCESS;
}
/*
* Open a memo file in the specified WorkArea.
*/
static HB_ERRCODE hb_dbfOpenMemFile( DBFAREAP pArea, LPDBOPENINFO pOpenInfo )
{
HB_TRACE( HB_TR_DEBUG, ( "hb_dbfOpenMemFile(%p, %p)", pArea, pOpenInfo ) );
hb_dbfErrorRT( pArea, EG_OPEN, EDBF_OPEN_DBF, pOpenInfo->abName, 0, 0, NULL );
return HB_FAILURE;
}
/*
* FILE2BLOB - store file contents in MEMO
*/
static HB_ERRCODE hb_dbfPutValueFile( DBFAREAP pArea, HB_USHORT uiIndex, const char * szFile, HB_USHORT uiMode )
{
HB_ERRCODE errCode = HB_SUCCESS;
LPFIELD pField;
HB_TRACE( HB_TR_DEBUG, ( "hb_dbfPutValueFile(%p, %hu, %s, %hu)", pArea, uiIndex, szFile, uiMode ) );
HB_SYMBOL_UNUSED( uiMode );
if( pArea->lpdbPendingRel )
{
if( SELF_FORCEREL( &pArea->area ) != HB_SUCCESS )
return HB_FAILURE;
}
/* Read record */
if( ! pArea->fValidBuffer && ! hb_dbfReadRecord( pArea ) )
return HB_FAILURE;
if( --uiIndex >= pArea->area.uiFieldCount )
return HB_FAILURE;
if( ! pArea->fPositioned )
return HB_FAILURE;
/* Buffer is hot? */
if( ! pArea->fRecordChanged && SELF_GOHOT( &pArea->area ) == HB_FAILURE )
return HB_FAILURE;
pField = pArea->area.lpFields + uiIndex;
if( pField->uiType == HB_FT_STRING )
{
PHB_FILE pFile;
pFile = hb_fileExtOpen( szFile, NULL, FO_READ | FO_DENYNONE |
FXO_DEFAULTS | FXO_SHARELOCK | FXO_NOSEEKPOS,
NULL, NULL );
if( ! pFile )
{
errCode = EDBF_OPEN_DBF;
}
else
{
HB_SIZE nRead = hb_fileReadAt( pFile, pArea->pRecord +
pArea->pFieldOffset[ uiIndex ],
pField->uiLen, 0 );
if( nRead != ( HB_SIZE ) FS_ERROR &&
nRead < ( HB_SIZE ) pField->uiLen )
memset( pArea->pRecord + pArea->pFieldOffset[ uiIndex ] + nRead,
' ', pField->uiLen - nRead );
hb_fileClose( pFile );
}
}
else
{
errCode = EDBF_DATATYPE;
}
/* Exit if any error */
if( errCode != HB_SUCCESS )
{
hb_dbfErrorRT( pArea, hb_dbfGetEGcode( errCode ), errCode,
errCode != EDBF_DATATYPE ? szFile : NULL,
errCode != EDBF_DATATYPE ? hb_fsError() : 0,
EF_CANDEFAULT, NULL );
return HB_FAILURE;
}
return HB_SUCCESS;
}
/*
* Read the database file header record in the WorkArea.
*/
static HB_ERRCODE hb_dbfReadDBHeader( DBFAREAP pArea )
{
HB_ERRCODE errCode;
PHB_ITEM pError;
HB_TRACE( HB_TR_DEBUG, ( "hb_dbfReadDBHeader(%p)", pArea ) );
pError = NULL;
do
{
errCode = HB_SUCCESS;
if( hb_fileReadAt( pArea->pDataFile, &pArea->dbfHeader,
sizeof( DBFHEADER ), 0 ) != sizeof( DBFHEADER ) )
{
errCode = EDBF_READ;
}
else
{
pArea->fAutoInc = pArea->fModStamp =
pArea->fTableEncrypted = pArea->fHasMemo = HB_FALSE;
pArea->bTableType = DB_DBF_STD;
pArea->bMemoType = DB_MEMO_NONE;
pArea->bCryptType = DB_CRYPT_NONE;
pArea->fHasTags = ( pArea->dbfHeader.bHasTags & 0x01 ) != 0;
switch( pArea->dbfHeader.bVersion )
{
case 0x31:
pArea->fAutoInc = HB_TRUE;
case 0x30:
case 0x32:
pArea->bTableType = DB_DBF_VFP;
if( pArea->dbfHeader.bHasTags & 0x02 )
{
pArea->bMemoType = DB_MEMO_FPT;
pArea->fHasMemo = HB_TRUE;
}
break;
case 0x03:
case 0x07: /* CA-VO DBFNTX and ANSI CP */
break;
case 0x83:
case 0x87: /* CA-VO DBFNTX+MEMO and ANSI CP */
pArea->fHasMemo = HB_TRUE;
pArea->bMemoType = DB_MEMO_DBT;
break;
case 0xE5:
pArea->fHasMemo = HB_TRUE;
pArea->bMemoType = DB_MEMO_SMT;
break;
case 0xF5:
pArea->fHasMemo = HB_TRUE;
pArea->bMemoType = DB_MEMO_FPT;
break;
case 0x06:
pArea->fTableEncrypted = HB_TRUE;
pArea->bCryptType = DB_CRYPT_SIX;
break;
case 0x86:
pArea->fTableEncrypted = HB_TRUE;
pArea->fHasMemo = HB_TRUE;
pArea->bCryptType = DB_CRYPT_SIX;
pArea->bMemoType = DB_MEMO_DBT;
break;
case 0xE6:
pArea->fHasMemo = HB_TRUE;
pArea->fTableEncrypted = HB_TRUE;
pArea->bCryptType = DB_CRYPT_SIX;
pArea->bMemoType = DB_MEMO_SMT;
break;
case 0xF6:
pArea->fHasMemo = HB_TRUE;
pArea->fTableEncrypted = HB_TRUE;
pArea->bCryptType = DB_CRYPT_SIX;
pArea->bMemoType = DB_MEMO_FPT;
break;
default:
errCode = EDBF_CORRUPT;
}
if( errCode == HB_SUCCESS )
break;
}
}
while( hb_dbfErrorRT( pArea, hb_dbfGetEGcode( errCode ), errCode,
pArea->szDataFileName, hb_fsError(),
EF_CANRETRY | EF_CANDEFAULT, &pError ) == E_RETRY );
if( pError )
hb_itemRelease( pError );
if( errCode != HB_SUCCESS )
return HB_FAILURE;
pArea->uiHeaderLen = HB_GET_LE_UINT16( pArea->dbfHeader.uiHeaderLen );
pArea->ulRecCount = HB_GET_LE_UINT32( pArea->dbfHeader.ulRecCount );
return HB_SUCCESS;
}
/*
* Write the database file header record in the WorkArea.
*/
static HB_ERRCODE hb_dbfWriteDBHeader( DBFAREAP pArea )
{
int iYear, iMonth, iDay;
HB_BOOL fLck = HB_FALSE;
HB_ERRCODE errCode;
HB_TRACE( HB_TR_DEBUG, ( "hb_dbfWriteDBHeader(%p)", pArea ) );
if( pArea->fReadonly )
{
hb_dbfErrorRT( pArea, EG_READONLY, EDBF_READONLY, NULL, 0, 0, NULL );
return HB_FAILURE;
}
pArea->dbfHeader.bHasTags = pArea->fHasTags ? 0x01 : 0x00;
if( pArea->bTableType == DB_DBF_VFP )
{
pArea->dbfHeader.bVersion = ( pArea->fAutoInc ? 0x31 : 0x30 );
if( pArea->fHasMemo && pArea->bMemoType == DB_MEMO_FPT )
pArea->dbfHeader.bHasTags |= 0x02;
}
else
{
pArea->dbfHeader.bVersion = 0x03;
if( pArea->fHasMemo )
{
if( pArea->bMemoType == DB_MEMO_DBT )
pArea->dbfHeader.bVersion = 0x83;
else if( pArea->bMemoType == DB_MEMO_FPT )
pArea->dbfHeader.bVersion = 0xF5;
else if( pArea->bMemoType == DB_MEMO_SMT )
pArea->dbfHeader.bVersion = 0xE5;
}
if( pArea->fTableEncrypted && pArea->bCryptType == DB_CRYPT_SIX )
pArea->dbfHeader.bVersion = ( pArea->dbfHeader.bVersion & 0xf0 ) | 0x06;
}
hb_dateToday( &iYear, &iMonth, &iDay );
pArea->dbfHeader.bYear = ( HB_BYTE ) ( iYear - 1900 );
pArea->dbfHeader.bMonth = ( HB_BYTE ) iMonth;
pArea->dbfHeader.bDay = ( HB_BYTE ) iDay;
/* Update record count */
if( pArea->fShared )
{
if( ! pArea->fHeaderLocked )
{
if( SELF_RAWLOCK( &pArea->area, HEADER_LOCK, 0 ) != HB_SUCCESS )
return HB_FAILURE;
fLck = HB_TRUE;
}
pArea->ulRecCount = hb_dbfCalcRecCount( pArea );
}
else
{
/* Exclusive mode */
/* write eof mark */
HB_FOFFSET nOffset = ( HB_FOFFSET ) pArea->uiHeaderLen +
( HB_FOFFSET ) pArea->uiRecordLen *
( HB_FOFFSET ) pArea->ulRecCount;
hb_fileWriteAt( pArea->pDataFile, "\032", 1, nOffset );
hb_fileTruncAt( pArea->pDataFile, nOffset + 1 );
}
HB_PUT_LE_UINT32( pArea->dbfHeader.ulRecCount, pArea->ulRecCount );
HB_PUT_LE_UINT16( pArea->dbfHeader.uiHeaderLen, pArea->uiHeaderLen );
HB_PUT_LE_UINT16( pArea->dbfHeader.uiRecordLen, pArea->uiRecordLen );
if( hb_fileWriteAt( pArea->pDataFile, &pArea->dbfHeader,
sizeof( DBFHEADER ), 0 ) == sizeof( DBFHEADER ) )
errCode = HB_SUCCESS;
else
errCode = HB_FAILURE;
pArea->fDataFlush = HB_TRUE;
pArea->fUpdateHeader = HB_FALSE;
if( fLck )
{
if( SELF_RAWLOCK( &pArea->area, HEADER_UNLOCK, 0 ) != HB_SUCCESS )
return HB_FAILURE;
}
if( errCode != HB_SUCCESS )
hb_dbfErrorRT( pArea, EG_WRITE, EDBF_WRITE, pArea->szDataFileName,
hb_fsError(), 0, NULL );
return errCode;
}
static HB_ERRCODE hb_dbfDrop( LPRDDNODE pRDD, PHB_ITEM pItemTable, PHB_ITEM pItemIndex, HB_ULONG ulConnect )
{
char szFileName[ HB_PATH_MAX ];
const char * szFile, * szExt;
PHB_ITEM pFileExt = NULL;
PHB_FNAME pFileName;
HB_BOOL fTable = HB_FALSE, fResult = HB_FALSE;
HB_TRACE( HB_TR_DEBUG, ( "hb_dbfDrop(%p,%p,%p,%lu)", pRDD, pItemTable, pItemIndex, ulConnect ) );
szFile = hb_itemGetCPtr( pItemIndex );
if( ! szFile[ 0 ] )
{
/* Try to delete index file */
szFile = hb_itemGetCPtr( pItemTable );
if( ! szFile[ 0 ] )
return HB_FAILURE;
fTable = HB_TRUE;
}
pFileName = hb_fsFNameSplit( szFile );
if( ! pFileName->szExtension && ( ! fTable || hb_setGetDefExtension() ) )
{
/* Add default extension if missing */
pFileExt = hb_itemPutC( NULL, NULL );
if( SELF_RDDINFO( pRDD, fTable ? RDDI_TABLEEXT : RDDI_ORDBAGEXT, ulConnect, pFileExt ) == HB_SUCCESS )
pFileName->szExtension = hb_itemGetCPtr( pFileExt );
}
hb_fsFNameMerge( szFileName, pFileName );
hb_xfree( pFileName );
/* Use hb_fileExists first to locate table which can be in differ path */
if( hb_fileExists( szFileName, szFileName ) )
{
fResult = hb_fileDelete( szFileName );
if( fResult && fTable )
{
/*
* Database table file has been deleted, now check if memo is
* supported and if yes then try to delete memo file if it exists
* in the same directory as table file
* hb_fsFNameSplit() repeated intentionally to respect
* the path set by hb_FileExists()
*/
pFileName = hb_fsFNameSplit( szFileName );
pFileExt = hb_itemPutC( pFileExt, NULL );
if( SELF_RDDINFO( pRDD, RDDI_MEMOEXT, ulConnect, pFileExt ) == HB_SUCCESS )
{
szExt = hb_itemGetCPtr( pFileExt );
if( szExt[ 0 ] )
{
pFileName->szExtension = szExt;
hb_fsFNameMerge( szFileName, pFileName );
hb_fileDelete( szFileName );
}
}
/*
* and try to delete production index also if it exists
* in the same directory as table file
*/
pFileExt = hb_itemPutC( pFileExt, NULL );
if( SELF_RDDINFO( pRDD, RDDI_ORDSTRUCTEXT, ulConnect, pFileExt ) == HB_SUCCESS )
{
szExt = hb_itemGetCPtr( pFileExt );
if( szExt[ 0 ] )
{
pFileName->szExtension = szExt;
hb_fsFNameMerge( szFileName, pFileName );
hb_fileDelete( szFileName );
}
}
hb_xfree( pFileName );
}
}
if( pFileExt )
hb_itemRelease( pFileExt );
return fResult ? HB_SUCCESS : HB_FAILURE;
}
static HB_ERRCODE hb_dbfExists( LPRDDNODE pRDD, PHB_ITEM pItemTable, PHB_ITEM pItemIndex, HB_ULONG ulConnect )
{
char szFileName[ HB_PATH_MAX ];
const char * szFile;
PHB_ITEM pFileExt = NULL;
PHB_FNAME pFileName;
HB_BOOL fTable = HB_FALSE;
HB_TRACE( HB_TR_DEBUG, ( "hb_dbfExists(%p,%p,%p,%lu)", pRDD, pItemTable, pItemIndex, ulConnect ) );
szFile = hb_itemGetCPtr( pItemIndex );
if( ! szFile[ 0 ] )
{
szFile = hb_itemGetCPtr( pItemTable );
if( ! szFile[ 0 ] )
return HB_FAILURE;
fTable = HB_TRUE;
}
pFileName = hb_fsFNameSplit( szFile );
if( ! pFileName->szExtension && ( ! fTable || hb_setGetDefExtension() ) )
{
pFileExt = hb_itemPutC( NULL, NULL );
if( SELF_RDDINFO( pRDD, fTable ? RDDI_TABLEEXT : RDDI_ORDBAGEXT, ulConnect, pFileExt ) == HB_SUCCESS )
pFileName->szExtension = hb_itemGetCPtr( pFileExt );
}
hb_fsFNameMerge( szFileName, pFileName );
hb_xfree( pFileName );
if( pFileExt )
hb_itemRelease( pFileExt );
return hb_fileExists( szFileName, NULL ) ? HB_SUCCESS : HB_FAILURE;
}
static HB_ERRCODE hb_dbfRename( LPRDDNODE pRDD, PHB_ITEM pItemTable, PHB_ITEM pItemIndex, PHB_ITEM pItemNew, HB_ULONG ulConnect )
{
char szFileName[ HB_PATH_MAX ];
char szFileNew[ HB_PATH_MAX ];
const char * szFile, * szExt;
PHB_ITEM pFileExt = NULL;
PHB_FNAME pFileName, pFileNameNew;
HB_BOOL fTable = HB_FALSE, fResult = HB_FALSE;
HB_TRACE( HB_TR_DEBUG, ( "hb_dbfRename(%p,%p,%p,%p,%lu)", pRDD, pItemTable, pItemIndex, pItemNew, ulConnect ) );
szFile = hb_itemGetCPtr( pItemIndex );
if( ! szFile[ 0 ] )
{
/* Try to delete index file */
szFile = hb_itemGetCPtr( pItemTable );
if( ! szFile[ 0 ] )
return HB_FAILURE;
fTable = HB_TRUE;
}
pFileName = hb_fsFNameSplit( szFile );
if( ! pFileName->szExtension && ( ! fTable || hb_setGetDefExtension() ) )
{
/* Add default extension if missing */
pFileExt = hb_itemPutC( pFileExt, NULL );
if( SELF_RDDINFO( pRDD, fTable ? RDDI_TABLEEXT : RDDI_ORDBAGEXT, ulConnect, pFileExt ) == HB_SUCCESS )
pFileName->szExtension = hb_itemGetCPtr( pFileExt );
}
hb_fsFNameMerge( szFileName, pFileName );
hb_xfree( pFileName );
szFile = hb_itemGetCPtr( pItemNew );
/* Use hb_fileExists first to locate table which can be in differ path */
if( szFile[ 0 ] && hb_fileExists( szFileName, szFileName ) )
{
/* hb_fsFNameSplit() repeated intentionally to respect
* the path set by hb_FileExists()
*/
pFileName = hb_fsFNameSplit( szFileName );
pFileNameNew = hb_fsFNameSplit( szFile );
if( ! pFileNameNew->szExtension && ( ! fTable || hb_setGetDefExtension() ) )
{
/* Add default extension if missing */
pFileExt = hb_itemPutC( pFileExt, NULL );
if( SELF_RDDINFO( pRDD, fTable ? RDDI_TABLEEXT : RDDI_ORDBAGEXT, ulConnect, pFileExt ) == HB_SUCCESS )
pFileNameNew->szExtension = hb_itemGetCPtr( pFileExt );
}
if( ! pFileNameNew->szPath )
pFileNameNew->szPath = pFileName->szPath;
hb_fsFNameMerge( szFileNew, pFileNameNew );
fResult = hb_fileRename( szFileName, szFileNew );
if( fResult && fTable )
{
/*
* Database table file has been renamed, now check if memo is
* supported and if yes then try to rename memo file if it exists
* in the same directory as table file
*/
pFileExt = hb_itemPutC( pFileExt, NULL );
if( SELF_RDDINFO( pRDD, RDDI_MEMOEXT, ulConnect, pFileExt ) == HB_SUCCESS )
{
szExt = hb_itemGetCPtr( pFileExt );
if( szExt[ 0 ] )
{
pFileName->szExtension = szExt;
pFileNameNew->szExtension = szExt;
hb_fsFNameMerge( szFileName, pFileName );
hb_fsFNameMerge( szFileNew, pFileNameNew );
hb_fileRename( szFileName, szFileNew );
}
}
/*
* and try to rename production index also if it exists
* in the same directory as table file
*/
pFileExt = hb_itemPutC( pFileExt, NULL );
if( SELF_RDDINFO( pRDD, RDDI_ORDSTRUCTEXT, ulConnect, pFileExt ) == HB_SUCCESS )
{
szExt = hb_itemGetCPtr( pFileExt );
if( szExt[ 0 ] )
{
pFileName->szExtension = szExt;
pFileNameNew->szExtension = szExt;
hb_fsFNameMerge( szFileName, pFileName );
hb_fsFNameMerge( szFileNew, pFileNameNew );
hb_fileRename( szFileName, szFileNew );
}
}
}
hb_xfree( pFileName );
hb_xfree( pFileNameNew );
}
if( pFileExt )
hb_itemRelease( pFileExt );
return fResult ? HB_SUCCESS : HB_FAILURE;
}
static void hb_dbfInitTSD( void * Cargo )
{
HB_TRACE( HB_TR_DEBUG, ( "hb_dbfInitTSD(%p)", Cargo ) );
( ( LPDBFDATA ) Cargo )->bTableType = DB_DBF_STD;
( ( LPDBFDATA ) Cargo )->bCryptType = DB_CRYPT_NONE;
( ( LPDBFDATA ) Cargo )->uiDirtyRead = HB_IDXREAD_CLEANMASK;
}
static void hb_dbfDestroyTSD( void * Cargo )
{
LPDBFDATA pData;
HB_TRACE( HB_TR_DEBUG, ( "hb_dbfDestroyTSD(%p)", Cargo ) );
pData = ( LPDBFDATA ) Cargo;
if( pData->szTrigger )
hb_xfree( pData->szTrigger );
if( pData->szPendingTrigger )
hb_xfree( pData->szPendingTrigger );
if( pData->szPasswd )
hb_xfree( pData->szPasswd );
if( pData->szPendingPasswd )
hb_xfree( pData->szPendingPasswd );
}
static HB_ERRCODE hb_dbfInit( LPRDDNODE pRDD )
{
PHB_TSD pTSD;
HB_TRACE( HB_TR_DEBUG, ( "hb_dbfInit(%p)", pRDD ) );
pTSD = ( PHB_TSD ) hb_xgrab( sizeof( HB_TSD ) );
HB_TSD_INIT( pTSD, sizeof( DBFDATA ), hb_dbfInitTSD, hb_dbfDestroyTSD );
pRDD->lpvCargo = ( void * ) pTSD;
if( ISSUPER_INIT( pRDD ) )
return SUPER_INIT( pRDD );
else
return HB_SUCCESS;
}
static HB_ERRCODE hb_dbfExit( LPRDDNODE pRDD )
{
HB_TRACE( HB_TR_DEBUG, ( "hb_dbfExit(%p)", pRDD ) );
if( pRDD->lpvCargo )
{
hb_stackReleaseTSD( ( PHB_TSD ) pRDD->lpvCargo );
hb_xfree( pRDD->lpvCargo );
pRDD->lpvCargo = NULL;
}
s_uiRddId = ( HB_USHORT ) -1;
if( ISSUPER_EXIT( pRDD ) )
return SUPER_EXIT( pRDD );
else
return HB_SUCCESS;
}
static HB_ERRCODE hb_dbfRddInfo( LPRDDNODE pRDD, HB_USHORT uiIndex, HB_ULONG ulConnect, PHB_ITEM pItem )
{
LPDBFDATA pData;
HB_TRACE( HB_TR_DEBUG, ( "hb_dbfRddInfo(%p, %hu, %lu, %p)", pRDD, uiIndex, ulConnect, pItem ) );
pData = DBFNODE_DATA( pRDD );
switch( uiIndex )
{
case RDDI_ISDBF:
case RDDI_CANPUTREC:
case RDDI_LOCAL:
hb_itemPutL( pItem, HB_TRUE );
break;
case RDDI_TABLEEXT:
{
const char * szNew = hb_itemGetCPtr( pItem );
char * szNewVal;
szNewVal = szNew[ 0 ] == '.' && szNew[ 1 ] ? hb_strdup( szNew ) : NULL;
hb_itemPutC( pItem, pData->szTableExt[ 0 ] ? pData->szTableExt : DBF_TABLEEXT );
if( szNewVal )
{
hb_strncpy( pData->szTableExt, szNewVal, sizeof( pData->szTableExt ) - 1 );
hb_xfree( szNewVal );
}
break;
}
case RDDI_TABLETYPE:
{
int iType = hb_itemGetNI( pItem );
hb_itemPutNI( pItem, pData->bTableType ? pData->bTableType : DB_DBF_STD );
switch( iType )
{
case DB_DBF_STD: /* standard dBase/Clipper DBF file */
case DB_DBF_VFP: /* VFP DBF file */
pData->bTableType = ( HB_BYTE ) iType;
}
break;
}
case RDDI_LOCKSCHEME:
{
int iScheme = hb_itemGetNI( pItem );
hb_itemPutNI( pItem, pData->bLockType ? pData->bLockType :
hb_setGetDBFLockScheme() );
switch( iScheme )
{
case DB_DBFLOCK_CLIPPER:
case DB_DBFLOCK_CLIPPER2:
case DB_DBFLOCK_COMIX:
case DB_DBFLOCK_VFP:
case DB_DBFLOCK_HB32:
#ifndef HB_LONG_LONG_OFF
case DB_DBFLOCK_HB64:
#endif
pData->bLockType = ( HB_BYTE ) iScheme;
}
break;
}
case RDDI_DIRTYREAD:
{
HB_BOOL fDirty = ( pData->uiDirtyRead == HB_IDXREAD_DIRTYMASK );
if( HB_IS_LOGICAL( pItem ) )
{
pData->uiDirtyRead = hb_itemGetL( pItem ) ?
HB_IDXREAD_DIRTYMASK : HB_IDXREAD_CLEANMASK;
}
hb_itemPutL( pItem, fDirty );
break;
}
case RDDI_INDEXPAGESIZE:
{
int iPageSize = hb_itemGetNI( pItem );
hb_itemPutNI( pItem, pData->uiIndexPageSize );
if( iPageSize >= 0x200 && iPageSize <= 0x2000 &&
( ( iPageSize - 1 ) & iPageSize ) == 0 )
pData->uiIndexPageSize = ( HB_USHORT ) iPageSize;
break;
}
case RDDI_TRIGGER:
{
char * szTrigger = pData->szTrigger;
HB_BOOL fFree = HB_FALSE;
if( HB_IS_STRING( pItem ) )
{
fFree = HB_TRUE;
pData->szTrigger = hb_itemGetCLen( pItem ) > 0 ?
hb_itemGetC( pItem ) : NULL;
}
if( fFree && szTrigger )
hb_itemPutCPtr( pItem, szTrigger );
else
hb_itemPutC( pItem, szTrigger );
if( ! szTrigger && ! fFree )
return HB_FAILURE;
break;
}
case RDDI_PENDINGTRIGGER:
if( HB_IS_STRING( pItem ) )
{
if( pData->szPendingTrigger )
{
hb_xfree( pData->szPendingTrigger );
pData->szPendingTrigger = NULL;
}
if( hb_itemGetCLen( pItem ) > 0 )
pData->szPendingTrigger = hb_itemGetC( pItem );
}
else if( pData->szPendingTrigger )
{
hb_itemPutCPtr( pItem, pData->szPendingTrigger );
pData->szPendingTrigger = NULL;
}
else
return HB_FAILURE;
break;
case RDDI_PASSWORD:
{
char * szPasswd = pData->szPasswd;
HB_BOOL fFree = HB_FALSE;
if( HB_IS_STRING( pItem ) )
{
fFree = HB_TRUE;
pData->szPasswd = hb_itemGetCLen( pItem ) > 0 ?
hb_itemGetC( pItem ) : NULL;
}
if( fFree && szPasswd )
hb_itemPutCPtr( pItem, szPasswd );
else
hb_itemPutC( pItem, szPasswd );
if( ! szPasswd && ! fFree )
return HB_FAILURE;
break;
}
case RDDI_PENDINGPASSWORD:
if( HB_IS_STRING( pItem ) )
{
if( pData->szPendingPasswd )
{
hb_xfree( pData->szPendingPasswd );
pData->szPendingPasswd = NULL;
}
if( hb_itemGetCLen( pItem ) > 0 )
pData->szPendingPasswd = hb_itemGetC( pItem );
}
else if( pData->szPendingPasswd )
{
hb_itemPutCPtr( pItem, pData->szPendingPasswd );
pData->szPendingPasswd = NULL;
}
else
return HB_FAILURE;
break;
default:
return SUPER_RDDINFO( pRDD, uiIndex, ulConnect, pItem );
}
return HB_SUCCESS;
}
#define hb_dbfWhoCares NULL
static const RDDFUNCS dbfTable = { ( DBENTRYP_BP ) hb_dbfBof,
( DBENTRYP_BP ) hb_dbfEof,
( DBENTRYP_BP ) hb_dbfFound,
( DBENTRYP_V ) hb_dbfGoBottom,
( DBENTRYP_UL ) hb_dbfGoTo,
( DBENTRYP_I ) hb_dbfGoToId,
( DBENTRYP_V ) hb_dbfGoTop,
( DBENTRYP_BIB ) hb_dbfSeek,
( DBENTRYP_L ) hb_dbfSkip,
( DBENTRYP_L ) hb_dbfSkipFilter,
( DBENTRYP_L ) hb_dbfSkipRaw,
( DBENTRYP_VF ) hb_dbfAddField,
( DBENTRYP_B ) hb_dbfAppend,
( DBENTRYP_I ) hb_dbfCreateFields,
( DBENTRYP_V ) hb_dbfDeleteRec,
( DBENTRYP_BP ) hb_dbfDeleted,
( DBENTRYP_SP ) hb_dbfFieldCount,
( DBENTRYP_VF ) hb_dbfFieldDisplay,
( DBENTRYP_SSI ) hb_dbfFieldInfo,
( DBENTRYP_SCP ) hb_dbfFieldName,
( DBENTRYP_V ) hb_dbfFlush,
( DBENTRYP_PP ) hb_dbfGetRec,
( DBENTRYP_SI ) hb_dbfGetValue,
( DBENTRYP_SVL ) hb_dbfGetVarLen,
( DBENTRYP_V ) hb_dbfGoCold,
( DBENTRYP_V ) hb_dbfGoHot,
( DBENTRYP_P ) hb_dbfPutRec,
( DBENTRYP_SI ) hb_dbfPutValue,
( DBENTRYP_V ) hb_dbfRecall,
( DBENTRYP_ULP ) hb_dbfRecCount,
( DBENTRYP_ISI ) hb_dbfRecInfo,
( DBENTRYP_ULP ) hb_dbfRecNo,
( DBENTRYP_I ) hb_dbfRecId,
( DBENTRYP_S ) hb_dbfSetFieldExtent,
( DBENTRYP_CP ) hb_dbfAlias,
( DBENTRYP_V ) hb_dbfClose,
( DBENTRYP_VO ) hb_dbfCreate,
( DBENTRYP_SI ) hb_dbfInfo,
( DBENTRYP_V ) hb_dbfNewArea,
( DBENTRYP_VO ) hb_dbfOpen,
( DBENTRYP_V ) hb_dbfRelease,
( DBENTRYP_SP ) hb_dbfStructSize,
( DBENTRYP_CP ) hb_dbfSysName,
( DBENTRYP_VEI ) hb_dbfEval,
( DBENTRYP_V ) hb_dbfPack,
( DBENTRYP_LSP ) hb_dbfPackRec,
( DBENTRYP_VS ) hb_dbfSort,
( DBENTRYP_VT ) hb_dbfTrans,
( DBENTRYP_VT ) hb_dbfTransRec,
( DBENTRYP_V ) hb_dbfZap,
( DBENTRYP_VR ) hb_dbfChildEnd,
( DBENTRYP_VR ) hb_dbfChildStart,
( DBENTRYP_VR ) hb_dbfChildSync,
( DBENTRYP_V ) hb_dbfSyncChildren,
( DBENTRYP_V ) hb_dbfClearRel,
( DBENTRYP_V ) hb_dbfForceRel,
( DBENTRYP_SSP ) hb_dbfRelArea,
( DBENTRYP_VR ) hb_dbfRelEval,
( DBENTRYP_SI ) hb_dbfRelText,
( DBENTRYP_VR ) hb_dbfSetRel,
( DBENTRYP_VOI ) hb_dbfOrderListAdd,
( DBENTRYP_V ) hb_dbfOrderListClear,
( DBENTRYP_VOI ) hb_dbfOrderListDelete,
( DBENTRYP_VOI ) hb_dbfOrderListFocus,
( DBENTRYP_V ) hb_dbfOrderListRebuild,
( DBENTRYP_VOO ) hb_dbfOrderCondition,
( DBENTRYP_VOC ) hb_dbfOrderCreate,
( DBENTRYP_VOI ) hb_dbfOrderDestroy,
( DBENTRYP_SVOI ) hb_dbfOrderInfo,
( DBENTRYP_V ) hb_dbfClearFilter,
( DBENTRYP_V ) hb_dbfClearLocate,
( DBENTRYP_V ) hb_dbfClearScope,
( DBENTRYP_VPLP ) hb_dbfCountScope,
( DBENTRYP_I ) hb_dbfFilterText,
( DBENTRYP_SI ) hb_dbfScopeInfo,
( DBENTRYP_VFI ) hb_dbfSetFilter,
( DBENTRYP_VLO ) hb_dbfSetLocate,
( DBENTRYP_VOS ) hb_dbfSetScope,
( DBENTRYP_VPL ) hb_dbfSkipScope,
( DBENTRYP_B ) hb_dbfLocate,
( DBENTRYP_CC ) hb_dbfCompile,
( DBENTRYP_I ) hb_dbfError,
( DBENTRYP_I ) hb_dbfEvalBlock,
( DBENTRYP_VSP ) hb_dbfRawLock,
( DBENTRYP_VL ) hb_dbfLock,
( DBENTRYP_I ) hb_dbfUnLock,
( DBENTRYP_V ) hb_dbfCloseMemFile,
( DBENTRYP_VO ) hb_dbfCreateMemFile,
( DBENTRYP_SCCS ) hb_dbfGetValueFile,
( DBENTRYP_VO ) hb_dbfOpenMemFile,
( DBENTRYP_SCCS ) hb_dbfPutValueFile,
( DBENTRYP_V ) hb_dbfReadDBHeader,
( DBENTRYP_V ) hb_dbfWriteDBHeader,
( DBENTRYP_R ) hb_dbfInit,
( DBENTRYP_R ) hb_dbfExit,
( DBENTRYP_RVVL ) hb_dbfDrop,
( DBENTRYP_RVVL ) hb_dbfExists,
( DBENTRYP_RVVVL ) hb_dbfRename,
( DBENTRYP_RSLV ) hb_dbfRddInfo,
( DBENTRYP_SVP ) hb_dbfWhoCares
};
HB_FUNC( _DBF ) { ; }
HB_FUNC_STATIC( DBF_GETFUNCTABLE )
{
RDDFUNCS * pTable;
HB_USHORT * puiCount, uiRddId;
puiCount = ( HB_USHORT * ) hb_parptr( 1 );
pTable = ( RDDFUNCS * ) hb_parptr( 2 );
uiRddId = ( HB_USHORT ) hb_parni( 4 );
HB_TRACE( HB_TR_DEBUG, ( "DBF_GETFUNCTABLE(%p, %p)", puiCount, pTable ) );
if( pTable )
{
HB_ERRCODE errCode;
if( puiCount )
*puiCount = RDDFUNCSCOUNT;
errCode = hb_rddInheritEx( pTable, &dbfTable, &dbfSuper, NULL, NULL );
hb_retni( errCode );
if( errCode == HB_SUCCESS )
{
/*
* we successfully register our RDD so now we can initialize it
* You may think that this place is RDD init statement, Druzus
*/
s_uiRddId = uiRddId;
}
}
else
hb_retni( HB_FAILURE );
}
static void hb_dbfRddInit( void * cargo )
{
HB_SYMBOL_UNUSED( cargo );
if( hb_rddRegister( "DBF", RDT_FULL ) > 1 )
hb_errInternal( HB_EI_RDDINVALID, NULL, NULL, NULL );
}
HB_INIT_SYMBOLS_BEGIN( dbf1__InitSymbols )
{ "_DBF", {HB_FS_PUBLIC|HB_FS_LOCAL}, {HB_FUNCNAME( _DBF )}, NULL },
{ "DBF_GETFUNCTABLE", {HB_FS_PUBLIC|HB_FS_LOCAL}, {HB_FUNCNAME( DBF_GETFUNCTABLE )}, NULL }
HB_INIT_SYMBOLS_END( dbf1__InitSymbols )
HB_CALL_ON_STARTUP_BEGIN( _hb_dbf_rdd_init_ )
hb_vmAtInit( hb_dbfRddInit, NULL );
HB_CALL_ON_STARTUP_END( _hb_dbf_rdd_init_ )
#if defined( HB_PRAGMA_STARTUP )
#pragma startup dbf1__InitSymbols
#pragma startup _hb_dbf_rdd_init_
#elif defined( HB_DATASEG_STARTUP )
#define HB_DATASEG_BODY HB_DATASEG_FUNC( dbf1__InitSymbols ) \
HB_DATASEG_FUNC( _hb_dbf_rdd_init_ )
#include "hbiniseg.h"
#endif