diff --git a/harbour/ChangeLog b/harbour/ChangeLog index 9e9dfa34e9..4fdfe63223 100644 --- a/harbour/ChangeLog +++ b/harbour/ChangeLog @@ -8,6 +8,32 @@ 2009-12-31 13:59 UTC+0100 Foo Bar (foo.bar foobar.org) */ +2009-04-28 19:45 UTC+0200 Przemyslaw Czerpak (druzus/at/priv.onet.pl) + * harbour/ChangeLog + * removed TOVERIFY note - Viktor checked it. + + * harbour/contrib/hbct/ctwin.c + ! redraw windows after each WCENTER() call + + * harbour/contrib/rddads/ads1.c + + added support for ADS_VARCHAR_FOX and ADS_VARBINARY_FOX fields + in ADS_VFP tables + + * harbour/include/dbinfo.ch + * harbour/include/hbrdddbf.h + * harbour/include/hbrddcdx.h + * harbour/include/hbrddnsx.h + * harbour/include/hbrddntx.h + * harbour/source/rdd/dbf1.c + * harbour/source/rdd/workarea.c + + added support for VFP tables with VARCHAR and VARBINARY fields + + added support for VFP tables with NULLABLE fields + + added new dbFieldInfo() action to check if given field is NULL, f.e.: + ? dbFieldInfo( DBS_ISNULL, FieldPos( ) ) + The above modifications were not tested with real VFP files. I do + not have VFP. VFP users should make some real life tests with tables + created by VFP. + 2009-04-27 19:17 UTC+0200 Przemyslaw Czerpak (druzus/at/priv.onet.pl) * harbour/contrib/rddads/ads1.c ! fixed very bad bug in code compiled for ADS_LIB_VERSION < 600 @@ -21,11 +47,6 @@ timestamp values read from index keys are rounded to whole seconds or setting scopes to data values on timestamp indexes does not work like in native RDDs or in ADT tables. - TOVERIFY: please check in which ACE version Ads[SG]etMilliseconds() - functions were added and if necessary add - #if ADS_LIB_VERSION >= ??? - protection. I do not have older ACE headers and I cannot - make it myself. To ADS users: please make some real life tests and report problems if any. diff --git a/harbour/contrib/hbct/ctwin.c b/harbour/contrib/hbct/ctwin.c index 69e1c2e26d..e804ada808 100644 --- a/harbour/contrib/hbct/ctwin.c +++ b/harbour/contrib/hbct/ctwin.c @@ -801,6 +801,8 @@ static int hb_ctw_CenterWindow( PHB_GTCTW pCTW, int iWindow, BOOL fCenter ) if( pWnd ) { + int iRow = pWnd->iFirstRow, iCol = pWnd->iFirstCol; + if( fCenter ) { int iHeight = pCTW->iBoardBottom - pCTW->iBoardTop + 1, @@ -825,6 +827,11 @@ static int hb_ctw_CenterWindow( PHB_GTCTW pCTW, int iWindow, BOOL fCenter ) if( pWnd->iFirstCol < pCTW->iBoardLeft ) pWnd->iFirstCol = pCTW->iBoardLeft; } + + if( !pWnd->fHidden && + ( iRow != pWnd->iFirstRow || iCol != pWnd->iFirstCol ) ) + hb_ctw_RemapAllWindows( pCTW, 0 ); + return iWindow; } } diff --git a/harbour/contrib/rddads/ads1.c b/harbour/contrib/rddads/ads1.c index 0f1e4f9f36..53f5cb4bc8 100644 --- a/harbour/contrib/rddads/ads1.c +++ b/harbour/contrib/rddads/ads1.c @@ -1575,10 +1575,32 @@ static HB_ERRCODE adsCreateFields( ADSAREAP pArea, PHB_ITEM pStruct ) break; case 'V': - dbFieldInfo.uiType = HB_FT_MEMO; - dbFieldInfo.uiTypeExtended = ADS_VARCHAR; +#if ADS_LIB_VERSION >= 900 + if( pArea->iFileType == ADS_VFP ) + { + dbFieldInfo.uiType = HB_FT_VARLENGTH; + dbFieldInfo.uiTypeExtended = ADS_VARCHAR_FOX; + } + else +#endif + { + dbFieldInfo.uiType = HB_FT_MEMO; + dbFieldInfo.uiTypeExtended = ADS_VARCHAR; + } break; +#if ADS_LIB_VERSION >= 900 + case 'Q': + if( pArea->iFileType == ADS_VFP ) + { + dbFieldInfo.uiType = HB_FT_VARLENGTH; + dbFieldInfo.uiTypeExtended = ADS_VARBINARY_FOX; + break; + } + else + return HB_FAILURE; +#endif + case 'R': if( pArea->iFileType == ADS_ADT && iNameLen >= 4 && !hb_strnicmp( szFieldType, "rowversion", iNameLen ) ) @@ -1675,21 +1697,6 @@ static HB_ERRCODE adsCreateFields( ADSAREAP pArea, PHB_ITEM pStruct ) dbFieldInfo.uiLen = 4; } } -/* -#if ADS_LIB_VERSION >= 900 - else if( pArea->iFileType == ADS_VFP && - ( iNameLen >= 4 && - hb_strnicmp( szFieldType, "timestamp", iNameLen ) == 0 ) ) - { - if( iNameLen > 4 ) - { - dbFieldInfo.uiType = HB_FT_DAYTIME; - dbFieldInfo.uiTypeExtended = ADS_TIMESTAMP; - dbFieldInfo.uiLen = 8; - } - } -#endif -*/ else return HB_FAILURE; break; @@ -1838,6 +1845,15 @@ static HB_ERRCODE adsFieldInfo( AREAP pArea, USHORT uiIndex, USHORT uiType, PHB_ hb_itemPutC( pItem, "RAW" ); break; + case HB_FT_VARLENGTH: +#if ADS_LIB_VERSION >= 900 + if( pField->uiTypeExtended == ADS_VARCHAR_FOX ) + hb_itemPutC( pItem, "V" ); +#endif + else + hb_itemPutC( pItem, "Q" ); + break; + case HB_FT_BLOB: hb_itemPutC( pItem, "BINARY" ); break; @@ -1993,26 +2009,38 @@ static HB_ERRCODE adsGetValue( ADSAREAP pArea, USHORT uiIndex, PHB_ITEM pItem ) switch( pField->uiType ) { case HB_FT_STRING: + case HB_FT_VARLENGTH: u32Length = pArea->maxFieldLen; if( !pArea->fPositioned ) { - memset( pBuffer, ' ', pField->uiLen ); + u32Length = pField->uiType == HB_FT_STRING ? pField->uiLen : 0; + memset( pBuffer, ' ', u32Length ); } #ifdef ADS_USE_OEM_TRANSLATION +#if ADS_LIB_VERSION >= 900 + else if( hb_ads_bOEM && pField->uiTypeExtended != ADS_VARBINARY_FOX ) +#else else if( hb_ads_bOEM ) +#endif { #if ADS_LIB_VERSION >= 600 - AdsGetFieldRaw( pArea->hTable, ADSFIELD( uiIndex ), pBuffer, &u32Length ); + AdsGetFieldRaw( pArea->hTable, ADSFIELD( uiIndex ), pBuffer, &u32Length ) == AE_NO_CURRENT_RECORD ) + { + u32Length = pField->uiType == HB_FT_STRING ? pField->uiLen : 0; + memset( pBuffer, ' ', u32Length ); + hb_adsUpdateAreaFlags( pArea ); + } #else if( AdsGetField( pArea->hTable, ADSFIELD( uiIndex ), pBuffer, &u32Length, ADS_NONE ) == AE_NO_CURRENT_RECORD ) { - memset( pBuffer, ' ', pField->uiLen ); + u32Length = pField->uiType == HB_FT_STRING ? pField->uiLen : 0; + memset( pBuffer, ' ', u32Length ); hb_adsUpdateAreaFlags( pArea ); } else { - char * pBufOem = hb_adsAnsiToOem( ( char * ) pBuffer, pField->uiLen ); - memcpy( pBuffer, pBufOem, pField->uiLen ); + char * pBufOem = hb_adsAnsiToOem( ( char * ) pBuffer, u32Length ); + memcpy( pBuffer, pBufOem, u32Length ); hb_adsOemAnsiFree( pBufOem ); } #endif @@ -2020,12 +2048,13 @@ static HB_ERRCODE adsGetValue( ADSAREAP pArea, USHORT uiIndex, PHB_ITEM pItem ) #endif else if( AdsGetField( pArea->hTable, ADSFIELD( uiIndex ), pBuffer, &u32Length, ADS_NONE ) == AE_NO_CURRENT_RECORD ) { - memset( pBuffer, ' ', pField->uiLen ); + u32Length = pField->uiType == HB_FT_STRING ? pField->uiLen : 0; + memset( pBuffer, ' ', u32Length ); /* It should not happen - sth desynchronize WA with ADS, update area flags, Druzus */ hb_adsUpdateAreaFlags( pArea ); } - hb_itemPutCL( pItem, ( char * ) pBuffer, pField->uiLen ); + hb_itemPutCL( pItem, ( char * ) pBuffer, u32Length ); break; case HB_FT_TIME: @@ -2352,6 +2381,7 @@ static HB_ERRCODE adsPutValue( ADSAREAP pArea, USHORT uiIndex, PHB_ITEM pItem ) switch( pField->uiType ) { case HB_FT_STRING: + case HB_FT_VARLENGTH: if( HB_IS_STRING( pItem ) ) { bTypeError = FALSE; @@ -2688,6 +2718,14 @@ static HB_ERRCODE adsCreate( ADSAREAP pArea, LPDBOPENINFO pCreateInfo ) else cType = "C"; break; + case HB_FT_VARLENGTH: +#if ADS_LIB_VERSION >= 900 + if( pField->uiTypeExtended == ADS_VARBINARY_FOX ) + cType = "VarB"; + else +#endif + cType = "VarC"; + break; case HB_FT_MEMO: cType = pField->uiTypeExtended == ADS_VARCHAR ? "VarC" : "M"; break; @@ -3011,7 +3049,7 @@ static HB_ERRCODE adsOpen( ADSAREAP pArea, LPDBOPENINFO pOpenInfo ) USHORT uiFields = 0, uiCount; UNSIGNED8 szName[ ADS_MAX_FIELD_NAME + 1 ]; /* See adsGettValue() for why we don't use pArea->uiMaxFieldNameLength here */ - UNSIGNED16 pusBufLen, pusType, pusDecimals; + UNSIGNED16 usBufLen, usType, usDecimals; DBFIELDINFO dbFieldInfo; char szAlias[ HB_RDD_MAX_ALIAS_LEN + 1 ], * szFile; BOOL fDictionary = FALSE; @@ -3019,15 +3057,15 @@ static HB_ERRCODE adsOpen( ADSAREAP pArea, LPDBOPENINFO pOpenInfo ) HB_TRACE(HB_TR_DEBUG, ("adsOpen(%p)", pArea)); hConnection = HB_ADS_DEFCONNECTION( pOpenInfo->ulConnection ); - u32RetVal = AdsGetHandleType( hConnection, &pusType); + u32RetVal = AdsGetHandleType( hConnection, &usType); if( u32RetVal == AE_SUCCESS ) { #if ADS_LIB_VERSION >= 600 /* ADS_*_CONNECTION was added in >= 6.00 */ #if ADS_LIB_VERSION < 900 /* ADS_SYS_ADMIN_CONNECTION was removed in >= 9.00 */ - fDictionary = ( pusType == ADS_DATABASE_CONNECTION - || pusType == ADS_SYS_ADMIN_CONNECTION ); + fDictionary = ( usType == ADS_DATABASE_CONNECTION + || usType == ADS_SYS_ADMIN_CONNECTION ); #else - fDictionary = ( pusType == ADS_DATABASE_CONNECTION ); + fDictionary = ( usType == ADS_DATABASE_CONNECTION ); #endif #endif } @@ -3140,12 +3178,12 @@ static HB_ERRCODE adsOpen( ADSAREAP pArea, LPDBOPENINFO pOpenInfo ) for( uiCount = 1; uiCount <= uiFields; uiCount++ ) { - pusBufLen = ADS_MAX_FIELD_NAME; - AdsGetFieldName( pArea->hTable, uiCount, szName, &pusBufLen ); + usBufLen = ADS_MAX_FIELD_NAME; + AdsGetFieldName( pArea->hTable, uiCount, szName, &usBufLen ); dbFieldInfo.atomName = szName; - * ( dbFieldInfo.atomName + pusBufLen ) = '\0'; - AdsGetFieldType( pArea->hTable, szName, &pusType ); + * ( dbFieldInfo.atomName + usBufLen ) = '\0'; + AdsGetFieldType( pArea->hTable, szName, &usType ); AdsGetFieldLength( pArea->hTable, szName, &u32Length ); dbFieldInfo.uiLen = ( USHORT ) u32Length; dbFieldInfo.uiDec = 0; @@ -3154,9 +3192,8 @@ static HB_ERRCODE adsOpen( ADSAREAP pArea, LPDBOPENINFO pOpenInfo ) { pArea->maxFieldLen = u32Length; } - - dbFieldInfo.uiTypeExtended = pusType; - switch( pusType ) + dbFieldInfo.uiTypeExtended = usType; + switch( usType ) { case ADS_STRING: dbFieldInfo.uiTypeExtended = 0; @@ -3177,27 +3214,27 @@ static HB_ERRCODE adsOpen( ADSAREAP pArea, LPDBOPENINFO pOpenInfo ) case ADS_NUMERIC: dbFieldInfo.uiTypeExtended = 0; dbFieldInfo.uiType = HB_FT_LONG; - AdsGetFieldDecimals( pArea->hTable, szName, &pusDecimals ); - dbFieldInfo.uiDec = ( USHORT ) pusDecimals; + AdsGetFieldDecimals( pArea->hTable, szName, &usDecimals ); + dbFieldInfo.uiDec = ( USHORT ) usDecimals; break; case ADS_DOUBLE: /* uiLen of extended types is set in following switch */ dbFieldInfo.uiType = HB_FT_DOUBLE; - AdsGetFieldDecimals( pArea->hTable, szName, &pusDecimals ); - dbFieldInfo.uiDec = ( USHORT ) pusDecimals; + AdsGetFieldDecimals( pArea->hTable, szName, &usDecimals ); + dbFieldInfo.uiDec = ( USHORT ) usDecimals; break; case ADS_CURDOUBLE: dbFieldInfo.uiType = HB_FT_CURDOUBLE; - AdsGetFieldDecimals( pArea->hTable, szName, &pusDecimals ); - dbFieldInfo.uiDec = ( USHORT ) pusDecimals; + AdsGetFieldDecimals( pArea->hTable, szName, &usDecimals ); + dbFieldInfo.uiDec = ( USHORT ) usDecimals; break; #ifdef ADS_MONEY /* Not defined below 7.00 */ case ADS_MONEY: dbFieldInfo.uiType = HB_FT_CURRENCY; - AdsGetFieldDecimals( pArea->hTable, szName, &pusDecimals ); - dbFieldInfo.uiDec = ( USHORT ) pusDecimals; + AdsGetFieldDecimals( pArea->hTable, szName, &usDecimals ); + dbFieldInfo.uiDec = ( USHORT ) usDecimals; break; #endif @@ -3237,6 +3274,13 @@ static HB_ERRCODE adsOpen( ADSAREAP pArea, LPDBOPENINFO pOpenInfo ) dbFieldInfo.uiType = HB_FT_DATE; break; +#if ADS_LIB_VERSION >= 900 + case ADS_VARCHAR_FOX: + case ADS_VARBINARY_FOX: + dbFieldInfo.uiType = HB_FT_VARLENGTH; + break; +#endif + case ADS_MEMO: dbFieldInfo.uiTypeExtended = 0; case ADS_VARCHAR: diff --git a/harbour/include/dbinfo.ch b/harbour/include/dbinfo.ch index e88aff934e..7f72e3fedf 100644 --- a/harbour/include/dbinfo.ch +++ b/harbour/include/dbinfo.ch @@ -323,6 +323,7 @@ #define DBI_USER 1000 /* User-defined DBI_ constants */ /* extended dbFieldInfo() actions */ +#define DBS_ISNULL 101 #define DBS_BLOB_GET 201 /* This is internal definition */ #define DBS_BLOB_LEN 202 #define DBS_BLOB_OFFSET 203 diff --git a/harbour/include/hbrddcdx.h b/harbour/include/hbrddcdx.h index 40a9a552a8..9f7d62327a 100644 --- a/harbour/include/hbrddcdx.h +++ b/harbour/include/hbrddcdx.h @@ -494,12 +494,15 @@ typedef struct _CDXAREA USHORT uiNewBlockSize; /* Size of new memo block */ USHORT uiMemoVersion; /* MEMO file version */ USHORT uiDirtyRead; /* Index dirty read bit filed */ + USHORT uiNullOffset; /* Offset to _NullFlags filed */ + USHORT uiNullCount; /* Number of null flags */ BYTE bTableType; /* DBF type */ BYTE bMemoType; /* MEMO type used in DBF memo fields */ BYTE bLockType; /* Type of locking shemes */ BYTE bCryptType; /* Type of used encryption */ DBFHEADER dbfHeader; /* DBF header buffer */ USHORT * pFieldOffset; /* Pointer to field offset array */ + PHB_DBFFIELDBITS pFieldBits; /* Pointer to extended DBF field info array */ BYTE * pRecord; /* Buffer of record data */ ULONG ulRecCount; /* Total records */ ULONG ulRecNo; /* Current record */ diff --git a/harbour/include/hbrdddbf.h b/harbour/include/hbrdddbf.h index 72767e2ab7..416eeb1098 100644 --- a/harbour/include/hbrdddbf.h +++ b/harbour/include/hbrdddbf.h @@ -148,10 +148,13 @@ typedef struct _DBFDATA BOOL fStruct; BOOL fStrictStruct; BOOL fMultiTag; -} DBFDATA; - -typedef DBFDATA * LPDBFDATA; +} DBFDATA, * LPDBFDATA; +typedef struct _HB_DBFFIELDBITS +{ + USHORT uiNullBit; + USHORT uiLengthBit; +} HB_DBFFIELDBITS, * PHB_DBFFIELDBITS; /* @@ -206,12 +209,15 @@ typedef struct _DBFAREA USHORT uiNewBlockSize; /* Size of new memo block */ USHORT uiMemoVersion; /* MEMO file version */ USHORT uiDirtyRead; /* Index dirty read bit filed */ + USHORT uiNullOffset; /* Offset to _NullFlags filed */ + USHORT uiNullCount; /* Number of null flags */ BYTE bTableType; /* DBF type */ BYTE bMemoType; /* MEMO type used in DBF memo fields */ BYTE bLockType; /* Type of locking shemes */ BYTE bCryptType; /* Type of used encryption */ DBFHEADER dbfHeader; /* DBF header buffer */ USHORT * pFieldOffset; /* Pointer to field offset array */ + PHB_DBFFIELDBITS pFieldBits; /* Pointer to extended DBF field info array */ BYTE * pRecord; /* Buffer of record data */ ULONG ulRecCount; /* Total records */ ULONG ulRecNo; /* Current record */ @@ -276,7 +282,7 @@ static HB_ERRCODE hb_dbfDeleteRec( DBFAREAP pArea ); static HB_ERRCODE hb_dbfDeleted( DBFAREAP pArea, BOOL * pDeleted ); #define hb_dbfFieldCount NULL #define hb_dbfFieldDisplay NULL -#define hb_dbfFieldInfo NULL +static HB_ERRCODE hb_dbfFieldInfo( DBFAREAP pArea, USHORT uiIndex, USHORT uiType, PHB_ITEM pItem ); #define hb_dbfFieldName NULL static HB_ERRCODE hb_dbfFlush( DBFAREAP pArea ); static HB_ERRCODE hb_dbfGetRec( DBFAREAP pArea, BYTE ** pBuffer ); diff --git a/harbour/include/hbrddnsx.h b/harbour/include/hbrddnsx.h index 7a58671e4e..49af18833a 100644 --- a/harbour/include/hbrddnsx.h +++ b/harbour/include/hbrddnsx.h @@ -583,12 +583,15 @@ typedef struct _NSXAREA USHORT uiNewBlockSize; /* Size of new memo block */ USHORT uiMemoVersion; /* MEMO file version */ USHORT uiDirtyRead; /* Index dirty read bit filed */ + USHORT uiNullOffset; /* Offset to _NullFlags filed */ + USHORT uiNullCount; /* Number of null flags */ BYTE bTableType; /* DBF type */ BYTE bMemoType; /* MEMO type used in DBF memo fields */ BYTE bLockType; /* Type of locking shemes */ BYTE bCryptType; /* Type of used encryption */ DBFHEADER dbfHeader; /* DBF header buffer */ USHORT * pFieldOffset; /* Pointer to field offset array */ + PHB_DBFFIELDBITS pFieldBits; /* Pointer to extended DBF field info array */ BYTE * pRecord; /* Buffer of record data */ ULONG ulRecCount; /* Total records */ ULONG ulRecNo; /* Current record */ diff --git a/harbour/include/hbrddntx.h b/harbour/include/hbrddntx.h index bdfba0c032..7ef3cdb32f 100644 --- a/harbour/include/hbrddntx.h +++ b/harbour/include/hbrddntx.h @@ -380,12 +380,15 @@ typedef struct _NTXAREA USHORT uiNewBlockSize; /* Size of new memo block */ USHORT uiMemoVersion; /* MEMO file version */ USHORT uiDirtyRead; /* Index dirty read bit filed */ + USHORT uiNullOffset; /* Offset to _NullFlags filed */ + USHORT uiNullCount; /* Number of null flags */ BYTE bTableType; /* DBF type */ BYTE bMemoType; /* MEMO type used in DBF memo fields */ BYTE bLockType; /* Type of locking shemes */ BYTE bCryptType; /* Type of used encryption */ DBFHEADER dbfHeader; /* DBF header buffer */ USHORT * pFieldOffset; /* Pointer to field offset array */ + PHB_DBFFIELDBITS pFieldBits; /* Pointer to extended DBF field info array */ BYTE * pRecord; /* Buffer of record data */ ULONG ulRecCount; /* Total records */ ULONG ulRecNo; /* Current record */ diff --git a/harbour/source/rdd/dbf1.c b/harbour/source/rdd/dbf1.c index d3ff651ac1..afdbc50a2d 100644 --- a/harbour/source/rdd/dbf1.c +++ b/harbour/source/rdd/dbf1.c @@ -272,7 +272,7 @@ static void hb_dbfUpdateStampFields( DBFAREAP pArea ) static void hb_dbfSetBlankRecord( DBFAREAP pArea, int iType ) { - BYTE *pPtr = pArea->pRecord, bFill = ' ', bNext; + BYTE * pPtr = pArea->pRecord, bFill = ' ', bNext; ULONG ulSize = 1; /* 1 byte ' ' for DELETE flag */ USHORT uiCount; LPFIELD pField; @@ -406,9 +406,47 @@ static void hb_dbfSetBlankRecord( DBFAREAP pArea, int iType ) } memset( pPtr, bFill, ulSize ); - ulSize = pArea->pRecord - pPtr - ulSize; + ulSize += pPtr - pArea->pRecord; if( ulSize < ( ULONG ) pArea->uiRecordLen ) - memset( pPtr, '\0', ( ULONG ) pArea->uiRecordLen - ulSize ); + memset( pArea->pRecord + ulSize, '\0', ( ULONG ) pArea->uiRecordLen - ulSize ); + + /* 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, USHORT uiField, BOOL fLength ) +{ + if( !pArea->pFieldBits ) + { + ULONG ulSize = sizeof( HB_DBFFIELDBITS ) * pArea->uiFieldExtent; + pArea->pFieldBits = memset( hb_xgrab( ulSize ), 0, ulSize ); + } + if( fLength ) + pArea->pFieldBits[ uiField ].uiLengthBit = pArea->uiNullCount++; + else + pArea->pFieldBits[ uiField ].uiNullBit = pArea->uiNullCount++; +} + +static BOOL hb_dbfGetNullFlag( DBFAREAP pArea, USHORT uiBit ) +{ + return ( pArea->pRecord[ pArea->uiNullOffset + ( uiBit >> 3 ) ] & + ( 1 << ( uiBit & 0x07 ) ) ) != 0; +} + +static void hb_dbfSetNullFlag( DBFAREAP pArea, USHORT uiBit ) +{ + pArea->pRecord[ pArea->uiNullOffset + ( uiBit >> 3 ) ] |= 1 << ( uiBit & 0x07 ); +} + +static void hb_dbfClearNullFlag( DBFAREAP pArea, USHORT uiBit ) +{ + pArea->pRecord[ pArea->uiNullOffset + ( uiBit >> 3 ) ] &= ~( 1 << ( uiBit & 0x07 ) ); } /* @@ -1858,7 +1896,7 @@ static HB_ERRCODE hb_dbfGetValue( DBFAREAP pArea, USHORT uiIndex, PHB_ITEM pItem { case HB_FT_STRING: #ifndef HB_CDP_SUPPORT_OFF - if( pArea->cdPage != hb_vmCDP() ) + if( ( pField->uiFlags & HB_FF_BINARY ) == 0 && pArea->cdPage != hb_vmCDP() ) { char * pVal = ( char * ) hb_xgrab( pField->uiLen + 1 ); memcpy( pVal, pArea->pRecord + pArea->pFieldOffset[ uiIndex ], pField->uiLen ); @@ -1874,6 +1912,19 @@ static HB_ERRCODE hb_dbfGetValue( DBFAREAP pArea, USHORT uiIndex, PHB_ITEM pItem } break; + case HB_FT_VARLENGTH: + { + USHORT uiLen = pField->uiLen; + if( hb_dbfGetNullFlag( pArea, pArea->pFieldBits[ uiIndex ].uiLengthBit ) ) + { + uiLen = ( UCHAR ) pArea->pRecord[ pArea->pFieldOffset[ uiIndex ] + uiLen - 1 ]; + /* protection against corrupted files */ + if( uiLen > pField->uiLen ) + uiLen = pField->uiLen; + } + hb_itemPutCL( pItem, ( char * ) pArea->pRecord + pArea->pFieldOffset[ uiIndex ], uiLen ); + break; + } case HB_FT_LOGICAL: hb_itemPutL( pItem, pArea->pRecord[ pArea->pFieldOffset[ uiIndex ] ] == 'T' || pArea->pRecord[ pArea->pFieldOffset[ uiIndex ] ] == 't' || @@ -2298,19 +2349,31 @@ static HB_ERRCODE hb_dbfPutValue( DBFAREAP pArea, USHORT uiIndex, PHB_ITEM pItem memcpy( pArea->pRecord + pArea->pFieldOffset[ uiIndex ], hb_itemGetCPtr( pItem ), uiSize ); #ifndef HB_CDP_SUPPORT_OFF - hb_cdpnTranslate( (char *) pArea->pRecord + pArea->pFieldOffset[ uiIndex ], hb_vmCDP(), pArea->cdPage, uiSize ); + if( ( pField->uiFlags & HB_FF_BINARY ) == 0 ) + hb_cdpnTranslate( ( char * ) pArea->pRecord + pArea->pFieldOffset[ uiIndex ], hb_vmCDP(), pArea->cdPage, uiSize ); #endif memset( pArea->pRecord + pArea->pFieldOffset[ uiIndex ] + uiSize, ' ', pField->uiLen - uiSize ); } - else if( pField->uiType == HB_FT_DAYTIME ) + else if( pField->uiType == HB_FT_VARLENGTH ) { - LONG lJulian, lMillisec; - BYTE * ptr = pArea->pRecord + pArea->pFieldOffset[ uiIndex ]; - hb_timeStampStrGetDT( hb_itemGetCPtr( pItem ), &lJulian, &lMillisec ); - HB_PUT_LE_UINT32( ptr, lJulian ); - ptr += 4; - HB_PUT_LE_UINT32( ptr, lMillisec ); + uiSize = ( USHORT ) hb_itemGetCLen( pItem ); + if( uiSize >= pField->uiLen ) + { + uiSize = pField->uiLen; + hb_dbfClearNullFlag( pArea, pArea->pFieldBits[ uiIndex ].uiLengthBit ); + } + else + { + pArea->pRecord[ pArea->pFieldOffset[ uiIndex ] + pField->uiLen - 1 ] = ( BYTE ) uiSize; + hb_dbfSetNullFlag( pArea, pArea->pFieldBits[ uiIndex ].uiLengthBit ); + } + memcpy( pArea->pRecord + pArea->pFieldOffset[ uiIndex ], + hb_itemGetCPtr( pItem ), uiSize ); +#ifndef HB_CDP_SUPPORT_OFF + if( ( pField->uiFlags & HB_FF_BINARY ) == 0 ) + hb_cdpnTranslate( ( char * ) pArea->pRecord + pArea->pFieldOffset[ uiIndex ], hb_vmCDP(), pArea->cdPage, uiSize ); +#endif } else uiError = EDBF_DATATYPE; @@ -2510,6 +2573,11 @@ static HB_ERRCODE hb_dbfPutValue( DBFAREAP pArea, USHORT uiIndex, PHB_ITEM pItem hb_itemRelease( pError ); return uiError == E_DEFAULT ? HB_SUCCESS : HB_FAILURE; } + else if( pArea->bTableType == DB_DBF_VFP && + ( pField->uiFlags & HB_FF_NULLABLE ) != 0 ) + { + hb_dbfClearNullFlag( pArea, pArea->pFieldBits[ uiIndex ].uiNullBit ); + } return HB_SUCCESS; } @@ -2695,6 +2763,13 @@ static HB_ERRCODE hb_dbfClose( DBFAREAP pArea ) pArea->pFieldOffset = NULL; } + /* Free field bits array */ + if( pArea->pFieldBits ) + { + hb_xfree( pArea->pFieldBits ); + pArea->pFieldBits = NULL; + } + /* Free buffer */ if( pArea->pRecord ) { @@ -2778,18 +2853,6 @@ static HB_ERRCODE hb_dbfCreate( DBFAREAP pArea, LPDBOPENINFO pCreateInfo ) fRawBlob = SELF_RDDINFO( SELF_RDDNODE( pArea ), RDDI_BLOB_SUPPORT, pCreateInfo->ulConnection, pItem ) == HB_SUCCESS && hb_itemGetL( pItem ); - if( pArea->bTableType == 0 ) - { - pItem = hb_itemPutNI( pItem, 0 ); - if( SELF_INFO( ( AREAP ) pArea, DBI_TABLETYPE, pItem ) != HB_SUCCESS ) - { - hb_itemRelease( pItem ); - pArea->lpdbOpenInfo = NULL; - return HB_FAILURE; - } - pArea->bTableType = hb_itemGetNI( pItem ); - } - if( pArea->bLockType == 0 ) { pItem = hb_itemPutNI( pItem, 0 ); @@ -2887,12 +2950,12 @@ static HB_ERRCODE hb_dbfCreate( DBFAREAP pArea, LPDBOPENINFO pCreateInfo ) pArea->szDataFileName = hb_strdup( ( char * ) szFileName ); - ulSize = pArea->uiFieldCount * sizeof( DBFFIELD ) + + ulSize = ( ULONG ) pArea->uiFieldCount * sizeof( DBFFIELD ) + ( pArea->bTableType == DB_DBF_VFP ? 1 : 2 ); if( pArea->uiFieldCount ) { - pBuffer = ( BYTE * ) hb_xgrab( ulSize + 1 ); - memset( pBuffer, 0, ulSize ); + pBuffer = ( BYTE * ) hb_xgrab( ulSize + sizeof( DBFFIELD ) + 1 ); + memset( pBuffer, 0, ulSize + sizeof( DBFFIELD ) + 1 ); } else { @@ -2904,7 +2967,7 @@ static HB_ERRCODE hb_dbfCreate( DBFAREAP pArea, LPDBOPENINFO pCreateInfo ) /* Size for deleted flag */ pArea->uiRecordLen = 1; - + pArea->uiNullCount = 0; for( uiCount = 0; uiCount < pArea->uiFieldCount; uiCount++ ) { LPFIELD pField = pArea->lpFields + uiCount; @@ -2914,6 +2977,7 @@ static HB_ERRCODE hb_dbfCreate( DBFAREAP pArea, LPDBOPENINFO pCreateInfo ) /* field offset */ if( pArea->bTableType == DB_DBF_VFP ) HB_PUT_LE_UINT16( pThisField->bReserved1, pArea->uiRecordLen ); + pThisField->bFieldFlags = ( BYTE ) pField->uiFlags; switch( pField->uiType ) { @@ -2970,23 +3034,24 @@ static HB_ERRCODE hb_dbfCreate( DBFAREAP pArea, LPDBOPENINFO pCreateInfo ) break; case HB_FT_ANY: - pThisField->bType = 'V'; - if( pField->uiLen < 3 || pField->uiLen == 5 ) - { - pField->uiLen = 6; - } - pThisField->bLen = ( BYTE ) pField->uiLen; - pThisField->bDec = ( BYTE ) ( pField->uiLen >> 8 ); - pArea->uiRecordLen += pField->uiLen; - if( pThisField->bLen >= 6 ) - { - pArea->uiMemoVersion = DB_MEMOVER_SIX; - pArea->fHasMemo = TRUE; - } - /* if( pArea->bTableType == DB_DBF_VFP ) fError = TRUE; - */ + else + { + pThisField->bType = 'V'; + if( pField->uiLen < 3 || pField->uiLen == 5 ) + { + pField->uiLen = 6; + } + pThisField->bLen = ( BYTE ) pField->uiLen; + pThisField->bDec = ( BYTE ) ( pField->uiLen >> 8 ); + pArea->uiRecordLen += pField->uiLen; + if( pThisField->bLen >= 6 ) + { + pArea->uiMemoVersion = DB_MEMOVER_SIX; + pArea->fHasMemo = TRUE; + } + } break; case HB_FT_DATE: @@ -3037,6 +3102,20 @@ static HB_ERRCODE hb_dbfCreate( DBFAREAP pArea, LPDBOPENINFO pCreateInfo ) pArea->uiRecordLen += pField->uiLen; break; + case HB_FT_VARLENGTH: + if( pField->uiLen > 255 ) + pField->uiLen = 255; + else if( pField->uiLen == 0 ) + pField->uiLen = 1; + if( pArea->bTableType == DB_DBF_VFP && ( pField->uiFlags & HB_FF_BINARY ) == 0 ) + pThisField->bType = 'V'; + else + pThisField->bType = 'Q'; + pThisField->bLen = ( BYTE ) pField->uiLen; + pArea->uiRecordLen += pField->uiLen; + hb_dbfAllocNullFlag( pArea, uiCount, TRUE ); + break; + case HB_FT_TIME: pThisField->bType = 'T'; pField->uiLen = 4; @@ -3100,6 +3179,20 @@ static HB_ERRCODE hb_dbfCreate( DBFAREAP pArea, LPDBOPENINFO pCreateInfo ) } 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 = ( BYTE ) uiCount; + pThisField->bDec = ( BYTE ) ( uiCount >> 8 ); + pArea->uiRecordLen += uiCount; + ulSize += sizeof( DBFFIELD ); + } + pArea->fShared = FALSE; /* pCreateInfo->fShared */ pArea->fReadonly = FALSE; /* pCreateInfo->fReadonly */ pArea->ulRecCount = 0; @@ -3441,6 +3534,29 @@ static HB_ERRCODE hb_dbfInfo( DBFAREAP pArea, USHORT uiIndex, PHB_ITEM pItem ) return errCode; } +static HB_ERRCODE hb_dbfFieldInfo( DBFAREAP pArea, USHORT uiIndex, USHORT uiType, PHB_ITEM pItem ) +{ + HB_TRACE(HB_TR_DEBUG, ("hb_dbfFieldInfo(%p, %hu, %hu, %p)", pArea, uiIndex, uiType, pItem)); + + if( uiIndex > pArea->uiFieldCount ) + return HB_FAILURE; + + switch( uiType ) + { + case DBS_ISNULL: + { + LPFIELD pField = pArea->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; + } + default: + return SUPER_FIELDINFO( ( AREAP ) pArea, uiIndex, uiType, pItem ); + } +} + /* * Retrieve information about a raw */ @@ -3592,6 +3708,14 @@ static HB_ERRCODE hb_dbfNewArea( DBFAREAP pArea ) 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 ), RDDI_TABLETYPE, 0, pItem ) == HB_SUCCESS ) + pArea->bTableType = hb_itemGetNI( pItem ); + hb_itemRelease( pItem ); + } + return HB_SUCCESS; } @@ -3862,6 +3986,7 @@ static HB_ERRCODE hb_dbfOpen( DBFAREAP pArea, LPDBOPENINFO pOpenInfo ) /* Size for deleted flag */ pArea->uiRecordLen = 1; + pArea->uiNullCount = 0; for( uiCount = 0; uiCount < uiFields + uiSkip; uiCount++ ) { pField = ( LPDBFFIELD ) ( pBuffer + uiCount * sizeof( DBFFIELD ) ); @@ -3987,13 +4112,18 @@ static HB_ERRCODE hb_dbfOpen( DBFAREAP pArea, LPDBOPENINFO pOpenInfo ) case 'Q': dbFieldInfo.uiType = HB_FT_VARLENGTH; - dbFieldInfo.uiFlags |= HB_FF_BINARY; + if( pArea->bTableType == DB_DBF_VFP ) + dbFieldInfo.uiFlags |= HB_FF_BINARY; + else + dbFieldInfo.uiFlags |= HB_FF_BINARY & pField->bFieldFlags; + hb_dbfAllocNullFlag( pArea, uiCount, TRUE ); break; case 'V': if( pArea->bTableType == DB_DBF_VFP ) { dbFieldInfo.uiType = HB_FT_VARLENGTH; + hb_dbfAllocNullFlag( pArea, uiCount, TRUE ); } else { @@ -4030,12 +4160,11 @@ static HB_ERRCODE hb_dbfOpen( DBFAREAP pArea, LPDBOPENINFO pOpenInfo ) break; case '0': - if( pArea->bTableType == DB_DBF_VFP && pField->bFieldFlags & 0x01 ) + if( /* pArea->bTableType == DB_DBF_VFP && */ + ( pField->bFieldFlags & HB_FF_HIDDEN ) != 0 ) { if( memcmp( dbFieldInfo.atomName, "_NullFlags", 10 ) == 0 ) - { - /* TODO: NULLABLE and VARLENGTH support */ - } + pArea->uiNullOffset = pArea->uiRecordLen; pArea->uiRecordLen += dbFieldInfo.uiLen; continue; } @@ -4045,9 +4174,16 @@ static HB_ERRCODE hb_dbfOpen( DBFAREAP pArea, LPDBOPENINFO pOpenInfo ) break; } - /* Add field */ if( errCode == HB_SUCCESS ) + { + if( pArea->bTableType == DB_DBF_VFP && + ( pField->bFieldFlags & HB_FF_NULLABLE ) != 0 ) + { + hb_dbfAllocNullFlag( pArea, uiCount, FALSE ); + } + /* Add field */ errCode = SELF_ADDFIELD( ( AREAP ) pArea, &dbFieldInfo ); + } /* Exit if error */ if( errCode != HB_SUCCESS ) @@ -4311,12 +4447,12 @@ void hb_dbfTranslateRec( DBFAREAP pArea, BYTE * pBuffer, PHB_CODEPAGE cdp_src, P for( uiIndex = 0, pField = pArea->lpFields; uiIndex < pArea->uiFieldCount; uiIndex++, pField++ ) { - if( pField->uiType == HB_FT_STRING && ( pField->uiFlags && HB_FF_BINARY ) == 0 ) + if( ( pField->uiFlags && HB_FF_BINARY ) == 0 && + ( pField->uiType == HB_FT_STRING || pField->uiType == HB_FT_VARLENGTH ) ) { hb_cdpnTranslate( ( char * ) pBuffer + pArea->pFieldOffset[ uiIndex ], cdp_src, cdp_dest, pField->uiLen ); } } - } #endif @@ -5037,6 +5173,7 @@ static HB_ERRCODE hb_dbfReadDBHeader( DBFAREAP pArea ) case 0x31: pArea->fAutoInc = TRUE; case 0x30: + case 0x32: pArea->bTableType = DB_DBF_VFP; if( pArea->dbfHeader.bHasTags & 0x02 ) { diff --git a/harbour/source/rdd/workarea.c b/harbour/source/rdd/workarea.c index 8a8e168214..6e0b70db96 100644 --- a/harbour/source/rdd/workarea.c +++ b/harbour/source/rdd/workarea.c @@ -263,7 +263,7 @@ static HB_ERRCODE hb_waAddField( AREAP pArea, LPDBFIELDINFO pFieldInfo ) pField->uiDec = pFieldInfo->uiDec; pField->uiFlags = pFieldInfo->uiFlags; pField->uiArea = pArea->uiArea; - pArea->uiFieldCount ++; + pArea->uiFieldCount++; return HB_SUCCESS; } @@ -417,7 +417,7 @@ static HB_ERRCODE hb_waCreateFields( AREAP pArea, PHB_ITEM pStruct ) case 'Q': pFieldInfo.uiType = HB_FT_VARLENGTH; - pFieldInfo.uiLen = uiLen > 255 ? 255 : uiLen; + pFieldInfo.uiLen = uiLen > 255 ? 255 : ( uiLen == 0 ? 1 : uiLen ); break; case 'M':