/*
 * $Id$
 */

/*
 * Harbour Project source code:
 * DBF RDD module
 *
 * Copyright 1999 Bruno Cantero <bruno@issnet.net>
 * www - http://www.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 of the License, or
 * (at your option) any later version, with one exception:
 *
 * The exception is that if you link the Harbour Runtime Library (HRL)
 * and/or the Harbour Virtual Machine (HVM) 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 HRL
 * and/or HVM code into it.
 *
 * 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 program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA (or visit
 * their web site at http://www.gnu.org/).
 *
 */

#define SUPERTABLE ( &dbfSuper )

#include <time.h>
#include <ctype.h>
#include "hbapi.h"
#include "hbapiitm.h"
#include "hbinit.h"
#include "hbapirdd.h"
#include "rddsys.ch"
#include "hbapierr.h"
#include "hbdate.h"
#include "hbapilng.h"
#include "hbvm.h"

typedef struct _DBFHEADER
{
   BYTE   bVersion;
   BYTE   bYear;
   BYTE   bMonth;
   BYTE   bDay;
   ULONG  ulRecords;
   USHORT uiHeaderLen;
   USHORT uiRecordLen;
   BYTE   bReserved1[ 16 ];
   BYTE   bHasTag;
   BYTE   bReserved2[ 3 ];
} DBFHEADER;

typedef DBFHEADER * LPDBFHEADER;


typedef struct _DBFFIELD
{
   BYTE bName[ 11 ];
   BYTE bType;
   BYTE bReserved1[ 4 ];
   BYTE bLen;
   BYTE bDec;
   BYTE bReserved2[ 13 ];
   BYTE bHasTag;
} DBFFIELD;

typedef DBFFIELD * LPDBFFIELD;


typedef struct
{
   ULONG  lNextBlock;
} MEMOHEADER;

typedef MEMOHEADER * LPMEMOHEADER;


typedef struct _DBFMEMO
{
   BOOL   fChanged;             /* Memo status */
   BYTE * pData;                /* Memo data */
   USHORT uiLen;                /* Len of data */
} DBFMEMO;

typedef DBFMEMO * LPDBFMEMO;


HB_FUNC( _DBFC );
HB_FUNC( DBF_GETFUNCTABLE );

HB_INIT_SYMBOLS_BEGIN( dbf1__InitSymbols )
{ "_DBFC",            HB_FS_PUBLIC, HB_FUNCNAME( _DBFC ), NULL },
{ "DBF_GETFUNCTABLE", HB_FS_PUBLIC, HB_FUNCNAME( DBF_GETFUNCTABLE ), NULL }
HB_INIT_SYMBOLS_END( dbf1__InitSymbols )
#if defined(_MSC_VER)
   #if _MSC_VER >= 1010
      #pragma data_seg( ".CRT$XIY" )
      #pragma comment( linker, "/Merge:.CRT=.data" )
   #else
      #pragma data_seg( "XIY" )
   #endif
   static HB_$INITSYM hb_vm_auto_dbf1__InitSymbols = dbf1__InitSymbols;
   #pragma data_seg()
#elif ! defined(__GNUC__)
   #pragma startup dbf1__InitSymbols
#endif

#define LOCK_START                          0x40000000L
#define LOCK_APPEND                         0x7FFFFFFEL
#define LOCK_FILE                           0x3FFFFFFFL
#define MEMO_BLOCK                                  512


static BOOL hb_nltoa( LONG lValue, char * szBuffer, USHORT uiLen )
{
   LONG lAbsNumber;
   int iCount, iPos;

   HB_TRACE(HB_TR_DEBUG, ("hb_nltoa(%ld, %p, %hu)", lValue, szBuffer, uiLen));

   lAbsNumber = ( lValue > 0 ) ? lValue : - lValue;
   iCount = iPos = uiLen;
   while( iCount-- > 0 )
   {
      szBuffer[ iCount ] = ( '0' + lAbsNumber % 10 );
      lAbsNumber /= 10;
   }

   if( lAbsNumber > 0 )
   {
      memset( szBuffer, ' ', uiLen );
      return FALSE;
   }

   uiLen--;
   for( iCount = 0; iCount < uiLen; iCount++ )
      if( szBuffer[ iCount ] == '0' )
         szBuffer[ iCount ] = ' ';
      else
         break;

   if( lValue < 0 )
   {
      if( szBuffer[ 0 ] != ' ' )
      {
         memset( szBuffer, ' ', iPos );
         return FALSE;
      }
      for( iCount = uiLen; iCount >= 0; iCount-- )
      {
         if( szBuffer[ iCount ] == ' ' )
         {
            szBuffer[ iCount ] = '-';
            break;
         }
      }
   }
   return TRUE;
}

static BOOL hb_ndtoa( double dValue, char * szBuffer, USHORT uiLen, USHORT uiDec )
{
   double dAbsNumber;
   int iCount;
   char szEndChar;

   HB_TRACE(HB_TR_DEBUG, ("hb_ndtoa(%lf, %p, %hu, %hu)", dValue, szBuffer, uiLen, uiDec));

   if( uiLen > 19 )
      uiLen = 19;
   if( uiDec + 2 > uiLen )
      uiDec = uiLen - 2 ;
   if( uiDec > 15 )
      uiDec = 15;
   dAbsNumber = ( dValue > 0 ) ? dValue : - dValue;
   iCount = uiLen - uiDec - ( ( dValue < 0 ) ? 2 : 1 );
   while( iCount-- > 0 )
      dAbsNumber /= 10;

   if( dAbsNumber > 1 || dValue >= 10000000000000000000.0 )
   {
      memset( szBuffer, ' ', uiLen );
      return FALSE;
   }
   szEndChar = szBuffer[ uiLen ];
   sprintf( szBuffer, "%*.*f", uiLen, uiDec, dValue );
   szBuffer[ uiLen ] = szEndChar;
   return TRUE;
}

static BOOL hb_dbfUpdateHeader( AREAP pArea, ULONG lRecCount )
{
   DBFHEADER pHeader;
   time_t t;
   struct tm * pTime;

   HB_TRACE(HB_TR_DEBUG, ("hb_dbfUpdateHeader(%p, %lu)", pArea, lRecCount));

   hb_fsSeek( pArea->lpDataInfo->hFile, 0, FS_SET );
   if( hb_fsRead( pArea->lpDataInfo->hFile, ( BYTE * ) &pHeader,
                  sizeof( DBFHEADER ) ) != sizeof( DBFHEADER ) )
      return FALSE;

   time( &t );
   pTime =  localtime( &t );
   pHeader.bYear = ( BYTE ) pTime->tm_year;
   pHeader.bMonth = ( BYTE ) pTime->tm_mon + 1;
   pHeader.bDay = ( BYTE ) pTime->tm_mday;
   pHeader.ulRecords = lRecCount;

   hb_fsSeek( pArea->lpDataInfo->hFile, 0, FS_SET );
   if( hb_fsWrite( pArea->lpDataInfo->hFile, ( BYTE * ) &pHeader,
                   sizeof( DBFHEADER ) ) != sizeof( DBFHEADER ) )
      return FALSE;

   pArea->lpExtendInfo->bYear = pHeader.bYear;
   pArea->lpExtendInfo->bMonth = pHeader.bMonth;
   pArea->lpExtendInfo->bDay = pHeader.bDay;
   return TRUE;
}

static BOOL hb_dbfWriteMemo( AREAP pArea, LPDBFMEMO pMemo, ULONG * lNewRecNo )
{
   USHORT uiNumBlocks, uiBytesRead, uiRead, uiCount;
   BYTE szBuffer[ MEMO_BLOCK ];
   MEMOHEADER pMemoHeader;

   HB_TRACE(HB_TR_DEBUG, ("hb_dbfWriteMemo(%p, %p, %p)", pArea, pMemo, lNewRecNo));

   if( !pArea->lpExtendInfo->fExclusive && !pArea->lpDataInfo->fFileLocked &&
       !hb_fsLock( pArea->lpDataInfo->pNext->hFile, LOCK_APPEND - 1, 1, FL_LOCK ) )
      return FALSE;

   uiNumBlocks = ( pMemo->uiLen + MEMO_BLOCK - 1 ) / MEMO_BLOCK;
   if( * lNewRecNo > 0 )
   {
      uiBytesRead = 0;
      hb_fsSeek( pArea->lpDataInfo->pNext->hFile, * lNewRecNo * MEMO_BLOCK, FS_SET );
      do
      {
         uiBytesRead += MEMO_BLOCK;
         uiRead = hb_fsRead( pArea->lpDataInfo->pNext->hFile, szBuffer, MEMO_BLOCK );
         if( !uiRead )
         {
            if( !pArea->lpExtendInfo->fExclusive && !pArea->lpDataInfo->fFileLocked )
               hb_fsLock( pArea->lpDataInfo->pNext->hFile, LOCK_APPEND - 1, 1, FL_UNLOCK );
            return FALSE;
         }
         for( uiCount = 0; uiCount < uiRead; uiCount++ )
            if( szBuffer[ uiCount ] == 0x1A )
               break;
      } while( uiCount >= MEMO_BLOCK && szBuffer[ uiCount ] != 0x1A );
      if( uiBytesRead <= pMemo->uiLen )        /* Not room for data */
         * lNewRecNo = 0;
   }

   if( * lNewRecNo == 0 )                    /* Add an entry at eof */
   {
      hb_fsSeek( pArea->lpDataInfo->pNext->hFile, 0, FS_SET );
      hb_fsRead( pArea->lpDataInfo->pNext->hFile, ( BYTE * ) &pMemoHeader,
                 sizeof( MEMOHEADER ) );
      * lNewRecNo = pMemoHeader.lNextBlock;
      pMemoHeader.lNextBlock = * lNewRecNo + uiNumBlocks;
      hb_fsSeek( pArea->lpDataInfo->pNext->hFile, 0, FS_SET );
      hb_fsWrite( pArea->lpDataInfo->pNext->hFile, ( BYTE * ) &pMemoHeader,
                  sizeof( MEMOHEADER ) );
   }

   hb_fsSeek( pArea->lpDataInfo->pNext->hFile, * lNewRecNo * MEMO_BLOCK, FS_SET );
   if( hb_fsWrite( pArea->lpDataInfo->pNext->hFile, pMemo->pData,
                  pMemo->uiLen ) != pMemo->uiLen )
   {
      if( !pArea->lpExtendInfo->fExclusive && !pArea->lpDataInfo->fFileLocked )
         hb_fsLock( pArea->lpDataInfo->pNext->hFile, LOCK_APPEND - 1, 1, FL_UNLOCK );
      return FALSE;
   }

   szBuffer[ 0 ] = 0x1A;
   if( hb_fsWrite( pArea->lpDataInfo->pNext->hFile, szBuffer, 1 ) != 1 )
   {
      if( !pArea->lpExtendInfo->fExclusive && !pArea->lpDataInfo->fFileLocked )
         hb_fsLock( pArea->lpDataInfo->pNext->hFile, LOCK_APPEND - 1, 1, FL_UNLOCK );
      return FALSE;
   }

   if( !pArea->lpExtendInfo->fExclusive && !pArea->lpDataInfo->fFileLocked )
      hb_fsLock( pArea->lpDataInfo->pNext->hFile, LOCK_APPEND - 1, 1, FL_UNLOCK );
   return TRUE;
}

static BOOL hb_dbfUpdateRecord( AREAP pArea, ULONG ulRecNo )
{
   ULONG ulRecCount = 0;
   USHORT uiCount;
   LPFIELD pField;
   BYTE pBuffer[ 1 ];

   HB_TRACE(HB_TR_DEBUG, ("hb_dbfUpdateRecord(%p, %lu)", pArea, ulRecNo));

   if( ulRecNo > pArea->lpExtendInfo->ulRecCount )
   {
      if( SELF_RECCOUNT( pArea, &ulRecCount ) == FAILURE )
         return FALSE;
      pArea->lpExtendInfo->ulRecCount = ulRecCount;
   }

   if( ulRecNo > 0 && ( ulRecNo <= ulRecCount || pArea->lpDataInfo->fAppend ) )
   {
      hb_fsSeek( pArea->lpDataInfo->hFile, pArea->lpExtendInfo->uiHeaderLen +
                 ( ulRecNo - 1 ) * pArea->lpExtendInfo->uiRecordLen, FS_SET );
      if( pArea->lpDataInfo->fAppend )
         pArea->lpExtendInfo->ulRecCount = ulRecNo;
      if( pArea->lpExtendInfo->fHasMemo )
      {
         for( uiCount = 0; uiCount < pArea->uiFieldCount; uiCount++ )
         {
            pField = pArea->lpFields + uiCount;
            if( pField->uiType == 'M' && ( ( LPDBFMEMO ) pField->memo )->fChanged )
               if( SELF_GETVALUEFILE( pArea, uiCount + 1, NULL ) == FAILURE )
                  return FALSE;
         }
      }
      if( hb_fsWrite( pArea->lpDataInfo->hFile, pArea->lpExtendInfo->bRecord,
                      pArea->lpExtendInfo->uiRecordLen ) != pArea->lpExtendInfo->uiRecordLen )
         return FALSE;

      /* Write EOF */
      if( pArea->lpDataInfo->fAppend )
      {
         pBuffer[ 0 ] = 0x1A;
         if( hb_fsWrite( pArea->lpDataInfo->hFile, pBuffer, 1 ) != 1 )
            return FALSE;
      }

      if( !hb_dbfUpdateHeader( pArea, pArea->lpExtendInfo->ulRecCount ) )
         return FALSE;
   }

   return TRUE;
}

static void hb_dbfClearBuffer( AREAP pArea )
{
   LPFIELD pField;
   USHORT uiCount;

   HB_TRACE(HB_TR_DEBUG, ("hb_dbfClearBuffer(%p)", pArea));

   memset( pArea->lpExtendInfo->bRecord, ' ', pArea->lpExtendInfo->uiRecordLen );
   pArea->lpExtendInfo->bRecord[ pArea->lpExtendInfo->uiRecordLen ] = 0;
   pArea->lpExtendInfo->fValidBuffer = TRUE;

   if( pArea->lpExtendInfo->fHasMemo )
   {
      for( uiCount = 0; uiCount < pArea->uiFieldCount; uiCount++ )
      {
         pField = pArea->lpFields + uiCount;
         if( pField->memo )
         {
            if( ( ( LPDBFMEMO ) pField->memo )->pData )
            {
               hb_xfree( ( ( LPDBFMEMO ) pField->memo )->pData );
               memset( pField->memo, 0, sizeof( DBFMEMO ) );
            }
         }
      }
   }
}

static void hb_dbfReadMemo( AREAP pArea, LPDBFMEMO pMemo, ULONG lMemoBlock )
{
   USHORT uiBytesRead, uiMaxRead, uiRead;
   BYTE * pData;

   HB_TRACE(HB_TR_DEBUG, ("hb_dbfReadMemo(%p, %p, %lu)", pArea, pMemo, lMemoBlock));

   hb_fsSeek( pArea->lpDataInfo->pNext->hFile, lMemoBlock, FS_SET );
   uiBytesRead = 0;
   uiMaxRead = pMemo->uiLen;
   for(;;)
   {
      if( uiMaxRead < MEMO_BLOCK )
      {
         pData = ( BYTE * ) hb_xgrab( uiBytesRead + MEMO_BLOCK + 1 );
         if( pMemo->uiLen > 0 )
         {
            memcpy( pData, pMemo->pData, pMemo->uiLen );
            hb_xfree( pMemo->pData );
         }
         pMemo->pData = pData;
         pMemo->uiLen = uiBytesRead + MEMO_BLOCK + 1;
         uiMaxRead = MEMO_BLOCK;
      }
      uiRead = hb_fsRead( pArea->lpDataInfo->pNext->hFile,
                          pMemo->pData + uiBytesRead, uiMaxRead );
      if( !uiRead )
         return;

      for(; uiRead > 0; uiBytesRead++, uiRead-- )
      {
         if( pMemo->pData[ uiBytesRead ] == 0x1A )
         {
            if( uiBytesRead > 0 )
            {
               pData = ( BYTE * ) hb_xgrab( uiBytesRead + 1 );
               memcpy( pData, pMemo->pData, uiBytesRead );
               pData[ uiBytesRead ] = 0;
            }
            else
               pData = 0;
            hb_xfree( pMemo->pData );
            pMemo->pData = pData;
            pMemo->uiLen = uiBytesRead;
            return;
         }
      }
      uiMaxRead = 0;
   }
}

static void hb_dbfReadBuffer( AREAP pArea, ULONG lRecNo )
{
   LPFIELD pField;
   USHORT uiCount;

   HB_TRACE(HB_TR_DEBUG, ("hb_dbfReadBuffer(%p, %lu)", pArea, lRecNo));

   if( pArea->lpExtendInfo->fValidBuffer )
      return;

   pArea->lpExtendInfo->fValidBuffer = TRUE;
   if( hb_fsSeek( pArea->lpDataInfo->hFile, pArea->lpExtendInfo->uiHeaderLen +
                  ( lRecNo - 1 ) * pArea->lpExtendInfo->uiRecordLen, FS_SET ) !=
       pArea->lpExtendInfo->uiHeaderLen + ( lRecNo - 1 ) * pArea->lpExtendInfo->uiRecordLen ||
       hb_fsRead( pArea->lpDataInfo->hFile, pArea->lpExtendInfo->bRecord,
                  pArea->lpExtendInfo->uiRecordLen ) != pArea->lpExtendInfo->uiRecordLen )
   {
      hb_dbfClearBuffer( pArea );
      return;
   }

   if( pArea->lpExtendInfo->fHasMemo && pArea->lpDataInfo->pNext )
   {
      pField = pArea->lpFields;
      for( uiCount = 0; uiCount < pArea->uiFieldCount; uiCount++ )
      {
         if( pField->uiType == 'M' )
            SELF_PUTVALUEFILE( pArea, uiCount + 1, NULL );
         pField = pField->lpfNext;
      }
   }
}

static BOOL hb_dbfIsLocked( AREAP pArea, ULONG lLockPos )
{
   ULONG lNumLocksPos;

   HB_TRACE(HB_TR_DEBUG, ("hb_dbfIsLocked(%p, %lu)", pArea, lLockPos));

   lNumLocksPos = pArea->lpDataInfo->lNumLocksPos;
   while( lNumLocksPos > 0 )
   {
      if( pArea->lpDataInfo->pLocksPos[ lNumLocksPos - 1 ] == lLockPos )
         return TRUE;
      lNumLocksPos--;
   }

   return FALSE;
}

static BOOL hb_dbfLockRecord( AREAP pArea, ULONG lRecNum )
{
   LPFILEINFO pFileInfo;

   HB_TRACE(HB_TR_DEBUG, ("hb_dbfLockRecord(%p, %lu)", pArea, lRecNum));

   if( pArea->lpExtendInfo->fExclusive || pArea->lpDataInfo->fFileLocked )
      return TRUE;

   pFileInfo = pArea->lpDataInfo;
   if( hb_dbfIsLocked( pArea, lRecNum ) )
      return TRUE;

   if( !hb_fsLock( pArea->lpDataInfo->hFile, LOCK_START +
                   pArea->lpExtendInfo->uiHeaderLen +
                   ( lRecNum - 1 ) * pArea->lpExtendInfo->uiRecordLen, 1, FL_LOCK ) )
      return FALSE;

   if( pFileInfo->lNumLocksPos == 0 )            /* Create the list */
   {
      pFileInfo->pLocksPos = ( ULONG * ) hb_xgrab( sizeof( ULONG ) );
      pFileInfo->pLocksPos[ 0 ] = lRecNum;
   }
   else                                          /* Resize the list */
   {
      pFileInfo->pLocksPos = ( ULONG * )
                    hb_xrealloc( pFileInfo->pLocksPos,
                                 ( pFileInfo->lNumLocksPos + 1 ) *
                                 sizeof( ULONG ) );
      pFileInfo->pLocksPos[ pFileInfo->lNumLocksPos ] = lRecNum;
   }
   pFileInfo->lNumLocksPos++;

   return TRUE;
}

static BOOL hb_dbfUnLockRecord( AREAP pArea, ULONG lRecNum )
{
   LPFILEINFO pFileInfo;
   ULONG lLockPos, * pList;

   HB_TRACE(HB_TR_DEBUG, ("hb_dbfUnLockRecord(%p, %lu)", pArea, lRecNum));

   if( pArea->lpExtendInfo->fExclusive || pArea->lpDataInfo->fFileLocked )
      return TRUE;

   pFileInfo = pArea->lpDataInfo;
   if( !hb_dbfIsLocked( pArea, lRecNum ) )
      return TRUE;

   if( !hb_fsLock( pArea->lpDataInfo->hFile, LOCK_START +
                   pArea->lpExtendInfo->uiHeaderLen +
                   ( lRecNum - 1 ) * pArea->lpExtendInfo->uiRecordLen, 1, FL_UNLOCK ) )
      return FALSE;

   if( pFileInfo->lNumLocksPos == 1 )            /* Delete the list */
   {
      hb_xfree( pFileInfo->pLocksPos );
      pFileInfo->lNumLocksPos = 0;
   }
   else                                          /* Resize the list */
   {
      /* Search the locked record */
      for( lLockPos = 0; lLockPos < pFileInfo->lNumLocksPos; lLockPos++ )
      {
         if( pFileInfo->pLocksPos[ lLockPos ] == lRecNum )
         {
            pList = pFileInfo->pLocksPos + lLockPos;
            memmove( pList, pList + 1,
                     ( pFileInfo->lNumLocksPos - lLockPos - 1 ) *
                     sizeof( ULONG ) );
            pFileInfo->pLocksPos = ( ULONG * )
                    hb_xrealloc( pFileInfo->pLocksPos,
                                 ( pFileInfo->lNumLocksPos - 1 ) *
                                 sizeof( ULONG ) );
            pFileInfo->lNumLocksPos--;
            return TRUE;
         }
      }
   }

   return TRUE;
}

static BOOL hb_dbfUnLockAllRecords( AREAP pArea )
{
   LPFILEINFO pFileInfo;
   ULONG lPosLocked;
   BOOL bUnLocked = TRUE;

   HB_TRACE(HB_TR_DEBUG, ("hb_dbfUnLockAllRecords(%p)", pArea));

   if( SELF_GOCOLD( pArea ) == FAILURE )
      return FALSE;

   if( pArea->lpExtendInfo->fExclusive )
      return TRUE;

   pFileInfo = pArea->lpDataInfo;
   for( lPosLocked = 0; lPosLocked < pFileInfo->lNumLocksPos; lPosLocked++ )
      if( !hb_fsLock( pArea->lpDataInfo->hFile, LOCK_START +
                   pArea->lpExtendInfo->uiHeaderLen +
                   ( pFileInfo->pLocksPos[ lPosLocked ] - 1 ) *
                   pArea->lpExtendInfo->uiRecordLen, 1, FL_UNLOCK ) )
         bUnLocked = FALSE;

   if( pFileInfo->lNumLocksPos > 0 )
      hb_xfree( pFileInfo->pLocksPos );
   pFileInfo->pLocksPos = NULL;
   pFileInfo->lNumLocksPos = 0;

   return bUnLocked;
}

static BOOL hb_dbfLockFile( AREAP pArea )
{
   HB_TRACE(HB_TR_DEBUG, ("hb_dbfLockFile(%p)", pArea));

   if( pArea->lpExtendInfo->fExclusive || pArea->lpDataInfo->fFileLocked )
      return TRUE;

   if( !hb_fsLock( pArea->lpDataInfo->hFile, LOCK_START, LOCK_FILE, FL_LOCK ) )
      return FALSE;
   pArea->lpDataInfo->fFileLocked = TRUE;
   return TRUE;
}

static BOOL hb_dbfUnLockFile( AREAP pArea )
{
   HB_TRACE(HB_TR_DEBUG, ("hb_dbfUnLockFile(%p)", pArea));

   if( SELF_GOCOLD( pArea ) == FAILURE )
      return FALSE;

   if( pArea->lpExtendInfo->fExclusive )
      return TRUE;

   hb_dbfUnLockAllRecords( pArea );
   if( pArea->lpDataInfo->fFileLocked )
   {
     if( !hb_fsLock( pArea->lpDataInfo->hFile, LOCK_START, LOCK_FILE, FL_UNLOCK ) )
        return FALSE;
      pArea->lpDataInfo->fFileLocked = FALSE;
   }
   return TRUE;
}

static void hb_dbfGetLockArray( AREAP pArea, PHB_ITEM pItem )
{
   ULONG lLockPos;

   HB_TRACE(HB_TR_DEBUG, ("hb_GetLockArray(%p, %p)", pArea, pItem));

   for( lLockPos = 1; lLockPos <= pArea->lpDataInfo->lNumLocksPos; lLockPos++ )
      hb_arrayAdd( pItem,
         hb_itemPutNL( NULL, pArea->lpDataInfo->pLocksPos[ lLockPos - 1 ] ) );
}

static RDDFUNCS dbfSuper = { 0 };


/*
 * -- DBF METHODS --
 */

#define dbfBof                                  NULL
#define dbfEof                                  NULL
#define dbfFound                                NULL
#define dbfSeek                                 NULL
#define dbfSkip                                 NULL
#define dbfSkipFilter                           NULL
#define dbfSkipRaw                              NULL
#define dbfCreateFields                         NULL
#define dbfFieldCount                           NULL
#define dbfFieldDisplay                         NULL
#define dbfFieldInfo                            NULL
#define dbfFieldName                            NULL
#define dbfSetFieldsExtent                      NULL
#define dbfAlias                                NULL
#define dbfNewArea                              NULL
#define dbfStructSize                           NULL
#define dbfSysName                              NULL
#define dbfEval                                 NULL
#define dbfOrderListAdd                         NULL
#define dbfOrderListClear                       NULL
#define dbfOrderListFocus                       NULL
#define dbfOrderListRebuild                     NULL
#define dbfOrderCondition                       NULL
#define dbfOrderCreate                          NULL
#define dbfOrderDestroy                         NULL
#define dbfOrderInfo                            NULL
#define dbfClearFilter                          NULL
#define dbfClearLocate                          NULL
#define dbfClearScope                           NULL
#define dbfCountScope                           NULL
#define dbfFilterText                           NULL
#define dbfScopeInfo                            NULL
#define dbfSetFilter                            NULL
#define dbfSetLocate                            NULL
#define dbfSetScope                             NULL
#define dbfSkipScope                            NULL
#define dbfCompile                              NULL
#define dbfError                                NULL
#define dbfEvalBlock                            NULL
#define dbfWhoCares                             NULL

static ERRCODE dbfAddField( AREAP pArea, LPDBFIELDINFO pFieldInfo )
{
   LPFIELD pField;

   HB_TRACE(HB_TR_DEBUG, ("dbfAddField(%p, %p)", pArea, pFieldInfo));

   if( SUPER_ADDFIELD( pArea, pFieldInfo ) == SUCCESS )
   {
      /* Validate the type */
      if( pFieldInfo->uiType != 'C' && pFieldInfo->uiType != 'N' &&
          pFieldInfo->uiType != 'M' && pFieldInfo->uiType != 'D' &&
          pFieldInfo->uiType != 'L' )
         return FAILURE;

      /* Validate the size */
      if( !pFieldInfo->uiLen )
         return FAILURE;

      if( pArea->lpExtendInfo->fHasMemo )
      {
         pField = pArea->lpFields + pArea->uiFieldCount - 1;
         pField->memo = ( void * ) hb_xgrab( sizeof( DBFMEMO ) );
         memset( pField->memo, 0, sizeof( DBFMEMO ) );
      }
      return SUCCESS;
   }
   return FAILURE;
}

static ERRCODE dbfAppend( AREAP pArea, BOOL bUnLockAll )
{
   ULONG ulRecCount, ulRecNo;
   PHB_ITEM pError;

   HB_TRACE(HB_TR_DEBUG, ("dbfAppend(%p, %d)", pArea, (int) bUnLockAll));

   if( SELF_GOCOLD( pArea ) == FAILURE )
      return FAILURE;

   if( pArea->lpExtendInfo->fReadOnly )
   {
      pError = hb_errNew();
      hb_errPutGenCode( pError, EG_READONLY );
      hb_errPutDescription( pError, hb_langDGetErrorDesc( EG_READONLY ) );
      hb_errPutSubCode( pError, 1025 );
      SELF_ERROR( pArea, pError );
      hb_errRelease( pError );
      return FAILURE;
   }

   if( SELF_RECCOUNT( pArea, &ulRecCount ) == FAILURE )
      return FAILURE;
   pArea->lpExtendInfo->ulRecCount = ulRecCount;

   if( !pArea->lpExtendInfo->fExclusive && !pArea->lpDataInfo->fFileLocked )
   {
      if( bUnLockAll && !hb_dbfUnLockAllRecords( pArea ) )
         return FAILURE;

      if( !hb_fsLock( pArea->lpDataInfo->hFile, LOCK_START, 1, FL_LOCK ) )
         return FAILURE;
   }

   ulRecNo = ulRecCount + 1;
   SELF_GOTO( pArea, ulRecNo );
   pArea->fEof = FALSE;
   hb_dbfClearBuffer( pArea );
   pArea->lpExtendInfo->fRecordChanged = TRUE;
   pArea->lpDataInfo->fAppend = TRUE;
   if( !hb_dbfUpdateRecord( pArea, ulRecNo ) )
   {
      if( !pArea->lpExtendInfo->fExclusive && !pArea->lpDataInfo->fFileLocked )
         hb_fsLock( pArea->lpDataInfo->hFile, LOCK_START, 1, FL_UNLOCK );
      return FAILURE;
   }

   if( !hb_dbfLockRecord( pArea, ulRecNo ) )
   {
      if( !pArea->lpExtendInfo->fExclusive && !pArea->lpDataInfo->fFileLocked )
         hb_fsLock( pArea->lpDataInfo->hFile, LOCK_START, 1, FL_UNLOCK );
      return FAILURE;
   }

   if( !pArea->lpExtendInfo->fExclusive && !pArea->lpDataInfo->fFileLocked &&
       !hb_fsLock( pArea->lpDataInfo->hFile, LOCK_START, 1, FL_UNLOCK ) )
      return FAILURE;

   return SUCCESS;
}

static ERRCODE dbfClose( AREAP pArea )
{
   HB_TRACE(HB_TR_DEBUG, ("dbfClose(%p)", pArea));

   if( pArea->lpDataInfo->hFile != FS_ERROR )
   {
      SELF_GOCOLD( pArea );
      SELF_RAWLOCK( pArea, FILE_UNLOCK, 0 );
      SELF_FLUSH( pArea );
      hb_fsClose( pArea->lpDataInfo->hFile );
      pArea->lpDataInfo->hFile = FS_ERROR;
   }
   if( pArea->lpExtendInfo->fHasMemo )
      SELF_CLOSEMEMFILE( pArea );

   return SUPER_CLOSE( pArea );
}

static ERRCODE dbfCloseMemFile( AREAP pArea )
{
   HB_TRACE(HB_TR_DEBUG, ("dbfCloseMemFile(%p)", pArea));

   if( pArea->lpDataInfo->pNext->hFile != FS_ERROR )
   {
      SELF_FLUSH( pArea );
      hb_fsClose( pArea->lpDataInfo->pNext->hFile );
      pArea->lpDataInfo->pNext->hFile = FS_ERROR;
   }

   return SUCCESS;
}

static ERRCODE dbfCreate( AREAP pArea, LPDBOPENINFO pCreateInfo )
{
   PHB_ITEM pError = NULL;
   BOOL bRetry;

   HB_TRACE(HB_TR_DEBUG, ("dbfCreate(%p, %p)", pArea, pCreateInfo));

   do
   {
      pArea->lpDataInfo->hFile = hb_fsCreate( pCreateInfo->abName, FC_NORMAL );
      if( pArea->lpDataInfo->hFile == FS_ERROR )
      {
         if( !pError )
         {
            pError = hb_errNew();
            hb_errPutGenCode( pError, EG_CREATE );
            hb_errPutSubCode( pError, 1004 );
            hb_errPutDescription( pError, hb_langDGetErrorDesc( EG_CREATE ) );
            hb_errPutFileName( pError, ( char * ) pCreateInfo->abName );
            hb_errPutFlags( pError, EF_CANRETRY );
         }
         bRetry = ( SELF_ERROR( pArea, pError ) == E_RETRY );
      }
      else
         bRetry = FALSE;
   } while( bRetry );
   if( pError )
      hb_errRelease( pError );

   if( pArea->lpDataInfo->hFile == FS_ERROR )
      return FAILURE;

   if( SELF_WRITEDBHEADER( pArea ) == FAILURE )
   {
      hb_fsClose( pArea->lpDataInfo->hFile );
      pArea->lpDataInfo->hFile = FS_ERROR;
      return FAILURE;
   }

   hb_fsClose( pArea->lpDataInfo->hFile );
   pArea->lpDataInfo->hFile = FS_ERROR;
   return SUCCESS;
}

static ERRCODE dbfCreateMemFile( AREAP pArea, LPDBOPENINFO pCreateInfo )
{
   LPFILEINFO lpMemInfo;
   LPMEMOHEADER pMemoHeader;
   BOOL bError;
   PHB_ITEM pError = NULL;
   BYTE * pBuffer;

   HB_TRACE(HB_TR_DEBUG, ("dbfCreateMemFile(%p, %p)", pArea, pCreateInfo));

   lpMemInfo = pArea->lpDataInfo->pNext;
   do
   {
      lpMemInfo->hFile = hb_fsCreate( pCreateInfo->abName, FC_NORMAL );
      if( lpMemInfo->hFile == FS_ERROR )
      {
         if( !pError )
         {
            pError = hb_errNew();
            hb_errPutGenCode( pError, EG_CREATE );
            hb_errPutSubCode( pError, 1005 );
            hb_errPutDescription( pError, hb_langDGetErrorDesc( EG_CREATE ) );
            hb_errPutFileName( pError, ( char * ) pCreateInfo->abName );
            hb_errPutFlags( pError, EF_CANRETRY );
         }
         bError = ( SELF_ERROR( pArea, pError ) == E_RETRY );
      }
      else
         bError = FALSE;
   } while( bError );
   if( pError )
      hb_errRelease( pError );

   if( lpMemInfo->hFile == FS_ERROR )
      return FAILURE;

   pMemoHeader = ( LPMEMOHEADER ) hb_xgrab( MEMO_BLOCK + 1 );
   memset( pMemoHeader, 0, MEMO_BLOCK + 1 );
   pMemoHeader->lNextBlock = 1;
   pBuffer = ( BYTE * ) pMemoHeader;
   pBuffer[ MEMO_BLOCK ] = 0x1A;
   bError = ( hb_fsWrite( lpMemInfo->hFile, ( BYTE * ) pMemoHeader,
                          MEMO_BLOCK + 1 ) != MEMO_BLOCK + 1 );
   hb_xfree( pMemoHeader );
   hb_fsClose( lpMemInfo->hFile );
   lpMemInfo->hFile = FS_ERROR;
   if( bError )
      return FAILURE;
   else
      return SUCCESS;
}

static ERRCODE dbfDeleted( AREAP pArea, BOOL * pDeleted )
{
   BYTE * pBuffer;

   HB_TRACE(HB_TR_DEBUG, ("dbfDeleted(%p, %p)", pArea, pDeleted));

   SELF_GETREC( pArea, &pBuffer );
   * pDeleted = ( pBuffer[ 0 ] ==  '*' );

   return SUCCESS;
}

static ERRCODE dbfDeleteRec( AREAP pArea )
{
   BYTE * pBuffer;

   HB_TRACE(HB_TR_DEBUG, ("dbfDeleteRec(%p)", pArea));

   if( SELF_GOHOT( pArea ) == FAILURE )
      return FAILURE;

   SELF_GETREC( pArea, &pBuffer );
   if( pBuffer[ 0 ] ==  '*' )
   {
      pArea->lpExtendInfo->fRecordChanged = FALSE;
      return SUCCESS;
   }

   pBuffer[ 0 ] =  '*';
   return SUCCESS;
}

static ERRCODE dbfFlush( AREAP pArea )
{
   HB_TRACE(HB_TR_DEBUG, ("dbfFlush(%p)", pArea));

   if( SELF_GOCOLD( pArea ) == FAILURE )
      return FAILURE;

   if( pArea->lpDataInfo->hFile != FS_ERROR )
      hb_fsCommit( pArea->lpDataInfo->hFile );
   if( pArea->lpExtendInfo->fHasMemo && pArea->lpDataInfo->pNext->hFile != FS_ERROR )
      hb_fsCommit( pArea->lpDataInfo->pNext->hFile );
   return FAILURE;
}

static ERRCODE dbfGetRec( AREAP pArea, BYTE ** pBuffer )
{
   HB_TRACE(HB_TR_DEBUG, ("dbfGetRec(%p, %p)", pArea, pBuffer));

   if( !pArea->lpExtendInfo->fValidBuffer )
      hb_dbfReadBuffer( pArea, pArea->lpExtendInfo->ulRecNo );

   * pBuffer = pArea->lpExtendInfo->bRecord;
   return SUCCESS;
}

static ERRCODE dbfGetValue( AREAP pArea, USHORT uiIndex, PHB_ITEM pItem )
{
   LPFIELD pField;
   BYTE * pBuffer, * szText, szEndChar;

   HB_TRACE(HB_TR_DEBUG, ("dbfGetValue(%p, %hu, %p)", pArea, uiIndex, pItem));

   if( uiIndex > pArea->uiFieldCount )
      return FAILURE;

   SELF_GETREC( pArea, &pBuffer );
   pField = pArea->lpFields + uiIndex - 1;
   szText = pBuffer + pField->uiOffset;
   switch( pField->uiType )
   {
      case 'C':
         hb_itemPutCL( pItem, ( char * ) szText,
                       pField->uiLen + ( ( USHORT ) pField->uiDec << 8 ) );
         break;

      case 'N':
         szEndChar = * ( szText + pField->uiLen );
         * ( szText + pField->uiLen ) = '\0';
         if( pField->uiDec )
            hb_itemPutNDLen( pItem, atof( ( char * ) szText ), ( int ) pField->uiLen - ( ( int ) pField->uiDec + 1 ), ( int ) pField->uiDec );
         else
            hb_itemPutNLLen( pItem, atol( ( char * ) szText ), ( int ) pField->uiLen );
         * ( szText + pField->uiLen ) = szEndChar;
         break;

      case 'D':
         szEndChar = * ( szText + pField->uiLen );
         * ( szText + pField->uiLen ) = '\0';
         hb_itemPutDS( pItem, ( char * ) szText );
         * ( szText + pField->uiLen ) = szEndChar;
         break;

      case 'L':
         if( * szText == 'T' )
            hb_itemPutL( pItem, TRUE );
         else
            hb_itemPutL( pItem, FALSE );
         break;

      case 'M':
         if( ( ( LPDBFMEMO ) pField->memo )->pData )
            hb_itemPutCL( pItem, ( char * ) ( ( LPDBFMEMO ) pField->memo )->pData,
                          ( ( LPDBFMEMO ) pField->memo )->uiLen );
         else
            hb_itemPutC( pItem, "" );

         hb_itemSetCMemo( pItem );
         break;
   }
   return SUCCESS;
}

static ERRCODE dbfGetValueFile( AREAP pArea, USHORT uiIndex, void * pFile )
{
   ULONG lRecNo, lNewRecNo;
   BYTE * pBuffer, * szText, szEndChar;
   LPFIELD pField;

   HB_TRACE(HB_TR_DEBUG, ("dbfGetValueFile(%p, %hu, %p)", pArea, uiIndex, pFile));

   HB_SYMBOL_UNUSED( pFile );

   if( uiIndex > pArea->uiFieldCount )
      return FAILURE;

   SELF_GETREC( pArea, &pBuffer );
   pField = pArea->lpFields + uiIndex - 1;
   szText = pBuffer + pField->uiOffset;
   if( !( ( LPDBFMEMO ) pField->memo )->pData )
      memset( szText, ' ', pField->uiLen );
   else
   {
      szEndChar = * ( szText + pField->uiLen );
      * ( szText + pField->uiLen ) = 0;
      lRecNo = atol( ( char * ) szText );
      lNewRecNo = lRecNo;
      if( !hb_dbfWriteMemo( pArea, ( LPDBFMEMO ) pField->memo, &lNewRecNo ) )
         return FAILURE;
      if( lNewRecNo != lRecNo )
         hb_nltoa( lNewRecNo, ( char * ) szText, pField->uiLen );
      * ( szText + pField->uiLen ) = szEndChar;
   }
   ( ( LPDBFMEMO ) pField->memo )->fChanged = FALSE;

   return SUCCESS;
}

static ERRCODE dbfGetVarLen( AREAP pArea, USHORT uiIndex, ULONG * ulLen )
{
   LPFIELD pField;

   HB_TRACE(HB_TR_DEBUG, ("dbfGetVarLen(%p, %hu, %p)", pArea, uiIndex, ulLen));

   if( uiIndex > pArea->uiFieldCount )
      return FAILURE;

   pField = pArea->lpFields + uiIndex - 1;
   if( pField->uiType == 'M' )
      * ulLen = ( ( LPDBFMEMO ) pField->memo )->uiLen;
   else
      * ulLen = pField->uiLen;
   return SUCCESS;
}

static ERRCODE dbfGoBottom( AREAP pArea )
{
   ULONG ulRecCount;

   HB_TRACE(HB_TR_DEBUG, ("dbfGoBottom(%p)", pArea));

   if( SELF_RECCOUNT( pArea, &ulRecCount ) == FAILURE )
      return FAILURE;
   pArea->lpExtendInfo->ulRecCount = ulRecCount;

   SELF_GOTO( pArea, ulRecCount );
   return SELF_SKIPFILTER( pArea, -1 );
}

static ERRCODE dbfGoCold( AREAP pArea )
{
   HB_TRACE(HB_TR_DEBUG, ("dbfGoCold(%p)", pArea));

   if( pArea->lpExtendInfo->fRecordChanged &&
       !hb_dbfUpdateRecord( pArea, pArea->lpExtendInfo->ulRecNo ) )
      return FAILURE;

   pArea->lpExtendInfo->fRecordChanged = FALSE;
   pArea->lpDataInfo->fAppend = FALSE;
   return SUCCESS;
}

static ERRCODE dbfGoHot( AREAP pArea )
{
   PHB_ITEM pError;

   HB_TRACE(HB_TR_DEBUG, ("dbfGoHot(%p)", pArea));

   if( !pArea->lpExtendInfo->fExclusive && !pArea->lpDataInfo->fFileLocked &&
       !hb_dbfIsLocked( pArea, pArea->lpExtendInfo->ulRecNo ) )
   {
      pError = hb_errNew();
      hb_errPutGenCode( pError, EG_UNLOCKED );
      hb_errPutDescription( pError, hb_langDGetErrorDesc( EG_UNLOCKED ) );
      hb_errPutSubCode( pError, 1022 );
      SELF_ERROR( pArea, pError );
      hb_errRelease( pError );
      return FAILURE;
   }

   if( pArea->lpExtendInfo->fReadOnly )
   {
      pError = hb_errNew();
      hb_errPutGenCode( pError, EG_READONLY );
      hb_errPutDescription( pError, hb_langDGetErrorDesc( EG_READONLY ) );
      hb_errPutSubCode( pError, 1025 );
      SELF_ERROR( pArea, pError );
      hb_errRelease( pError );
      return FAILURE;
   }
   pArea->lpExtendInfo->fRecordChanged = TRUE;
   return SUCCESS;
}

static ERRCODE dbfGoTo( AREAP pArea, ULONG ulRecNo )
{
   ULONG ulRecCount;

   HB_TRACE(HB_TR_DEBUG, ("dbfGoTo(%p, %lu)", pArea, ulRecNo));

   if( SELF_GOCOLD( pArea ) == FAILURE )
      return FAILURE;

   if( ulRecNo > pArea->lpExtendInfo->ulRecCount )
   {
      if( SELF_RECCOUNT( pArea, &ulRecCount ) == FAILURE )
         return FAILURE;
      pArea->lpExtendInfo->ulRecCount = ulRecCount;
   }
   else 
      ulRecCount = pArea->lpExtendInfo->ulRecCount;

   if( ulRecCount < 1 )
   {
      pArea->fBof = 1;
      pArea->fEof = 1;
      ulRecNo = 1;
   }
   else
   {
      if( ulRecNo > ulRecCount + 1 )
         ulRecNo = ulRecCount + 1;

      if( ulRecNo <= 0 )
      {
         pArea->fBof = 1;
         ulRecNo = 1;
      }
      else
         pArea->fBof = ( ulRecNo == 1 && pArea->fBof );

      pArea->fEof = ( ulRecNo == ulRecCount + 1 );
   }

   pArea->lpExtendInfo->ulRecNo = ulRecNo;
   if( ulRecCount > 0 )
      pArea->lpExtendInfo->fValidBuffer = FALSE;
   else
      hb_dbfClearBuffer( pArea );

   return SUCCESS;
}

static ERRCODE dbfGoToId( AREAP pArea, PHB_ITEM pItem )
{
   PHB_ITEM pError;
   ULONG ulRecNo;

   HB_TRACE(HB_TR_DEBUG, ("dbfGoToId(%p, %p)", pArea, pItem));

   if( HB_IS_NUMERIC( pItem ) )
   {
      ulRecNo = hb_itemGetNL( pItem );
      if( ulRecNo == 0 )
         ulRecNo = pArea->lpExtendInfo->ulRecNo;
      return SELF_GOTO( pArea, ulRecNo );
   }
   else
   {
      pError = hb_errNew();
      hb_errPutGenCode( pError, EG_DATATYPE );
      hb_errPutDescription( pError, hb_langDGetErrorDesc( EG_DATATYPE ) );
      hb_errPutSubCode( pError, 1020 );
      SELF_ERROR( pArea, pError );
      hb_errRelease( pError );
      return FAILURE;
   }
}

static ERRCODE dbfGoTop( AREAP pArea )
{
   HB_TRACE(HB_TR_DEBUG, ("dbfGoTop(%p)", pArea));

   pArea->fBof = 0;
   SELF_GOTO( pArea, 1 );
   return SELF_SKIPFILTER( pArea, 1 );
}

static ERRCODE dbfInfo( AREAP pArea, USHORT uiIndex, PHB_ITEM pItem )
{
   HB_TRACE(HB_TR_DEBUG, ("dbfInfo(%p, %hu, %p)", pArea, uiIndex, pItem));

   switch( uiIndex )
   {
      case DBI_DBFILTER:
         SELF_FILTERTEXT( pArea, pItem );
         break;

      case DBI_ISDBF:
      case DBI_CANPUTREC:
         hb_itemPutL( pItem, TRUE );
         break;

      case DBI_TABLEEXT:
         hb_itemPutC( pItem, ".dbf" );
         break;

      case DBI_MEMOEXT:
         hb_itemPutC( pItem, ".dbt" );
         break;

      case DBI_GETLOCKARRAY:
         hb_dbfGetLockArray( pArea, pItem );
         break;

      case DBI_LASTUPDATE:
         hb_itemPutDL( pItem, hb_dateEncode( pArea->lpExtendInfo->bYear,
                                             pArea->lpExtendInfo->bMonth,
                                             pArea->lpExtendInfo->bDay ) );
         break;

      case DBI_GETRECSIZE:
         hb_itemPutNL( pItem, pArea->lpExtendInfo->uiRecordLen );
         break;

      case DBI_GETHEADERSIZE:
         hb_itemPutNL( pItem, pArea->lpExtendInfo->uiHeaderLen );
         break;
   }
   return SUCCESS;
}

static ERRCODE dbfLock( AREAP pArea, LPDBLOCKINFO pLockInfo )
{
   HB_TRACE(HB_TR_DEBUG, ("dbfLock(%p, %p)", pArea, pLockInfo));

   if( pLockInfo->itmRecID == 0 )
   {
      hb_dbfUnLockAllRecords( pArea );

      /* Get current record */
      pLockInfo->itmRecID = pArea->lpExtendInfo->ulRecNo;
   }
   if( SELF_RAWLOCK( pArea, pLockInfo->uiMethod, pLockInfo->itmRecID ) == SUCCESS )
      pLockInfo->fResult = TRUE;
   else
      pLockInfo->fResult = FALSE;

   return SUCCESS;
}

static ERRCODE dbfOpen( AREAP pArea, LPDBOPENINFO pOpenInfo )
{
   USHORT uiFlags;
   PHB_ITEM pFileExt;
   char * szFileName;
   PHB_FNAME pFileName;
   PHB_ITEM pError = NULL;
   BOOL bRetry;

   HB_TRACE(HB_TR_DEBUG, ("dbfOpen(%p, %p)", pArea, pOpenInfo));

   if( SUPER_OPEN( pArea, pOpenInfo ) == FAILURE )
      return FAILURE;

   uiFlags = pOpenInfo->fReadonly ? FO_READ : FO_READWRITE;
   uiFlags |= pOpenInfo->fShared ? FO_DENYNONE : FO_EXCLUSIVE;
   do
   {
      pArea->lpDataInfo->hFile = hb_fsOpen( pOpenInfo->abName, uiFlags );
      if( pArea->lpDataInfo->hFile == FS_ERROR )
      {
         if( !pError )
         {
            pError = hb_errNew();
            hb_errPutGenCode( pError, EG_OPEN );
            hb_errPutSubCode( pError, 1001 );
            hb_errPutDescription( pError, hb_langDGetErrorDesc( EG_OPEN ) );
            hb_errPutFileName( pError, ( char * ) pOpenInfo->abName );
            hb_errPutFlags( pError, EF_CANRETRY | EF_CANDEFAULT );
         }
         bRetry = ( SELF_ERROR( pArea, pError ) == E_RETRY );
      }
      else
         bRetry = FALSE;
   } while( bRetry );
   if( pError )
      hb_errRelease( pError );

   if( pArea->lpDataInfo->hFile == FS_ERROR )
   {
      SELF_CLOSE( pArea );
      return FAILURE;
   }

   if( SELF_READDBHEADER( pArea ) == FAILURE )
   {
      SELF_CLOSE( pArea );
      return FAILURE;
   }

   if( pArea->lpExtendInfo->fHasMemo )
   {
      pFileName = hb_fsFNameSplit( ( char * ) pOpenInfo->abName );
      pFileExt = hb_itemPutC( NULL, "" );
      SELF_INFO( pArea, DBI_MEMOEXT, pFileExt );
      szFileName = ( char * ) hb_xgrab( _POSIX_PATH_MAX + 3 );
      szFileName[ 0 ] = '\0';
      if( pFileName->szPath )
         strcat( szFileName, pFileName->szPath );
      strcat( szFileName, pFileName->szName );
      strcat( szFileName, hb_itemGetCPtr( pFileExt ) );
      pOpenInfo->abName = ( BYTE * ) szFileName;
      hb_itemRelease( pFileExt );
      hb_xfree( pFileName );

      pArea->lpDataInfo->pNext = ( LPFILEINFO ) hb_xgrab( sizeof( FILEINFO ) );
      memset( pArea->lpDataInfo->pNext, 0, sizeof( FILEINFO ) );
      pArea->lpDataInfo->pNext->hFile = FS_ERROR;
      pArea->lpDataInfo->pNext->szFileName = szFileName;

      if( SELF_OPENMEMFILE( pArea, pOpenInfo ) == FAILURE )
      {
         SELF_CLOSE( pArea );
         return FAILURE;
      }
   }
   return SELF_GOTOP( pArea );
}

static ERRCODE dbfOpenMemFile( AREAP pArea, LPDBOPENINFO pOpenInfo )
{
   LPFILEINFO lpMemInfo;
   LPMEMOHEADER pMemoHeader;
   USHORT uiFlags;
   PHB_ITEM pError = NULL;
   BOOL bRetry;

   HB_TRACE(HB_TR_DEBUG, ("dbfOpenMemFile(%p, %p)", pArea, pOpenInfo));

   lpMemInfo = pArea->lpDataInfo->pNext;
   uiFlags = pOpenInfo->fReadonly ? FO_READ : FO_READWRITE;
   uiFlags |= pOpenInfo->fShared ? FO_DENYNONE : FO_EXCLUSIVE;
   do
   {
      lpMemInfo->hFile = hb_fsOpen( pOpenInfo->abName, uiFlags );
      if( lpMemInfo->hFile == FS_ERROR )
      {
         if( !pError )
         {
            pError = hb_errNew();
            hb_errPutGenCode( pError, EG_OPEN );
            hb_errPutSubCode( pError, 1002 );
            hb_errPutDescription( pError, hb_langDGetErrorDesc( EG_OPEN ) );
            hb_errPutFileName( pError, ( char * ) pOpenInfo->abName );
            hb_errPutFlags( pError, EF_CANRETRY );
         }
         bRetry = ( SELF_ERROR( pArea, pError ) == E_RETRY );
      }
      else
         bRetry = FALSE;
   } while( bRetry );
   if( pError )
      hb_errRelease( pError );

   if( lpMemInfo->hFile == FS_ERROR )
      return FAILURE;

   pMemoHeader = ( LPMEMOHEADER ) hb_xgrab( MEMO_BLOCK + 1 );
   if( hb_fsRead( lpMemInfo->hFile, ( BYTE * ) pMemoHeader,
                  MEMO_BLOCK + 1 ) != MEMO_BLOCK + 1 )
   {
      hb_xfree( pMemoHeader );
      return FAILURE;
   }
   pArea->lpExtendInfo->ulNextBlock = pMemoHeader->lNextBlock;
   hb_xfree( pMemoHeader );
   return SUCCESS;
}

static ERRCODE dbfPack( AREAP pArea )
{
   ULONG ulRecCount, ulRecIn, ulRecOut, ulEvery;
   BOOL bDeleted;
   PHB_ITEM pError;
   BYTE * pBuffer, pEOF[ 1 ];

   HB_TRACE(HB_TR_DEBUG, ("dbfPack(%p)", pArea));

   if( !pArea->lpExtendInfo->fExclusive )
   {
      pError = hb_errNew();
      hb_errPutGenCode( pError, EG_SHARED );
      hb_errPutDescription( pError, hb_langDGetErrorDesc( EG_SHARED ) );
      hb_errPutSubCode( pError, 1023 );
      SELF_ERROR( pArea, pError );
      hb_errRelease( pError );
      return FAILURE;
   }

   if( SELF_GOCOLD( pArea ) == FAILURE || pArea->lpExtendInfo->fReadOnly ||
       SELF_RECCOUNT( pArea, &ulRecCount ) == FAILURE )
      return FAILURE;
   pArea->lpExtendInfo->ulRecCount = ulRecCount;

   ulRecOut = 0;
   ulRecIn = 1;
   ulEvery = 0;
   while ( ulRecIn <= ulRecCount )
   {
      SELF_GOTO( pArea, ulRecIn );
      SELF_DELETED( pArea, &bDeleted );

      /* Execute the Code Block */
      if( pArea->lpExtendInfo->itmEval )
      {
         ulEvery++;
         if( ulEvery >= pArea->lpExtendInfo->ulEvery )
         {
            ulEvery = 0;
            hb_vmPushSymbol( &hb_symEval );
            hb_vmPush( pArea->lpExtendInfo->itmEval );
            hb_vmDo( 0 );
         }
      }

      if( !bDeleted )
      {
         ulRecOut++;
         if( ulRecIn != ulRecOut )            /* Copy record */
         {
            SELF_GETREC( pArea, &pBuffer );
            hb_fsSeek( pArea->lpDataInfo->hFile, pArea->lpExtendInfo->uiHeaderLen +
                       ( ulRecOut - 1 ) * pArea->lpExtendInfo->uiRecordLen, FS_SET );
            hb_fsWrite( pArea->lpDataInfo->hFile, pBuffer, pArea->lpExtendInfo->uiRecordLen );
         }
      }
      ulRecIn++;
   }

   /* Execute the Code Block for pending record */
   if( pArea->lpExtendInfo->itmEval && ulEvery > 0 )
   {
      hb_vmPushSymbol( &hb_symEval );
      hb_vmPush( pArea->lpExtendInfo->itmEval );
      hb_vmDo( 0 );
   }

   hb_dbfUpdateHeader( pArea, ulRecOut );

   /* Write EOF */
   pEOF[ 0 ] = 0x1A;
   hb_fsSeek( pArea->lpDataInfo->hFile, pArea->lpExtendInfo->uiHeaderLen +
              ulRecOut * pArea->lpExtendInfo->uiRecordLen, FS_SET );
   hb_fsWrite( pArea->lpDataInfo->hFile, pEOF, 1 );

   /* Truncate the file */
   hb_fsWrite( pArea->lpDataInfo->hFile, NULL, 0 );

   return SELF_GOTOP( pArea );
}

static ERRCODE dbfPutRec( AREAP pArea, BYTE * pBuffer )
{
   HB_TRACE(HB_TR_DEBUG, ("dbfPutRec(%p, %p)", pArea, pBuffer));

   if( SELF_GOHOT( pArea ) == FAILURE )
      return FAILURE;

   memcpy( pArea->lpExtendInfo->bRecord, pBuffer, pArea->lpExtendInfo->uiRecordLen );
   pArea->lpExtendInfo->fValidBuffer = TRUE;

   return SUCCESS;
}

static ERRCODE dbfPutValue( AREAP pArea, USHORT uiIndex, PHB_ITEM pItem )
{
   LPFIELD pField;
   USHORT uiCount;
   BYTE * pBuffer, * szText, szEndChar;
   BOOL bError;
   long lDay, lMonth, lYear;
   PHB_ITEM pError;

   HB_TRACE(HB_TR_DEBUG, ("dbfPutValue(%p, %hu, %p)", pArea, uiIndex, pItem));

   if( uiIndex > pArea->uiFieldCount )
      return FAILURE;

   if( SELF_GOHOT( pArea ) == FAILURE )
      return FAILURE;

   SELF_GETREC( pArea, &pBuffer );
   pField = pArea->lpFields + uiIndex - 1;
   szText = pBuffer + pField->uiOffset;
   bError = TRUE;
   switch( pField->uiType )
   {
      case 'C':
         if( HB_IS_STRING( pItem ) )
         {
            uiCount = ( USHORT ) hb_itemGetCLen( pItem );
            if( uiCount > pField->uiLen )
               uiCount = pField->uiLen;
            memcpy( szText, hb_itemGetCPtr( pItem ), uiCount );
            memset( szText + uiCount, ' ', pField->uiLen - uiCount );
            bError = FALSE;
         }
         break;

      case 'N':
         if( HB_IS_NUMERIC( pItem ) )
         {
            if( pField->uiDec )
               bError = !hb_ndtoa( hb_itemGetND( pItem ), ( char * ) szText,
                                   pField->uiLen, pField->uiDec );
            else
               bError = !hb_nltoa( hb_itemGetNL( pItem ), ( char * ) szText,
                                   pField->uiLen );
            if( bError )
            {
               pError = hb_errNew();
               hb_errPutGenCode( pError, EG_DATAWIDTH );
               hb_errPutDescription( pError, hb_langDGetErrorDesc( EG_DATAWIDTH ) );
               hb_errPutSubCode( pError, 1021 );
               SELF_ERROR( pArea, pError );
               hb_errRelease( pError );
            }
            bError = FALSE;
         }
         break;

      case 'D':
         if( HB_IS_DATE( pItem ) )
         {
            szEndChar = * ( szText + pField->uiLen );
            hb_dateDecode( hb_itemGetDL( pItem ), &lYear, &lMonth, &lDay );
            hb_dateStrPut( ( char * ) szText, lYear, lMonth, lDay );
            * ( szText + pField->uiLen ) = szEndChar;
            bError = FALSE;
         }
         break;

      case 'L':
         if( HB_IS_LOGICAL( pItem ) )
         {
            *szText = hb_itemGetL( pItem ) ? 'T' : 'F';
            bError = FALSE;
         }
         break;

      case 'M':
         if( HB_IS_STRING( pItem ) )
         {
            uiCount = ( USHORT ) hb_itemGetCLen( pItem );
            if( ( ( LPDBFMEMO ) pField->memo )->uiLen < uiCount )
            {
               if( ( ( LPDBFMEMO ) pField->memo )->pData )
                  ( ( LPDBFMEMO ) pField->memo )->pData =
                                  ( BYTE * ) hb_xrealloc( ( ( LPDBFMEMO ) pField->memo )->pData,
                                                          uiCount + 1 );
               else
                  ( ( LPDBFMEMO ) pField->memo )->pData =
                                  ( BYTE * ) hb_xgrab( uiCount + 1 );
            }
            ( ( LPDBFMEMO ) pField->memo )->uiLen = uiCount;
            if( uiCount > 0 )
            {
               memcpy( ( ( LPDBFMEMO ) pField->memo )->pData, hb_itemGetCPtr( pItem ), uiCount );
               ( ( LPDBFMEMO ) pField->memo )->pData[ uiCount ] = 0;
            }
            else
            {
               if( ( ( LPDBFMEMO ) pField->memo )->pData )
               {
                  hb_xfree( ( ( LPDBFMEMO ) pField->memo )->pData );
                  memset( pField->memo, 0, sizeof( DBFMEMO ) );
               }
            }
            ( ( LPDBFMEMO ) pField->memo )->fChanged = TRUE;
            bError = FALSE;
         }
         break;
   }

   if( bError )
   {
      pError = hb_errNew();
      hb_errPutGenCode( pError, EG_DATATYPE );
      hb_errPutDescription( pError, hb_langDGetErrorDesc( EG_DATATYPE ) );
      hb_errPutSubCode( pError, 1020 );
      SELF_ERROR( pArea, pError );
      hb_errRelease( pError );
      pArea->lpExtendInfo->fRecordChanged = FALSE;
      return FAILURE;
   }
   pArea->lpExtendInfo->fRecordChanged = TRUE;
   return SUCCESS;
}

static ERRCODE dbfPutValueFile( AREAP pArea, USHORT uiIndex, void * pFile )
{
   LPFIELD pField;
   BYTE * pBuffer, * szText, szEndChar;
   ULONG lMemoBlock;

   HB_TRACE(HB_TR_DEBUG, ("dbfPutValueFile(%p, %hu, %p)", pArea, uiIndex, pFile));

   HB_SYMBOL_UNUSED( pFile );

   if( uiIndex > pArea->uiFieldCount )
      return FAILURE;

   SELF_GETREC( pArea, &pBuffer );
   pField = pArea->lpFields + uiIndex - 1;;
   szText = pBuffer + pField->uiOffset;
   szEndChar = * ( szText + pField->uiLen );
   * ( szText + pField->uiLen ) = 0;
   lMemoBlock = atol( ( char * ) szText ) * MEMO_BLOCK;
   * ( szText + pField->uiLen ) = szEndChar;
   if( lMemoBlock > 0 )
      hb_dbfReadMemo( pArea, ( LPDBFMEMO ) pField->memo, lMemoBlock );
   else if( ( ( LPDBFMEMO ) pField->memo )->pData )
   {
      hb_xfree( ( ( LPDBFMEMO ) pField->memo )->pData );
      memset( pField->memo, 0, sizeof( DBFMEMO ) );
   }
   return SUCCESS;
}

static ERRCODE dbfRawLock( AREAP pArea, USHORT uiAction, ULONG lRecNo )
{
   HB_TRACE(HB_TR_DEBUG, ("dbfRawLock(%p, %hu, %lu)", pArea, uiAction, lRecNo));

   if( SELF_GOCOLD( pArea ) == FAILURE )
      return FAILURE;

   switch( uiAction )
   {
      case REC_LOCK:
         if( !hb_dbfLockRecord( pArea, lRecNo ) )
            return FAILURE;
         break;

      case REC_UNLOCK:
         if( !hb_dbfUnLockRecord( pArea, lRecNo ) )
            return FAILURE;
         break;

      case FILE_LOCK:
         if( !hb_dbfLockFile( pArea ) )
            return FAILURE;
         break;

      case FILE_UNLOCK:
         if( !hb_dbfUnLockFile( pArea ) )
            return FAILURE;
         break;
   }
   return SUCCESS;
}

static ERRCODE dbfReadDBHeader( AREAP pArea )
{
   DBFHEADER pHeader;
   DBFIELDINFO pFieldInfo;
   LPDBFFIELD pDBField;
   USHORT uiDataLen;
   char * szBuffer;
   USHORT uiFields, uiCount;

   HB_TRACE(HB_TR_DEBUG, ("dbfReadHeader(%p)", pArea));

   hb_fsSeek( pArea->lpDataInfo->hFile, 0, FS_SET );
   if( hb_fsRead( pArea->lpDataInfo->hFile, ( BYTE * ) &pHeader,
                  sizeof( DBFHEADER ) ) != sizeof( DBFHEADER ) )
      return FAILURE;

   pArea->lpExtendInfo->uiHeaderLen = pHeader.uiHeaderLen;
   pArea->lpExtendInfo->bYear = pHeader.bYear;
   pArea->lpExtendInfo->bMonth = pHeader.bMonth;
   pArea->lpExtendInfo->bDay = pHeader.bDay;
   uiDataLen = pHeader.uiHeaderLen - sizeof( DBFHEADER );
   szBuffer = ( char * ) hb_xgrab( uiDataLen );
   if( hb_fsRead( pArea->lpDataInfo->hFile, ( BYTE * ) szBuffer,
                  uiDataLen ) != uiDataLen )
   {
      hb_xfree( szBuffer );
      return FAILURE;
   }

   for( uiFields = 0; uiFields < uiDataLen; uiFields += 32 )
      if( szBuffer[ uiFields ] == 0xD )
         break;

   uiFields /= 32;
   if( ( uiDataLen / 32 ) < uiFields )
   {
      hb_xfree( szBuffer );
      return FAILURE;
   }

   pArea->lpExtendInfo->uiRecordLen = 1;
   SELF_SETFIELDEXTENT( pArea, uiFields );
   pFieldInfo.typeExtended = 0;
   pFieldInfo.uiLen = 0;
   pDBField = ( LPDBFFIELD ) szBuffer;
   for( uiCount = 0; uiCount < uiFields; uiCount++ )
   {
      pFieldInfo.atomName = ( BYTE * ) pDBField->bName;
      pFieldInfo.uiType = toupper( pDBField->bType );

      if( pFieldInfo.uiType == 'N' )
      {
         pFieldInfo.uiLen = ( USHORT ) pDBField->bLen;
         pFieldInfo.uiDec = ( USHORT ) pDBField->bDec;
      }
      else
      {
         if( pFieldInfo.uiType == 'L' || pFieldInfo.uiType == 'D' ||
             pFieldInfo.uiType == 'M' )
         {
            pFieldInfo.uiLen = ( USHORT ) pDBField->bLen;
            if( pFieldInfo.uiType == 'M' )
               pArea->lpExtendInfo->fHasMemo = TRUE;
         }
         else if( pFieldInfo.uiType == 'C' )
         {
            pFieldInfo.uiLen = ( USHORT ) pDBField->bLen +
                               ( ( USHORT ) pDBField->bDec << 8 );
         }
         pFieldInfo.uiDec = 0;
      }
      pArea->lpExtendInfo->uiRecordLen += pFieldInfo.uiLen;
      SELF_ADDFIELD( pArea, &pFieldInfo );
      pDBField++;
   }
   hb_xfree( szBuffer );
   pArea->lpExtendInfo->bRecord = ( BYTE * ) hb_xgrab( pArea->lpExtendInfo->uiRecordLen + 1 );
   hb_dbfClearBuffer( pArea );
   pArea->lpExtendInfo->bRecord[ pArea->lpExtendInfo->uiRecordLen ] = 0;
   return SUCCESS;
}

static ERRCODE dbfRecAll( AREAP pArea )
{
   BYTE * pBuffer;

   HB_TRACE(HB_TR_DEBUG, ("dbfRecAll(%p)", pArea));

   if( SELF_GOHOT( pArea ) == FAILURE )
      return FAILURE;

   SELF_GETREC( pArea, &pBuffer );
   if( pBuffer[ 0 ] !=  '*' )
   {
      pArea->lpExtendInfo->fRecordChanged = FALSE;
      return SUCCESS;
   }
   pBuffer[ 0 ] =  ' ';

   return SUCCESS;
}

static ERRCODE dbfRecCount( AREAP pArea, ULONG * pRecCount )
{
   DBFHEADER pHeader;

   HB_TRACE(HB_TR_DEBUG, ("dbfRecCount(%p, %p)", pArea, pRecCount));

   hb_fsSeek( pArea->lpDataInfo->hFile, 0, FS_SET );
   if( hb_fsRead( pArea->lpDataInfo->hFile, ( BYTE * ) &pHeader,
                  sizeof( DBFHEADER ) ) != sizeof( DBFHEADER ) )
      return FAILURE;
   * pRecCount = pHeader.ulRecords;
   return SUCCESS;
}

static ERRCODE dbfRecInfo( AREAP pArea, PHB_ITEM pRecNo, USHORT uiType, PHB_ITEM pItem )
{
   BYTE * pBuffer;
   ULONG ulRecNo;

   HB_TRACE(HB_TR_DEBUG, ("dbfRecInfo(%p, %p, %hu, %p)", pArea, pRecNo, uiType, pItem));

   ulRecNo = pArea->lpExtendInfo->ulRecNo;
   if( SELF_GOTOID( pArea, pRecNo ) == SUCCESS )
   {
      switch( uiType )
      {
         case DBRI_DELETED:
            SELF_GETREC( pArea, &pBuffer );
            hb_itemPutL( pItem, ( pBuffer[ 0 ] ==  '*' ) );
            break;

         case DBRI_LOCKED:
            hb_itemPutL( pItem, hb_dbfIsLocked( pArea, pArea->lpExtendInfo->ulRecNo ) );
            break;

         case DBRI_RECNO:
            SELF_RECNO( pArea, pItem );
            break;

         case DBRI_RECSIZE:
            hb_itemPutNL( pItem, pArea->lpExtendInfo->uiRecordLen );
            break;

         case DBRI_UPDATED:
            hb_itemPutL( pItem, pArea->lpExtendInfo->fRecordChanged );
            break;
      }
   }
   SELF_GOTO( pArea, ulRecNo );

   return SUCCESS;
}

static ERRCODE dbfRecNo( AREAP pArea, PHB_ITEM pRecNo )
{
   HB_TRACE(HB_TR_DEBUG, ("dbfRecNo(%p, %p)", pArea, pRecNo));

   hb_itemPutNL( pRecNo, pArea->lpExtendInfo->ulRecNo );
   return SUCCESS;
}

static ERRCODE dbfRelease( AREAP pArea )
{
   USHORT  uiCount;
   LPFIELD pField;

   HB_TRACE(HB_TR_DEBUG, ("dbfRelease(%p)", pArea));

   if( pArea->lpExtendInfo->fHasMemo )
   {
      for( uiCount = 0; uiCount < pArea->uiFieldCount; uiCount++ )
      {
         pField = pArea->lpFields + uiCount;
         if( pField->memo )
         {
            if( ( ( LPDBFMEMO ) pField->memo )->pData )
               hb_xfree( ( ( LPDBFMEMO ) pField->memo )->pData );
            hb_xfree( pField->memo );
         }
      }
   }
   return SUPER_RELEASE( pArea );
}

static ERRCODE dbfUnLock( AREAP pArea, ULONG lRecNo )
{
   HB_TRACE(HB_TR_DEBUG, ("dbfUnLock(%p, %lu)", pArea, lRecNo));

   if( lRecNo == 0 )
      hb_dbfUnLockAllRecords( pArea );
   else
      SELF_RAWLOCK( pArea, REC_UNLOCK, lRecNo );
   return SUCCESS;
}

static ERRCODE dbfWriteDBHeader( AREAP pArea )
{
   DBFHEADER pHeader;
   DBFFIELD pDBField;
   USHORT uiCount;
   LPFIELD pField;
   time_t t;
   struct tm * pTime;

   HB_TRACE(HB_TR_DEBUG, ("dbfWriteDBHeader(%p)", pArea));

   memset( &pHeader, 0, sizeof( DBFHEADER ) );
   pHeader.uiRecordLen = 1;
   pHeader.bVersion = 0x03;
   pField = pArea->lpFields;
   for( uiCount = 0; uiCount < pArea->uiFieldCount; uiCount++ )
   {
      switch( pField->uiType )
      {
         case 'C':
         case 'N':
            pHeader.uiRecordLen += pField->uiLen;
            break;

         case 'M':
            pHeader.uiRecordLen += 10;
            pHeader.bVersion = 0x83;
            pArea->lpExtendInfo->fHasMemo = TRUE;
            break;

         case 'D':
            pHeader.uiRecordLen += 8;
            break;

         case 'L':
            pHeader.uiRecordLen += 1;
            break;
      }
      pField++;
   }

   time( &t );
   pTime =  localtime( &t );
   pHeader.bYear = ( BYTE ) pTime->tm_year;
   pHeader.bMonth = ( BYTE ) pTime->tm_mon + 1;
   pHeader.bDay = ( BYTE ) pTime->tm_mday;
   pHeader.uiHeaderLen = ( USHORT ) ( 32 * ( pArea->uiFieldCount + 1 ) + 1 );
   pHeader.bHasTag = 0;
   pHeader.ulRecords = 0;
   if( hb_fsWrite( pArea->lpDataInfo->hFile, ( BYTE * ) &pHeader,
                   sizeof( DBFHEADER ) ) != sizeof( DBFHEADER ) )
      return FAILURE;

   pField = pArea->lpFields;
   for( uiCount = 0; uiCount < pArea->uiFieldCount; uiCount++ )
   {
      memset( &pDBField, 0, sizeof( DBFFIELD ) );
      strncpy( ( char * ) pDBField.bName, ( ( PHB_DYNS ) pField->sym )->pSymbol->szName,
               sizeof( pDBField.bName ) );
      pDBField.bType = ( BYTE ) pField->uiType;
      switch( pDBField.bType )
      {
         case 'C':
            pDBField.bLen = pField->uiLen & 0xFF;
            pDBField.bDec = pField->uiLen >> 8;
            break;

         case 'M':
            pDBField.bLen = 10;
            pDBField.bDec = 0;
            break;

         case 'D':
            pDBField.bLen = 8;
            pDBField.bDec = 0;
            break;

         case 'L':
            pDBField.bLen = 1;
            pDBField.bDec = 0;
            break;

         case 'N':
            pDBField.bLen = ( BYTE ) pField->uiLen;
            pDBField.bDec = ( BYTE ) pField->uiDec;
            break;
      }
      if( hb_fsWrite( pArea->lpDataInfo->hFile, ( BYTE * ) &pDBField,
                      sizeof( DBFFIELD ) ) != sizeof( DBFFIELD ) )
         return FAILURE;
      pField++;
   }
   if( hb_fsWrite( pArea->lpDataInfo->hFile, ( BYTE * ) "\15\32", 2 ) != 2 )
      return FAILURE;
   return SUCCESS;
}

static ERRCODE dbfZap( AREAP pArea )
{
   PHB_ITEM pError;
   DBOPENINFO pInfo;
   ULONG ulRecCount;

   HB_TRACE(HB_TR_DEBUG, ("dbfZap(%p)", pArea));

   if( !pArea->lpExtendInfo->fExclusive )
   {
      pError = hb_errNew();
      hb_errPutGenCode( pError, EG_SHARED );
      hb_errPutDescription( pError, hb_langDGetErrorDesc( EG_SHARED ) );
      hb_errPutSubCode( pError, 1023 );
      SELF_ERROR( pArea, pError );
      hb_errRelease( pError );
      return FAILURE;
   }

   if( SELF_GOCOLD( pArea ) == FAILURE || pArea->lpExtendInfo->fReadOnly )
      return FAILURE;

   /* Test if can write into file */
   SELF_RECCOUNT( pArea, &ulRecCount );
   pArea->lpExtendInfo->ulRecCount = ulRecCount;
   if( !hb_dbfUpdateHeader( pArea, ulRecCount ) )
      return FAILURE;

   hb_dbfUnLockAllRecords( pArea );
   hb_fsClose( pArea->lpDataInfo->hFile );
   pInfo.abName = ( BYTE * ) pArea->lpDataInfo->szFileName;
   SELF_CREATE( pArea, &pInfo );
   hb_fsClose( pArea->lpDataInfo->hFile );
   pArea->lpDataInfo->hFile = hb_fsOpen( pInfo.abName, FO_READWRITE | FO_EXCLUSIVE );
   if( pArea->lpExtendInfo->fHasMemo )
   {
      hb_fsClose( pArea->lpDataInfo->pNext->hFile );
      pInfo.abName = ( BYTE * ) pArea->lpDataInfo->pNext->szFileName;
      SELF_CREATEMEMFILE( pArea, &pInfo );
      hb_fsClose( pArea->lpDataInfo->pNext->hFile );
      pArea->lpDataInfo->pNext->hFile = hb_fsOpen( pInfo.abName, FO_READWRITE | FO_EXCLUSIVE );
   }
   return SELF_GOTOP( pArea );
}

static RDDFUNCS dbfTable = { dbfBof,
                             dbfEof,
                             dbfFound,
                             dbfGoBottom,
                             dbfGoTo,
                             dbfGoToId,
                             dbfGoTop,
                             dbfSeek,
                             dbfSkip,
                             dbfSkipFilter,
                             dbfSkipRaw,
                             dbfAddField,
                             dbfAppend,
                             dbfCreateFields,
                             dbfDeleteRec,
                             dbfDeleted,
                             dbfFieldCount,
                             dbfFieldDisplay,
                             dbfFieldInfo,
                             dbfFieldName,
                             dbfFlush,
                             dbfGetRec,
                             dbfGetValue,
                             dbfGetVarLen,
                             dbfGoCold,
                             dbfGoHot,
                             dbfPutRec,
                             dbfPutValue,
                             dbfRecAll,
                             dbfRecCount,
                             dbfRecInfo,
                             dbfRecNo,
                             dbfSetFieldsExtent,
                             dbfAlias,
                             dbfClose,
                             dbfCreate,
                             dbfInfo,
                             dbfNewArea,
                             dbfOpen,
                             dbfRelease,
                             dbfStructSize,
                             dbfSysName,
                             dbfEval,
                             dbfPack,
                             dbfZap,
                             dbfOrderListAdd,
                             dbfOrderListClear,
                             dbfOrderListFocus,
                             dbfOrderListRebuild,
                             dbfOrderCondition,
                             dbfOrderCreate,
                             dbfOrderDestroy,
                             dbfOrderInfo,
                             dbfClearFilter,
                             dbfClearLocate,
                             dbfClearScope,
                             dbfCountScope,
                             dbfFilterText,
                             dbfScopeInfo,
                             dbfSetFilter,
                             dbfSetLocate,
                             dbfSetScope,
                             dbfSkipScope,
                             dbfCompile,
                             dbfError,
                             dbfEvalBlock,
                             dbfRawLock,
                             dbfLock,
                             dbfUnLock,
                             dbfCloseMemFile,
                             dbfCreateMemFile,
                             dbfGetValueFile,
                             dbfOpenMemFile,
                             dbfPutValueFile,
                             dbfReadDBHeader,
                             dbfWriteDBHeader,
                             dbfWhoCares
                           };

HB_FUNC( _DBFC )
{
}

HB_FUNC( DBF_GETFUNCTABLE )
{
   RDDFUNCS * pTable;
   USHORT * uiCount;

   uiCount = ( USHORT * ) hb_itemGetPtr( hb_param( 1, HB_IT_POINTER ) );
   * uiCount = RDDFUNCSCOUNT;
   pTable = ( RDDFUNCS * ) hb_itemGetPtr( hb_param( 2, HB_IT_POINTER ) );
   
   HB_TRACE(HB_TR_DEBUG, ("DBF_GETFUNCTABLE(%i, %p)", uiCount, pTable));

   if( pTable )
      hb_retni( hb_rddInherit( pTable, &dbfTable, &dbfSuper, 0 ) );
   else
      hb_retni( FAILURE );
}

