diff --git a/harbour/ChangeLog b/harbour/ChangeLog index 36d23997ea..029005eade 100644 --- a/harbour/ChangeLog +++ b/harbour/ChangeLog @@ -1,3 +1,10 @@ +19990831-02:37 GMT+1 Bruno Cantero + * include/rddapi.h + source/rdd/dbcmd.c + source/rdd/dbf1.c + tests/working/testdbf.prg + * Full support for memo fields. + 19990830-19:00 GMT+1 Victor Szel * source/filesys.c diff --git a/harbour/include/rddapi.h b/harbour/include/rddapi.h index 656d4b7dad..c4cf5815a8 100644 --- a/harbour/include/rddapi.h +++ b/harbour/include/rddapi.h @@ -195,6 +195,7 @@ typedef struct BYTE * bRecord; /* Buffer of the data */ BOOL fHasMemo; /* Work Area with Memo fields */ ULONG lRecNo; /* Current record */ + ULONG lNextBlock; /* Next block for memos */ BOOL fExclusive; /* Share the file */ BOOL fReadOnly; /* Read only file */ BYTE bYear; /* Last update */ @@ -484,6 +485,7 @@ typedef struct _FIELD USHORT uiDec; /* Decimal length */ USHORT uiArea; /* Area this field resides in */ void * sym; /* Symbol that represents the field */ + void * memo; /* Pointer to memo data */ struct _FIELD *lpfNext; /* The next field in the list */ } FIELD; @@ -712,7 +714,9 @@ typedef struct _RDDFUNCS DBENTRYP_VP createMemFile; #if 0 DBENTRYP_SVPB getValueFile; +#endif DBENTRYP_VP openMemFile; +#if 0 DBENTRYP_SVP putValueFile; #endif diff --git a/harbour/source/rdd/dbcmd.c b/harbour/source/rdd/dbcmd.c index 9f17b69905..71cde1b480 100644 --- a/harbour/source/rdd/dbcmd.c +++ b/harbour/source/rdd/dbcmd.c @@ -437,7 +437,7 @@ static RDDFUNCS defTable = { Bof, ( DBENTRYP_VL ) UnSupported, ( DBENTRYP_UL ) UnSupported, ( DBENTRYP_VP ) UnSupported, - /*( DBENTRYP_VP ) UnSupported,*/ + ( DBENTRYP_VP ) UnSupported, UnSupported, UnSupported }; @@ -1245,176 +1245,176 @@ HARBOUR HB_DBUNLOCKALL( void ) HARBOUR HB_DBUSEAREA( void ) { -// char * szDriver, * szFileName, * szAlias; -// WORD wLen; -// LPRDDNODE pRddNode; -// LPAREANODE pAreaNode; -// USHORT uiSize, uiRddID; -// DBOPENINFO pInfo; -// PHB_FNAME pFileName; -// PHB_ITEM pFileExt; -// -// bNetError = FALSE; -// -// if( hb_parl( 1 ) ) -// hb_rddSelectFirstAvailable(); -// else if( pCurrArea ) /* If current WorkArea is in use then close it */ -// { -// SELF_CLOSE( ( AREAP ) pCurrArea->pArea ); -// SELF_RELEASE( ( AREAP ) pCurrArea->pArea ); -// -// if( pWorkAreas == pCurrArea ) /* Empty list */ -// pWorkAreas = 0; -// else -// { -// if( pCurrArea->pPrev ) -// pCurrArea->pPrev->pNext = pCurrArea->pNext; -// if( pCurrArea->pNext ) -// pCurrArea->pNext->pPrev = pCurrArea->pPrev; -// } -// -// hb_xfree( pCurrArea->pArea ); -// hb_xfree( pCurrArea ); -// pCurrArea = 0; -// } -// -// hb_rddCheck(); -// szDriver = hb_parc( 2 ); -// if( ( wLen = strlen( szDriver ) ) > 0 ) -// hb_strUpper( szDriver, wLen ); -// else -// szDriver = szDefDriver; -// -// uiRddID = 0; -// pRddNode = hb_rddFindNode( szDriver, &uiRddID ); -// if( !pRddNode ) -// { -// hb_errRT_DBCMD( EG_ARG, 1015, 0, "DBUSEAREA" ); -// return; -// } -// -// szFileName = hb_parc( 3 ); -// if( strlen( szFileName ) == 0 ) -// { -// hb_errRT_DBCMD( EG_ARG, 1005, 0, "DBUSEAREA" ); -// return; -// } -// -// pFileName = hb_fsFNameSplit( szFileName ); -// szAlias = hb_parc( 4 ); -// if( strlen( szAlias ) == 0 ) -// szAlias = pFileName->szName; -// -// /* Create a new WorkArea node */ -// -// pCurrArea = ( LPAREANODE ) hb_xgrab( sizeof( AREANODE ) ); -// -// if( pRddNode->uiAreaSize == 0 ) /* Calculate the size of WorkArea */ -// { -// uiSize = sizeof( AREA ); /* Default Size Area */ -// pCurrArea->pArea = ( AREAP ) hb_xgrab( uiSize ); -// memset( pCurrArea->pArea, 0, uiSize ); -// ( ( AREAP ) pCurrArea->pArea )->lprfsHost = &pRddNode->pTable; -// -// /* Need more space? */ -// SELF_STRUCTSIZE( ( AREAP ) pCurrArea->pArea, &uiSize ); -// if( uiSize > sizeof( AREA ) ) /* Size of Area changed */ -// pCurrArea->pArea = ( AREAP ) hb_xrealloc( pCurrArea->pArea, uiSize ); -// -// pRddNode->uiAreaSize = uiSize; /* Update the size of WorkArea */ -// } -// else -// { -// pCurrArea->pArea = ( AREAP ) hb_xgrab( pRddNode->uiAreaSize ); -// memset( pCurrArea->pArea, 0, pRddNode->uiAreaSize ); -// ( ( AREAP ) pCurrArea->pArea )->lprfsHost = &pRddNode->pTable; -// } -// -// ( ( AREAP ) pCurrArea->pArea )->rddID = uiRddID; -// -// pCurrArea->pPrev = 0; -// pCurrArea->pNext = 0; -// -// SELF_NEW( ( AREAP ) pCurrArea->pArea ); -// -// szFileName = ( char * ) hb_xgrab( _POSIX_PATH_MAX + 3 ); -// strcpy( szFileName, hb_parc( 3 ) ); -// if( !pFileName->szExtension ) -// { -// pFileExt = hb_itemPutC( 0, "" ); -// SELF_INFO( ( AREAP ) pCurrArea->pArea, DBI_TABLEEXT, pFileExt ); -// strcat( szFileName, pFileExt->item.asString.value ); -// hb_itemRelease( pFileExt ); -// } -// pInfo.uiArea = uiCurrArea; -// pInfo.abName = ( BYTE * ) szFileName; -// pInfo.atomAlias = ( BYTE * ) szAlias; -// pInfo.fShared = ISLOG( 5 ) ? hb_parl( 5 ) : !hb_set.HB_SET_EXCLUSIVE; -// pInfo.fReadonly = ISLOG( 6 ) ? hb_parl( 6 ) : FALSE; -// -// if( SELF_OPEN( ( AREAP ) pCurrArea->pArea, &pInfo ) == FAILURE ) -// { -// SELF_RELEASE( ( AREAP ) pCurrArea->pArea ); -// hb_xfree( pCurrArea->pArea ); -// hb_xfree( pCurrArea ); -// hb_xfree( szFileName ); -// hb_xfree( pFileName ); -// pCurrArea = 0; -// return; -// } -// -// if( ( ( AREAP ) pCurrArea->pArea )->lpExtendInfo->fHasMemo ) -// { -// pFileExt = hb_itemPutC( 0, "" ); -// SELF_INFO( ( AREAP ) pCurrArea->pArea, DBI_MEMOEXT, pFileExt ); -// szFileName[ 0 ] = 0; -// if( pFileName->szPath ) -// strcat( szFileName, pFileName->szPath ); -// strcat( szFileName, pFileName->szName ); -// strcat( szFileName, pFileExt->item.asString.value ); -// pInfo.abName = ( BYTE * ) szFileName; -// hb_itemRelease( pFileExt ); -// if( SELF_OPENMEMFILE( ( AREAP ) pCurrArea->pArea, &pInfo ) == FAILURE ) -// { -// SELF_CLOSE( ( AREAP ) pCurrArea->pArea ); -// SELF_RELEASE( ( AREAP ) pCurrArea->pArea ); -// hb_xfree( pCurrArea->pArea ); -// hb_xfree( pCurrArea ); -// hb_xfree( szFileName ); -// hb_xfree( pFileName ); -// pCurrArea = 0; -// return; -// } -// } -// -// hb_xfree( szFileName ); -// hb_xfree( pFileName ); -// ( ( AREAP ) pCurrArea->pArea )->uiArea = uiCurrArea; -// -// /* Insert the new WorkArea node */ -// -// if( !pWorkAreas ) -// { -// pWorkAreas = pCurrArea; /* The new WorkArea node is the first */ -// return; -// } -// -// pAreaNode = pWorkAreas; -// while( pAreaNode->pNext ) -// { -// if( ( ( AREAP ) pAreaNode->pArea )->uiArea > uiCurrArea ) -// { -// /* Insert the new WorkArea node */ -// pCurrArea->pPrev = pAreaNode->pPrev; -// pCurrArea->pNext = pAreaNode; -// pAreaNode->pPrev = pCurrArea; -// if( pCurrArea->pPrev ) -// pCurrArea->pPrev->pNext = pCurrArea; -// } -// pAreaNode = pAreaNode->pNext; -// } -// pAreaNode->pNext = pCurrArea; /* Append the new WorkArea node */ -// pCurrArea->pPrev = pAreaNode; + char * szDriver, * szFileName, * szAlias; + WORD wLen; + LPRDDNODE pRddNode; + LPAREANODE pAreaNode; + USHORT uiSize, uiRddID; + DBOPENINFO pInfo; + PHB_FNAME pFileName; + PHB_ITEM pFileExt; + + bNetError = FALSE; + + if( hb_parl( 1 ) ) + hb_rddSelectFirstAvailable(); + else if( pCurrArea ) /* If current WorkArea is in use then close it */ + { + SELF_CLOSE( ( AREAP ) pCurrArea->pArea ); + SELF_RELEASE( ( AREAP ) pCurrArea->pArea ); + + if( pWorkAreas == pCurrArea ) /* Empty list */ + pWorkAreas = 0; + else + { + if( pCurrArea->pPrev ) + pCurrArea->pPrev->pNext = pCurrArea->pNext; + if( pCurrArea->pNext ) + pCurrArea->pNext->pPrev = pCurrArea->pPrev; + } + + hb_xfree( pCurrArea->pArea ); + hb_xfree( pCurrArea ); + pCurrArea = 0; + } + + hb_rddCheck(); + szDriver = hb_parc( 2 ); + if( ( wLen = strlen( szDriver ) ) > 0 ) + hb_strUpper( szDriver, wLen ); + else + szDriver = szDefDriver; + + uiRddID = 0; + pRddNode = hb_rddFindNode( szDriver, &uiRddID ); + if( !pRddNode ) + { + hb_errRT_DBCMD( EG_ARG, 1015, 0, "DBUSEAREA" ); + return; + } + + szFileName = hb_parc( 3 ); + if( strlen( szFileName ) == 0 ) + { + hb_errRT_DBCMD( EG_ARG, 1005, 0, "DBUSEAREA" ); + return; + } + + pFileName = hb_fsFNameSplit( szFileName ); + szAlias = hb_parc( 4 ); + if( strlen( szAlias ) == 0 ) + szAlias = pFileName->szName; + + /* Create a new WorkArea node */ + + pCurrArea = ( LPAREANODE ) hb_xgrab( sizeof( AREANODE ) ); + + if( pRddNode->uiAreaSize == 0 ) /* Calculate the size of WorkArea */ + { + uiSize = sizeof( AREA ); /* Default Size Area */ + pCurrArea->pArea = ( AREAP ) hb_xgrab( uiSize ); + memset( pCurrArea->pArea, 0, uiSize ); + ( ( AREAP ) pCurrArea->pArea )->lprfsHost = &pRddNode->pTable; + + /* Need more space? */ + SELF_STRUCTSIZE( ( AREAP ) pCurrArea->pArea, &uiSize ); + if( uiSize > sizeof( AREA ) ) /* Size of Area changed */ + pCurrArea->pArea = ( AREAP ) hb_xrealloc( pCurrArea->pArea, uiSize ); + + pRddNode->uiAreaSize = uiSize; /* Update the size of WorkArea */ + } + else + { + pCurrArea->pArea = ( AREAP ) hb_xgrab( pRddNode->uiAreaSize ); + memset( pCurrArea->pArea, 0, pRddNode->uiAreaSize ); + ( ( AREAP ) pCurrArea->pArea )->lprfsHost = &pRddNode->pTable; + } + + ( ( AREAP ) pCurrArea->pArea )->rddID = uiRddID; + + pCurrArea->pPrev = 0; + pCurrArea->pNext = 0; + + SELF_NEW( ( AREAP ) pCurrArea->pArea ); + + szFileName = ( char * ) hb_xgrab( _POSIX_PATH_MAX + 3 ); + strcpy( szFileName, hb_parc( 3 ) ); + if( !pFileName->szExtension ) + { + pFileExt = hb_itemPutC( 0, "" ); + SELF_INFO( ( AREAP ) pCurrArea->pArea, DBI_TABLEEXT, pFileExt ); + strcat( szFileName, pFileExt->item.asString.value ); + hb_itemRelease( pFileExt ); + } + pInfo.uiArea = uiCurrArea; + pInfo.abName = ( BYTE * ) szFileName; + pInfo.atomAlias = ( BYTE * ) szAlias; + pInfo.fShared = ISLOG( 5 ) ? hb_parl( 5 ) : !hb_set.HB_SET_EXCLUSIVE; + pInfo.fReadonly = ISLOG( 6 ) ? hb_parl( 6 ) : FALSE; + + if( SELF_OPEN( ( AREAP ) pCurrArea->pArea, &pInfo ) == FAILURE ) + { + SELF_RELEASE( ( AREAP ) pCurrArea->pArea ); + hb_xfree( pCurrArea->pArea ); + hb_xfree( pCurrArea ); + hb_xfree( szFileName ); + hb_xfree( pFileName ); + pCurrArea = 0; + return; + } + + if( ( ( AREAP ) pCurrArea->pArea )->lpExtendInfo->fHasMemo ) + { + pFileExt = hb_itemPutC( 0, "" ); + SELF_INFO( ( AREAP ) pCurrArea->pArea, DBI_MEMOEXT, pFileExt ); + szFileName[ 0 ] = 0; + if( pFileName->szPath ) + strcat( szFileName, pFileName->szPath ); + strcat( szFileName, pFileName->szName ); + strcat( szFileName, pFileExt->item.asString.value ); + pInfo.abName = ( BYTE * ) szFileName; + hb_itemRelease( pFileExt ); + if( SELF_OPENMEMFILE( ( AREAP ) pCurrArea->pArea, &pInfo ) == FAILURE ) + { + SELF_CLOSE( ( AREAP ) pCurrArea->pArea ); + SELF_RELEASE( ( AREAP ) pCurrArea->pArea ); + hb_xfree( pCurrArea->pArea ); + hb_xfree( pCurrArea ); + hb_xfree( szFileName ); + hb_xfree( pFileName ); + pCurrArea = 0; + return; + } + } + + hb_xfree( szFileName ); + hb_xfree( pFileName ); + ( ( AREAP ) pCurrArea->pArea )->uiArea = uiCurrArea; + + /* Insert the new WorkArea node */ + + if( !pWorkAreas ) + { + pWorkAreas = pCurrArea; /* The new WorkArea node is the first */ + return; + } + + pAreaNode = pWorkAreas; + while( pAreaNode->pNext ) + { + if( ( ( AREAP ) pAreaNode->pArea )->uiArea > uiCurrArea ) + { + /* Insert the new WorkArea node */ + pCurrArea->pPrev = pAreaNode->pPrev; + pCurrArea->pNext = pAreaNode; + pAreaNode->pPrev = pCurrArea; + if( pCurrArea->pPrev ) + pCurrArea->pPrev->pNext = pCurrArea; + } + pAreaNode = pAreaNode->pNext; + } + pAreaNode->pNext = pCurrArea; /* Append the new WorkArea node */ + pCurrArea->pPrev = pAreaNode; } HARBOUR HB_DELETED( void ) diff --git a/harbour/source/rdd/dbf1.c b/harbour/source/rdd/dbf1.c index 77ac7cab91..2b3783cd8b 100644 --- a/harbour/source/rdd/dbf1.c +++ b/harbour/source/rdd/dbf1.c @@ -51,9 +51,10 @@ typedef struct typedef DBFHEADER * LPDBFHEADER; + typedef struct { - LONG lNextBlock; + ULONG lNextBlock; } MEMOHEADER; typedef MEMOHEADER * LPMEMOHEADER; @@ -73,6 +74,16 @@ typedef struct typedef DBFFIELD * LPDBFFIELD; +typedef struct _DBFMEMO +{ + BOOL fChanged; /* Memo status */ + BYTE * pData; /* Memo data */ + USHORT uiLen; /* Len of data */ +} DBFMEMO; + +typedef DBFMEMO * LPDBFMEMO; + + HARBOUR HB__DBF( void ); HARBOUR HB_DBF_GETFUNCTABLE( void ); @@ -88,6 +99,7 @@ HB_INIT_SYMBOLS_END( dbf1__InitSymbols ) #define LOCK_FILE 0x3FFFFFFFL #define MEMO_BLOCK 512 + static BOOL hb_nltoa( LONG lValue, char * szBuffer, USHORT uiLen ) { LONG lAbsNumber; @@ -190,9 +202,63 @@ static BOOL hb_dbfUpdateHeader( AREAP pArea, ULONG lRecCount ) return TRUE; } +static BOOL hb_dbfWriteMemo( AREAP pArea, LPDBFMEMO pMemo, ULONG * lNewRecNo ) +{ + USHORT uiNumBlocks, uiBytesRead, uiRead, uiCount; + BYTE szBuffer[ MEMO_BLOCK ]; + MEMOHEADER pMemoHeader; + + uiNumBlocks = ( pMemo->uiLen + MEMO_BLOCK - 1 ) / MEMO_BLOCK; + if( * lNewRecNo > 0 ) + { + uiBytesRead = 0; + hb_fsSeek( pArea->lpFileInfo->pNext->hFile, * lNewRecNo * MEMO_BLOCK, FS_SET ); + do + { + uiBytesRead += MEMO_BLOCK; + uiRead = hb_fsRead( pArea->lpFileInfo->pNext->hFile, szBuffer, MEMO_BLOCK ); + if( !uiRead ) + 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->lpFileInfo->pNext->hFile, 0, FS_SET ); + if( hb_fsRead( pArea->lpFileInfo->pNext->hFile, ( BYTE * ) &pMemoHeader, + sizeof( MEMOHEADER ) ) != sizeof( MEMOHEADER ) ) + return FALSE; + + * lNewRecNo = pMemoHeader.lNextBlock; + pMemoHeader.lNextBlock = * lNewRecNo + uiNumBlocks; + hb_fsSeek( pArea->lpFileInfo->pNext->hFile, 0, FS_SET ); + hb_fsWrite( pArea->lpFileInfo->pNext->hFile, ( BYTE * ) &pMemoHeader, + sizeof( MEMOHEADER ) ); + } + + hb_fsSeek( pArea->lpFileInfo->pNext->hFile, * lNewRecNo * MEMO_BLOCK, FS_SET ); + if( hb_fsWrite( pArea->lpFileInfo->pNext->hFile, pMemo->pData, + pMemo->uiLen ) != pMemo->uiLen ) + return FALSE; + + szBuffer[ 0 ] = 0x1A; + if( hb_fsWrite( pArea->lpFileInfo->pNext->hFile, szBuffer, 1 ) != 1 ) + return FALSE; + + return TRUE; +} + static BOOL hb_dbfUpdateRecord( AREAP pArea, ULONG lRecNo ) { - ULONG lRecCount; + ULONG lRecCount, lNewRecNo; + USHORT uiCount, uiOffset; + LPFIELD pField; + BYTE * szText, szEndChar; if( SELF_RECCOUNT( pArea, &lRecCount ) == FAILURE ) return FALSE; @@ -203,6 +269,39 @@ static BOOL hb_dbfUpdateRecord( AREAP pArea, ULONG lRecNo ) ( lRecNo - 1 ) * pArea->lpExtendInfo->uiRecordLen, FS_SET ); if( pArea->lpFileInfo->fAppend ) lRecCount = lRecNo; + if( pArea->lpExtendInfo->fHasMemo ) + { + uiOffset = 1; + for( uiCount = 0; uiCount < pArea->uiFieldCount; uiCount++ ) + { + pField = pArea->lpFields + uiCount; + if( pField->uiType == 'C' ) + uiOffset += pField->uiLen + ( ( USHORT ) pField->uiDec << 8 ); + else + { + if( pField->uiType == 'M' && ( ( LPDBFMEMO ) pField->memo )->fChanged ) + { + szText = pArea->lpExtendInfo->bRecord + 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 FALSE; + if( lNewRecNo != lRecNo ) + hb_nltoa( lNewRecNo, ( char * ) szText, pField->uiLen ); + * ( szText + pField->uiLen ) = szEndChar; + } + ( ( LPDBFMEMO ) pField->memo )->fChanged = FALSE; + } + uiOffset += pField->uiLen; + } + } + } if( hb_fsWrite( pArea->lpFileInfo->hFile, pArea->lpExtendInfo->bRecord, pArea->lpExtendInfo->uiRecordLen ) != pArea->lpExtendInfo->uiRecordLen || !hb_dbfUpdateHeader( pArea, lRecCount ) ) @@ -212,8 +311,86 @@ static BOOL hb_dbfUpdateRecord( AREAP pArea, ULONG lRecNo ) return TRUE; } +static void hb_dbfClearBuffer( AREAP pArea ) +{ + LPFIELD pField; + USHORT uiCount; + + memset( pArea->lpExtendInfo->bRecord, ' ', pArea->lpExtendInfo->uiRecordLen ); + + 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_fsSeek( pArea->lpFileInfo->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->lpFileInfo->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 ERRCODE hb_dbfReadBuffer( AREAP pArea, ULONG lRecNo ) { + LPFIELD pField; + USHORT uiCount, uiOffset; + BYTE * szText, szEndChar; + ULONG lMemoBlock; + if( pArea->lpExtendInfo->fRecordChanged && !hb_dbfUpdateRecord( pArea, pArea->lpExtendInfo->lRecNo ) ) return FAILURE; @@ -224,10 +401,43 @@ static ERRCODE hb_dbfReadBuffer( AREAP pArea, ULONG lRecNo ) hb_fsRead( pArea->lpFileInfo->hFile, pArea->lpExtendInfo->bRecord, pArea->lpExtendInfo->uiRecordLen ) != pArea->lpExtendInfo->uiRecordLen ) { + hb_dbfClearBuffer( pArea ); memset( pArea->lpExtendInfo->bRecord, ' ', pArea->lpExtendInfo->uiRecordLen ); pArea->lpExtendInfo->bRecord[ pArea->lpExtendInfo->uiRecordLen ] = 0; return FAILURE; } + + if( pArea->lpExtendInfo->fHasMemo && pArea->lpFileInfo->pNext ) + { + pField = pArea->lpFields; + uiOffset = 1; + for( uiCount = 0; uiCount < pArea->uiFieldCount; uiCount++ ) + { + if( pField->uiType == 'C' ) + uiOffset += pField->uiLen + ( ( USHORT ) pField->uiDec << 8 ); + else + { + if( pField->uiType == 'M' ) + { + szText = pArea->lpExtendInfo->bRecord + 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 ) ); + } + } + uiOffset += pField->uiLen; + } + pField = pField->lpfNext; + } + } + return SUCCESS; } @@ -399,6 +609,24 @@ static RDDFUNCS dbfSuper = { 0 }; * -- DBF METHODS -- */ +static ERRCODE AddField( AREAP pArea, LPDBFIELDINFO pFieldInfo ) +{ + LPFIELD pField; + + if( SUPER_ADDFIELD( pArea, pFieldInfo ) == SUCCESS ) + { + 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 Append( AREAP pArea, BOOL bUnLockAll ) { ULONG lRecCount, lRecNo; @@ -421,7 +649,7 @@ static ERRCODE Append( AREAP pArea, BOOL bUnLockAll ) lRecCount++; lRecNo = lRecCount; pArea->fEof = FALSE; - memset( pArea->lpExtendInfo->bRecord, ' ', pArea->lpExtendInfo->uiRecordLen ); + hb_dbfClearBuffer( pArea ); pArea->lpExtendInfo->fRecordChanged = TRUE; pArea->lpFileInfo->fAppend = TRUE; if( !hb_dbfUpdateRecord( pArea, lRecNo ) ) @@ -598,6 +826,14 @@ static ERRCODE GetValue( AREAP pArea, USHORT uiIndex, PHB_ITEM pItem ) else hb_itemPutL( pItem, 0 ); break; + + case 'M': + if( ( ( LPDBFMEMO ) pField->memo )->pData ) + hb_itemPutCL( pItem, ( char * ) ( ( LPDBFMEMO ) pField->memo )->pData, + ( ( LPDBFMEMO ) pField->memo )->uiLen ); + else + hb_itemPutC( pItem, "" ); + break; } return SUCCESS; @@ -759,6 +995,37 @@ static ERRCODE Open( AREAP pArea, LPDBOPENINFO pOpenInfo ) return SELF_GOTOP( pArea ); } +static ERRCODE OpenMemFile( AREAP pArea, LPDBOPENINFO pOpenInfo ) +{ + LPFILEINFO lpMemInfo; + LPMEMOHEADER pMemoHeader; + USHORT uiFlags; + + lpMemInfo = ( LPFILEINFO ) hb_xgrab( sizeof( FILEINFO ) ); + memset( lpMemInfo, 0, sizeof( FILEINFO ) ); + lpMemInfo->hFile = FS_ERROR; + pArea->lpFileInfo->pNext = lpMemInfo; + + uiFlags = pOpenInfo->fReadonly ? FO_READ : FO_READWRITE; + uiFlags |= pOpenInfo->fShared ? FO_DENYNONE : FO_EXCLUSIVE; + lpMemInfo->hFile = hb_fsOpen( pOpenInfo->abName, uiFlags ); + + 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->lNextBlock = pMemoHeader->lNextBlock; + hb_xfree( pMemoHeader ); + + return SELF_GOTOP( pArea ); +} + static ERRCODE PutValue( AREAP pArea, USHORT uiIndex, PHB_ITEM pItem ) { LPFIELD pField; @@ -856,6 +1123,35 @@ static ERRCODE PutValue( AREAP pArea, USHORT uiIndex, PHB_ITEM pItem ) bError = FALSE; } break; + + case 'M': + if( pItem->type & IT_STRING ) + { + uiCount = pItem->item.asString.length; + if( ( ( LPDBFMEMO ) pField->memo )->uiLen < uiCount ) + { + if( ( ( LPDBFMEMO ) pField->memo )->pData ) + hb_xfree( ( ( LPDBFMEMO ) pField->memo )->pData ); + ( ( LPDBFMEMO ) pField->memo )->pData = ( BYTE * ) hb_xgrab( uiCount + 1 ); + } + ( ( LPDBFMEMO ) pField->memo )->uiLen = uiCount; + if( uiCount > 0 ) + { + memcpy( ( ( LPDBFMEMO ) pField->memo )->pData, pItem->item.asString.value, 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 ) @@ -975,7 +1271,7 @@ static ERRCODE ReadDBHeader( AREAP pArea ) } hb_xfree( szBuffer ); pArea->lpExtendInfo->bRecord = ( BYTE * ) hb_xgrab( pArea->lpExtendInfo->uiRecordLen + 1 ); - memset( pArea->lpExtendInfo->bRecord, ' ', pArea->lpExtendInfo->uiRecordLen ); + hb_dbfClearBuffer( pArea ); pArea->lpExtendInfo->bRecord[ pArea->lpExtendInfo->uiRecordLen ] = 0; return SUCCESS; } @@ -1025,6 +1321,27 @@ static ERRCODE RecNo( AREAP pArea, PHB_ITEM pRecNo ) return SUCCESS; } +static ERRCODE Release( AREAP pArea ) +{ + USHORT uiCount; + LPFIELD pField; + + 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 SkipRaw( AREAP pArea, LONG lToSkip ) { return SELF_GOTO( pArea, pArea->lpExtendInfo->lRecNo + lToSkip ); @@ -1144,7 +1461,7 @@ static RDDFUNCS dbfTable = { 0, /* Super Bof */ 0, /* Super Skip */ 0, /* Super SkipFilter */ SkipRaw, - 0, /* Super AddField */ + AddField, Append, 0, /* Super CreateFields */ DeleteRec, @@ -1167,7 +1484,7 @@ static RDDFUNCS dbfTable = { 0, /* Super Bof */ Info, 0, /* Super NewArea */ Open, - 0, /* Super Release */ + Release, 0, /* Super StructSize */ 0, /* Super SysName */ 0, /* Super Error */ @@ -1175,7 +1492,7 @@ static RDDFUNCS dbfTable = { 0, /* Super Bof */ Lock, UnLock, CreateMemFile, - /*0, */ /* Super OpenMemFile */ + OpenMemFile, ReadDBHeader, WriteDBHeader }; diff --git a/harbour/tests/working/testdbf.prg b/harbour/tests/working/testdbf.prg index 16498373d0..acbc42ffbb 100644 --- a/harbour/tests/working/testdbf.prg +++ b/harbour/tests/working/testdbf.prg @@ -8,14 +8,23 @@ function main() { "NUMERIC", "N", 8, 0 }, ; { "DOUBLE", "N", 8, 2 }, ; { "DATE", "D", 8, 0 }, ; - { "LOGICAL", "L", 1, 0 } } + { "LOGICAL", "L", 1, 0 }, ; + { "MEMO1", "M", 10, 0 }, ; + { "MEMO2", "M", 10, 0 } } - local aRdd := rddList() - - QOut( "Registered RDD's:", LTrim( Str( Len( aRdd ) ) ), "=>" ) - aEval( aRdd, { | cDriver | QQOut( "", cDriver ) } ) - QOut() - QOut( "Creating a DBF file" ) - dbCreate( "testdbf.dbf", aStruct ) + dbCreate( "testdbf", aStruct ) + dbUseArea(,, "testdbf" ) + ? "[" + FIELD->MEMO1 + "]" + ? "[" + FIELD->MEMO2 + "]" + ? "-" + FIELD->MEMO1 := "Hello world!" + FIELD->MEMO2 := "Harbour power" + ? "[" + FIELD->MEMO1 + "]" + ? "[" + FIELD->MEMO2 + "]" + dbAppend() + FIELD->MEMO1 := "111" + FIELD->MEMO2 := "222" + ? "[" + FIELD->MEMO1 + "]" + ? "[" + FIELD->MEMO2 + "]" return nil