diff --git a/harbour/ChangeLog b/harbour/ChangeLog index 09b690ffd1..afa9b341be 100644 --- a/harbour/ChangeLog +++ b/harbour/ChangeLog @@ -8,6 +8,68 @@ 2002-12-01 23:12 UTC+0100 Foo Bar */ +2005-09-23 15:45 UTC+0100 Ryszard Glab + * config/global.cf + * include/dbinfo.ch + * include/hbapi.h + * include/hbapierr.h + * include/hbapifs.h + * include/hbapirdd.h + * include/hbdbf.h + * include/hbdbferr.h + * include/hbdefs.h + * include/hbrddcdx.h + * include/hbrdddbf.h + * include/hbrdddbt.h + * include/hbrdddel.h + * include/hbrddfpt.h + * include/hbrddntx.h + * include/hbrddsdf.h + * include/hbrddwrk.h + * include/hbvm.h + * source/common/hbstr.c + * source/rdd/Makefile + * source/rdd/dbcmd.c + * source/rdd/dbf1.c + * source/rdd/dbtotal.prg + * source/rdd/delim0.prg + * source/rdd/delim1.c + * source/rdd/rddsys.prg + * source/rdd/sdf0.prg + * source/rdd/sdf1.c + * source/rdd/workarea.c + * source/rdd/dbfcdx/Makefile + * source/rdd/dbfcdx/dbfcdx0.prg + * source/rdd/dbfcdx/dbfcdx1.c + * source/rdd/dbfdbt/Makefile + * source/rdd/dbfdbt/dbfdbt1.c + * source/rdd/dbffpt/Makefile + * source/rdd/dbffpt/dbffpt0.prg + * source/rdd/dbffpt/dbffpt1.c + * source/rdd/dbfntx/Makefile + * source/rdd/dbfntx/dbfntx0.prg + * source/rdd/dbfntx/dbfntx1.c + * source/rdd/nulsys/nulsys.prg + * source/rtl/errorapi.c + * source/rtl/filesys.c + * source/vm/dynsym.c + * source/vm/extend.c + * source/vm/itemapi.c + * source/vm/hvm.c + + include/hbsxfunc.h + + source/rdd/dbfcdx/sixcdx0.prg + + source/rdd/dbfcdx/sixcdx1.c + + source/rdd/hbsix/Makefile + + source/rdd/hbsix/sxcompr.c + + source/rdd/hbsix/sxcrypt.c + + source/rdd/hbsix/sxdate.c + + source/rdd/hsx/Makefile + + source/rdd/hsx/cftsfunc.c + + source/rdd/hsx/hsx.c + * changes to synhronize RDD code with xHarbour (state of 23.09.2005) + Many, many thanks to Przemek Czerpak for his work. + + 2005-09-20 10:16 UTC+0100 Viktor Szakats * source/rtl/tget.prg diff --git a/harbour/config/global.cf b/harbour/config/global.cf index 82be78e66a..4da1ae971d 100644 --- a/harbour/config/global.cf +++ b/harbour/config/global.cf @@ -11,6 +11,8 @@ HB_DB_DRIVERS=\ dbfcdx \ dbffpt \ dbfdbt \ + hbsix \ + hsx \ ifeq ($(HB_BIN_COMPILE),) HB_BIN_COMPILE := $(TOP)$(ROOT)source/compiler/$(HB_ARCH) diff --git a/harbour/include/dbinfo.ch b/harbour/include/dbinfo.ch index 9e2df31297..71d98e42ba 100644 --- a/harbour/include/dbinfo.ch +++ b/harbour/include/dbinfo.ch @@ -53,6 +53,54 @@ #ifndef HB_DBINFO_CH_ #define HB_DBINFO_CH_ +/* + Constants for SELF_RDDINFO () +*/ + +#define RDDI_ISDBF 1 /* Does this RDD support DBFs? */ +#define RDDI_CANPUTREC 2 /* Can this RDD Put Records? */ +#define RDDI_DELIMITER 3 /* The field delimiter (as a string) */ +#define RDDI_SEPARATOR 4 /* The record separator (as a string) */ + +#define RDDI_TABLEEXT 5 /* Default data file's file extension */ +#define RDDI_MEMOEXT 6 /* Default memo file's file extension */ +#define RDDI_ORDBAGEXT 7 /* Default multi tag index's file extension */ +#define RDDI_ORDEREXT 8 /* default single tag index's file extension */ +#define RDDI_ORDSTRUCTEXT 9 /* default single tag index's file extension */ + +#define RDDI_LOCAL 10 /* Local file access? */ +#define RDDI_REMOTE 11 /* Remote table access? */ +#define RDDI_CONNECTION 12 /* Get/Set default connection */ +#define RDDI_TABLETYPE 13 /* Type of table file */ +#define RDDI_MEMOTYPE 14 /* Type of MEMO file: DBT, SMT, FPT(FP,SIX3,FLEXIII) */ +#define RDDI_LARGEFILE 15 /* Is large file size (>=4GB) supported */ +#define RDDI_LOCKSCHEME 16 /* Locking scheme used by RDD */ +#define RDDI_RECORDMAP 17 /* Does RDD support record map functionality? */ +#define RDDI_ENCRYPTION 18 /* Does RDD support encryption */ +#define RDDI_TRIGGERS 19 /* Get/Set default trigger function */ +#define RDDI_AUTOLOCK 20 /* automatic locking on update */ + +/* index parameters */ +#define RDDI_STRUCTORD 21 /* Are structural indexes supported */ +#define RDDI_STRICTREAD 22 /* Flag for avoiding RDD hierarchy and using a bigger buffer when indexing */ +#define RDDI_STRICTSTRUCT 23 /* Flag for strict structural order checking */ +#define RDDI_OPTIMIZE 24 /* Flag for whether to use query optimization */ +#define RDDI_FORCEOPT 25 /* Flag for forcing linear optimization */ +#define RDDI_AUTOOPEN 26 /* Flag for automatically opening structural indexes */ +#define RDDI_AUTOORDER 27 /* When a structural index is opened, the order to be set */ +#define RDDI_AUTOSHARE 28 /* When a network is detected, open the index shared, otherwise open exclusively */ +#define RDDI_MULTITAG 29 /* Does RDD support multi tag in index file */ +#define RDDI_SORTRECNO 30 /* Is record number part of key in sorting */ +#define RDDI_MULTIKEY 31 /* Does custom orders support repeated keys? */ + +/* memo parameters */ +#define RDDI_MEMOBLOCKSIZE 32 /* Memo File's block size */ +#define RDDI_MEMOVERSION 33 /* sub version of memo file */ +#define RDDI_MEMOGCTYPE 34 /* type of garbage collector used by GC */ +#define RDDI_MEMOREADLOCK 35 /* use read lock in memo file access */ +#define RDDI_MEMOREUSE 36 /* reuse free space on write */ + + /* Constants for SELF_ORDINFO () */ @@ -90,13 +138,14 @@ #define DBOI_SCOPEBOTTOM 40 /* Get or Set the scope botto */ #define DBOI_SCOPETOPCLEAR 41 /* Clear the scope top */ #define DBOI_SCOPEBOTTOMCLEAR 42 /* Clear the scope bottom */ - #define DBOI_CUSTOM 45 /* Is this a Custom Index? */ #define DBOI_SKIPUNIQUE 46 /* Was a skip to adjacent unique Key successful? */ #define DBOI_KEYSINCLUDED 50 /* Number of keys in the index order */ /* key numbers and counts */ #define DBOI_KEYGOTO DBOI_POSITION +#define DBOI_KEYGOTORAW DBOI_KEYNORAW +#define DBOI_KEYNO DBOI_POSITION #define DBOI_KEYNORAW 51 /* The key number disregarding filters */ #define DBOI_KEYCOUNTRAW 52 /* The key count disregarding filter */ @@ -110,7 +159,7 @@ #define DBOI_AUTOORDER 63 /* When a structural index is opened, the order to be set */ #define DBOI_AUTOSHARE 64 /* When a network is detected, open the index shared, otherwise open exclusively */ -/* Harbour extensions */ +/* xHarbour extensions */ #define DBOI_SKIPEVAL 100 /* skip while code block doesn't return TRUE */ #define DBOI_SKIPEVALBACK 101 /* skip backward while code block doesn't return TRUE */ #define DBOI_SKIPREGEX 102 /* skip while regular expression on index key doesn't return TRUE */ @@ -118,6 +167,34 @@ #define DBOI_SKIPWILD 104 /* skip while while comparison with given pattern with wildcards doesn't return TRUE */ #define DBOI_SKIPWILDBACK 105 /* skip backward while comparison with given pattern with wildcards doesn't return TRUE */ #define DBOI_SCOPEEVAL 106 /* skip through index evaluating given C function */ +#define DBOI_FINDREC 107 /* find given record in a Tag beginning from TOP */ +#define DBOI_FINDRECCONT 108 /* find given record in a Tag beginning from current position */ +#define DBOI_SCOPESET 109 /* set both scopes */ +#define DBOI_SCOPECLEAR 110 /* clear both scopes */ + +#define DBOI_BAGCOUNT 111 /* number of open order bags */ +#define DBOI_BAGNUMBER 112 /* bag position in bag list */ +#define DBOI_BAGORDER 113 /* number of first order in a bag */ + +#define DBOI_ISMULTITAG 114 /* does RDD support multi tag in index file */ +#define DBOI_ISSORTRECNO 115 /* is record number part of key in sorting */ +#define DBOI_LARGEFILE 116 /* is large file size (>=4GB) supported */ +#define DBOI_TEMPLATE 117 /* order with free user keys */ +#define DBOI_MULTIKEY 118 /* custom order with multikeys */ +#define DBOI_CHGONLY 119 /* update only existing keys */ +#define DBOI_PARTIAL 120 /* is index partially updated */ +#define DBOI_SHARED 121 /* is index open in shared mode */ +#define DBOI_ISREADONLY 122 /* is index open in readonly mode */ +#define DBOI_READLOCK 123 /* get/set index read lock */ +#define DBOI_WRITELOCK 124 /* get/set index write lock */ +#define DBOI_UPDATECOUNTER 125 /* get/set update index counter */ + +#define DBOI_EVALSTEP 126 /* eval step (EVERY) used in index command */ +#define DBOI_ISREINDEX 127 /* Is reindex in process */ +#define DBOI_I_BAGNAME 128 /* created index name */ +#define DBOI_I_TAGNAME 129 /* created tag name */ + +#define DBOI_RELKEYPOS 130 /* get/set relative key position (in range 0 - 1) */ /* Return values for DBOI_OPTLEVEL */ #define DBOI_OPTIMIZED_NONE 0 @@ -130,9 +207,10 @@ #define DBRI_RECSIZE 3 #define DBRI_RECNO 4 #define DBRI_UPDATED 5 -#define DBRI_RAWRECORD 6 -#define DBRI_RAWMEMOS 7 -#define DBRI_RAWDATA 8 +#define DBRI_ENCRYPTED 6 +#define DBRI_RAWRECORD 7 +#define DBRI_RAWMEMOS 8 +#define DBRI_RAWDATA 9 /* constants for some SCOPED DBOI_* parameter */ #define DBRMI_FUNCTION 1 @@ -179,8 +257,24 @@ #define DBI_LOCKSCHEME 128 /* Locking scheme used by RDD */ #define DBI_ISREADONLY 129 /* Was the file opened readonly? */ #define DBI_ROLLBACK 130 /* Rollback changes made to current record */ +#define DBI_PASSWORD 131 /* Workarea password */ +#define DBI_ISENCRYPTED 132 /* The database is encrypted */ +#define DBI_MEMOTYPE 133 /* Type of MEMO file: DBT, SMT, FPT */ +#define DBI_SEPARATOR 134 /* The record separator (as a string) */ +#define DBI_MEMOVERSION 135 /* sub version of memo file */ +#define DBI_TABLETYPE 136 /* Type of table file */ -#define DBI_USER 1000 /* User-defined DBI_ constants */ +/* RECORD MAP (RM) support */ +#define DBI_RM_SUPPORTED 150 /* has WA RDD record map support? */ +#define DBI_RM_CREATE 151 /* create new empty work area record map */ +#define DBI_RM_REMOVE 152 /* remove active work area record map */ +#define DBI_RM_CLEAR 153 /* remove all records from WA record map */ +#define DBI_RM_FILL 154 /* add all records to WA record map */ +#define DBI_RM_ADD 155 /* add record to work area record map */ +#define DBI_RM_DROP 156 /* remove record from work area record map */ +#define DBI_RM_TEST 157 /* test if record is set in WA record map */ +#define DBI_RM_COUNT 158 /* number of records set in record map */ +#define DBI_RM_HANDLE 159 /* get/set record map filter handle */ /* BLOB support - definitions for internal use by BLOB.CH */ #define DBI_BLOB_DIRECT_EXPORT 201 @@ -199,6 +293,9 @@ #define DBI_BLOB_OFFSET 212 #define DBI_BLOB_RECOVER 213 +#define DBI_USER 1000 /* User-defined DBI_ constants */ + +/* extended dbFieldInfo() actions */ #define DBS_BLOB_GET 201 /* This is internal definition */ #define DBS_BLOB_LEN 202 #define DBS_BLOB_OFFSET 203 @@ -208,4 +305,42 @@ #define BLOB_EXPORT_APPEND 1 #define BLOB_EXPORT_OVERWRITE 0 +#define BLOB_IMPORT_COMPRESS 1 +#define BLOB_IMPORT_ENCRYPT 2 + +#define FILEGET_APPEND BLOB_EXPORT_APPEND +#define FILEGET_OVERWRITE BLOB_EXPORT_OVERWRITE + +#define FILEPUT_COMPRESS BLOB_IMPORT_COMPRESS +#define FILEPUT_ENCRYPT BLOB_IMPORT_ENCRYPT + +/* DBF TYPES */ +#define DB_DBF_STD 0 +#define DB_DBF_VFP 1 + +/* MEMO TYPES */ +#define DB_MEMO_NONE 0 +#define DB_MEMO_DBT 1 +#define DB_MEMO_FPT 2 +#define DB_MEMO_SMT 3 + +/* MEMO EXTENDED TYPES */ +#define DB_MEMOVER_STD 1 +#define DB_MEMOVER_SIX 2 +#define DB_MEMOVER_FLEX 3 +#define DB_MEMOVER_CLIP 4 + +/* ENCRYPTION TYPE */ +#define DB_CRYPT_NONE 0 +#define DB_CRYPT_SIX 1 + +/* LOCK SCHEMES */ +#define DB_DBFLOCK_DEFAULT 0 +#define DB_DBFLOCK_CLIP 1 +#define DB_DBFLOCK_CL53 2 +#define DB_DBFLOCK_VFP 3 +#define DB_DBFLOCK_CL53EXT 4 +#define DB_DBFLOCK_XHB64 5 + + #endif /* HB_DBINFO_CH_ */ diff --git a/harbour/include/hbapi.h b/harbour/include/hbapi.h index b6471fcc9f..303e21135f 100644 --- a/harbour/include/hbapi.h +++ b/harbour/include/hbapi.h @@ -104,6 +104,7 @@ HB_EXTERN_BEGIN #define HB_IS_MEMVAR( p ) HB_IS_OF_TYPE( p, HB_IT_MEMVAR ) #define HB_IS_POINTER( p ) HB_IS_OF_TYPE( p, HB_IT_POINTER ) #define HB_IS_NUMERIC( p ) ( ( p )->type & HB_IT_NUMERIC ) +#define HB_IS_NUMBER( p ) ( ( p )->type & HB_IT_NUMERIC ) #define HB_IS_NUMINT( p ) ( ( p )->type & HB_IT_NUMINT ) #define HB_IS_COMPLEX( p ) ( ( p )->type & HB_IT_COMPLEX ) #define HB_IS_BADITEM( p ) ( ( p )->type & HB_IT_COMPLEX && ( p )->type & ~( HB_IT_COMPLEX | HB_IT_MEMOFLAG ) ) @@ -313,10 +314,12 @@ extern HB_SYMB hb_symEval; /* Extend API */ extern char HB_EXPORT * hb_parc( int iParam, ... ); /* retrieve a string parameter */ +extern char HB_EXPORT * hb_parcx( int iParam, ... ); /* retrieve a string parameter */ extern ULONG HB_EXPORT hb_parclen( int iParam, ... ); /* retrieve a string parameter length */ extern ULONG HB_EXPORT hb_parcsiz( int iParam, ... ); /* retrieve a by-reference string parameter length, including terminator */ extern char HB_EXPORT * hb_pards( int iParam, ... ); /* retrieve a date as a string yyyymmdd */ extern char HB_EXPORT * hb_pardsbuff( char * szDate, int iParam, ... ); /* retrieve a date as a string yyyymmdd */ +extern LONG HB_EXPORT hb_pardl( int iParam, ... ); /* retrieve a date as a LONG NUMBER */ extern ULONG HB_EXPORT hb_parinfa( int iParamNum, ULONG uiArrayIndex ); /* retrieve length or element type of an array parameter */ extern int HB_EXPORT hb_parinfo( int iParam ); /* Determine the param count or data type */ extern int HB_EXPORT hb_parl( int iParam, ... ); /* retrieve a logical parameter as an int */ @@ -352,6 +355,7 @@ extern LONGLONG HB_EXPORT hb_parnll( int iParam, ... ); /* retrieve a numeric #define hb_retc_const( szText ) hb_itemPutCConst( &hb_stack.Return, szText ) #define hb_retclen( szText, ulLen ) hb_itemPutCL( &hb_stack.Return, szText, ulLen ) #define hb_retclen_buffer( szText, ulLen ) hb_itemPutCPtr( &hb_stack.Return, szText, ulLen ) +#define hb_retcAdopt( szText ) hb_itemPutCPtr( &hb_stack.Return, (szText), strlen( szText ) ) #define hb_retds( szDate ) hb_itemPutDS( &hb_stack.Return, szDate ) #define hb_retd( lYear, lMonth, lDay ) hb_itemPutD( &hb_stack.Return, lYear, lMonth, lDay ) #define hb_retdl( lJulian ) hb_itemPutDL( &hb_stack.Return, lJulian ) @@ -379,6 +383,7 @@ extern void HB_EXPORT hb_retc_buffer( char * szText ); /* sames as above, but extern void HB_EXPORT hb_retc_const( char * szText ); /* returns a string as a pcode based string */ extern void HB_EXPORT hb_retclen( char * szText, ULONG ulLen ); /* returns a string with a specific length */ extern void HB_EXPORT hb_retclen_buffer( char * szText, ULONG ulLen ); /* sames as above, but accepts an allocated buffer */ +extern void HB_EXPORT hb_retcAdopt( char * szText ); /* adopts a pointer to a string as the value of an item */ extern void HB_EXPORT hb_retds( char * szDate ); /* returns a date, must use yyyymmdd format */ extern void HB_EXPORT hb_retd( int iYear, int iMonth, int iDay ); /* returns a date */ extern void HB_EXPORT hb_retdl( long lJulian ); /* returns a long value as a julian date */ @@ -444,6 +449,7 @@ extern BOOL HB_EXPORT hb_arrayNew( PHB_ITEM pItem, ULONG ulLen ); /* creat extern ULONG HB_EXPORT hb_arrayLen( PHB_ITEM pArray ); /* retrives the array len */ extern BOOL HB_EXPORT hb_arrayIsObject( PHB_ITEM pArray ); /* retrives if the array is an object */ extern BOOL HB_EXPORT hb_arrayAdd( PHB_ITEM pArray, PHB_ITEM pItemValue ); /* add a new item to the end of an array item */ +extern BOOL HB_EXPORT hb_arrayAddForward( PHB_ITEM pArray, PHB_ITEM pValue ); /* add a new item to the end of an array item with no incrementing of reference counters */ extern BOOL HB_EXPORT hb_arrayIns( PHB_ITEM pArray, ULONG ulIndex ); /* insert a nil item into an array, without changing the length */ extern BOOL HB_EXPORT hb_arrayDel( PHB_ITEM pArray, ULONG ulIndex ); /* delete an array item, without changing length */ extern BOOL HB_EXPORT hb_arraySize( PHB_ITEM pArray, ULONG ulLen ); /* sets the array total length */ @@ -497,6 +503,7 @@ extern char * hb_strUpper( char * szText, ULONG ulLen ); /* convert an existin extern char * hb_strLower( char * szText, ULONG ulLen ); /* convert an existing string buffer to lower case */ extern char * hb_strncpy( char * pDest, const char * pSource, ULONG ulLen ); /* copy at most ulLen bytes from string buffer to another buffer and _always_ set 0 in destin buffer */ extern char * hb_strncat( char * pDest, const char * pSource, ULONG ulLen ); /* copy at most ulLen-strlen(pDest) bytes from string buffer to another buffer and _always_ set 0 in destin buffer */ +extern char * hb_strndup( const char * pszText, ULONG ulLen ); extern char * hb_strncpyTrim( char * pDest, const char * pSource, ULONG ulLen ); extern char * hb_strncpyUpper( char * pDest, const char * pSource, ULONG ulLen ); /* copy an existing string buffer to another buffer, as upper case */ extern char * hb_strncpyUpperTrim( char * pDest, const char * pSource, ULONG ulLen ); @@ -507,6 +514,8 @@ extern BOOL hb_compStrToNum( const char* szNum, HB_LONG * plVal, double * pd extern BOOL hb_valStrnToNum( const char* szNum, ULONG ulLen, HB_LONG * plVal, double * pdVal, int * piDec, int * piWidth ); extern BOOL hb_strToNum( const char* szNum, HB_LONG * plVal, double * pdVal ); /* converts string to number, returns TRUE if results is double */ extern BOOL hb_strnToNum( const char* szNum, ULONG ulLen, HB_LONG * plVal, double * pdVal ); /* converts string to number, returns TRUE if results is double */ +extern char * hb_xstrcat( char *dest, const char *src, ... ); /* Concatenates multiple strings into a single result */ +extern char * hb_xstrcpy( char *szDest, const char *szSrc, ...); /* Concatenates multiple strings into a single result */ extern double hb_numRound( double dResult, int iDec ); /* round a number to a specific number of digits */ extern double hb_numInt( double dNum ); /* take the integer part of the number */ @@ -526,6 +535,7 @@ extern USHORT hb_objGetClass( PHB_ITEM pItem ); /* dynamic symbol table management */ extern PHB_DYNS hb_dynsymGet( char * szName ); /* finds and creates a dynamic symbol if not found */ +extern PHB_DYNS hb_dynsymGetCase( char * szName ); /* finds and creates a dynamic symbol if not found - case sensitive */ extern PHB_DYNS hb_dynsymNew( PHB_SYMB pSymbol ); /* creates a new dynamic symbol based on a local one */ extern PHB_DYNS hb_dynsymFind( char * szName ); /* finds a dynamic symbol */ extern PHB_DYNS hb_dynsymFindName( char * szName ); /* converts to uppercase and finds a dynamic symbol */ diff --git a/harbour/include/hbapierr.h b/harbour/include/hbapierr.h index 03c1b22cee..1a74366b7a 100644 --- a/harbour/include/hbapierr.h +++ b/harbour/include/hbapierr.h @@ -143,12 +143,15 @@ extern PHB_ITEM hb_errRT_New_Subst( USHORT uiSeverity, char * szSubSystem, USHORT uiOsCode, USHORT uiFlags ); +extern PHB_ITEM hb_errRT_SubstParams( char *szSubSystem, ULONG ulGenCode, ULONG ulSubCode, char * szDescription, char * szOperation ); + extern USHORT hb_errRT_BASE ( ULONG ulGenCode, ULONG ulSubCode, char * szDescription, char * szOperation, ULONG ulArgCount, ... ); extern USHORT hb_errRT_BASE_Ext1 ( ULONG ulGenCode, ULONG ulSubCode, char * szDescription, char * szOperation, USHORT uiOsCode, USHORT uiFlags, ULONG ulArgCount, ... ); extern PHB_ITEM hb_errRT_BASE_Subst ( ULONG ulGenCode, ULONG ulSubCode, char * szDescription, char * szOperation, ULONG ulArgCount, ... ); extern void hb_errRT_BASE_SubstR ( ULONG ulGenCode, ULONG ulSubCode, char * szDescription, char * szOperation, ULONG ulArgCount, ... ); extern USHORT hb_errRT_TERM ( ULONG ulGenCode, ULONG ulSubCode, char * szDescription, char * szOperation, USHORT uiOSCode, USHORT uiFlags ); extern USHORT hb_errRT_DBCMD ( ULONG ulGenCode, ULONG ulSubCode, char * szDescription, char * szOperation ); +extern USHORT hb_errRT_DBCMD_Ext ( ULONG ulGenCode, ULONG ulSubCode, const char * szDescription, const char * szOperation, USHORT uiFlags ); extern USHORT hb_errRT_TOOLS ( ULONG ulGenCode, ULONG ulSubCode, char * szDescription, char * szOperation ); extern void hb_errInternal ( ULONG ulIntCode, char * szText, char * szPar1, char * szPar2 ); diff --git a/harbour/include/hbapifs.h b/harbour/include/hbapifs.h index 41a17f47bc..706d68e354 100644 --- a/harbour/include/hbapifs.h +++ b/harbour/include/hbapifs.h @@ -81,9 +81,14 @@ typedef int FHANDLE; /* Extended file open mode flags */ #define FXO_TRUNCATE 0x0100 /* Create (truncate if exists) */ #define FXO_APPEND 0x0200 /* Create (append if exists) */ +#define FXO_UNIQUE 0x0400 /* Create unique file FO_EXCL ??? */ #define FXO_FORCEEXT 0x0800 /* Force default extension */ #define FXO_DEFAULTS 0x1000 /* Use SET command defaults */ #define FXO_DEVICERAW 0x2000 /* Open devices in raw mode */ +/* xHarbour extension */ +#define FXO_SHARELOCK 0x4000 /* emulate DOS SH_DENY* mode in POSIX OS */ +#define FXO_COPYNAME 0x8000 /* copy final szPath into pFilename */ + /* File attributes flags */ #define HB_FA_ALL 0 @@ -145,10 +150,13 @@ extern FHANDLE HB_EXPORT hb_fsPOpen ( BYTE * pFilename, BYTE * pMode ); #define hb_fsFLock( h, s, l ) hb_fsLock( h, s, l, FL_LOCK ) #define hb_fsFUnlock( h, s, l ) hb_fsLock( h, s, l, FL_UNLOCK ) +#define HB_MAX_DRIVE_LENGTH 10 +#define HB_MAX_FILE_EXT 10 + /* Filename support */ typedef struct { - char szBuffer[ _POSIX_PATH_MAX + 3 + 10 ]; /* TOFIX: +10 is for the drive letter support, and should be changed to some manifest constant */ + char szBuffer[ _POSIX_PATH_MAX + HB_MAX_DRIVE_LENGTH + HB_MAX_FILE_EXT + 1 ]; /* TOFIX: +10 is for the drive letter support, and should be changed to some manifest constant */ char * szPath; char * szName; char * szExtension; @@ -167,7 +175,7 @@ typedef struct _HB_PATHNAMES extern void hb_fsAddSearchPath( char * szPath, HB_PATHNAMES * * pSearchList ); -extern BOOL hb_spFile( BYTE * pFilename, BYTE RetPath[ _POSIX_PATH_MAX + 3 + 10 ] ); +extern BOOL hb_spFile( BYTE * pFilename, BYTE RetPath[ _POSIX_PATH_MAX + HB_MAX_DRIVE_LENGTH + HB_MAX_FILE_EXT + 1 ] ); extern FHANDLE hb_spOpen( BYTE * pFilename, USHORT uiFlags ); extern FHANDLE hb_spCreate( BYTE * pFilename, USHORT uiAttr ); extern FHANDLE hb_spCreateEx( BYTE * pFilename, USHORT uiAttr, USHORT uiFlags ); diff --git a/harbour/include/hbapiitm.h b/harbour/include/hbapiitm.h index d4e88d9160..142e35001d 100644 --- a/harbour/include/hbapiitm.h +++ b/harbour/include/hbapiitm.h @@ -115,6 +115,7 @@ extern PHB_ITEM hb_itemPutNLLen ( PHB_ITEM pItem, long lNumber, int iWidth ); extern PHB_ITEM hb_itemPutPtr ( PHB_ITEM pItem, void * pValue ); extern BOOL hb_itemRelease ( PHB_ITEM pItem ); extern PHB_ITEM hb_itemReturn ( PHB_ITEM pItem ); +extern PHB_ITEM hb_itemReturnForward( PHB_ITEM pItem ); extern ULONG hb_itemSize ( PHB_ITEM pItem ); extern USHORT hb_itemType ( PHB_ITEM pItem ); extern char * hb_itemTypeStr ( PHB_ITEM pItem ); @@ -129,6 +130,7 @@ extern PHB_ITEM hb_itemPutNLLLen( PHB_ITEM pItem, LONGLONG lNumber, int iWidth extern PHB_ITEM hb_itemParamPtr ( USHORT uiParam, int iMask ); extern int hb_itemStrCmp ( PHB_ITEM pFirst, PHB_ITEM pSecond, BOOL bForceExact ); /* our string compare */ extern void hb_itemCopy ( PHB_ITEM pDest, PHB_ITEM pSource ); /* copies an item to one place to another respecting its containts */ +extern void hb_itemForwardValue( PHB_ITEM pDest, PHB_ITEM pSource ); /* copies the value of an item without incrementing of reference counters */ extern void hb_itemMove ( PHB_ITEM pDest, PHB_ITEM pSource ); extern void hb_itemClear ( PHB_ITEM pItem ); extern PHB_ITEM hb_itemUnRef ( PHB_ITEM pItem ); /* de-references passed variable */ diff --git a/harbour/include/hbapirdd.h b/harbour/include/hbapirdd.h index b64ff4fb6f..cb3f0a70b3 100644 --- a/harbour/include/hbapirdd.h +++ b/harbour/include/hbapirdd.h @@ -59,24 +59,33 @@ HB_EXTERN_BEGIN -#define HARBOUR_MAX_RDD_DRIVERNAME_LENGTH 32 -#define HARBOUR_MAX_RDD_ALIAS_LENGTH 32 +#define HARBOUR_MAX_RDD_DRIVERNAME_LENGTH 32 +#ifndef HARBOUR_MAX_RDD_ALIAS_LENGTH + #define HARBOUR_MAX_RDD_ALIAS_LENGTH 32 +#endif + +/* #define HARBOUR_MAX_RDD_FIELDNAME_LENGTH 32 */ +#define HARBOUR_MAX_RDD_AREA_NUM 65535 + +#define HARBOUR_MAX_RDD_RELTEXT_LENGTH 256 /* RDD virtual machine integration functions */ -extern USHORT hb_rddInsertAreaNode( char *szDriver ); -extern USHORT hb_rddGetCurrentFieldPos( char * szName ); -extern int hb_rddGetCurrentWorkAreaNumber( void ); -void * hb_rddGetCurrentWorkAreaPointer( void ); -extern ERRCODE hb_rddSelectWorkAreaAlias( char * szAlias ); -extern ERRCODE hb_rddSelectWorkAreaNumber( int iArea ); -extern ERRCODE hb_rddSelectWorkAreaSymbol( PHB_SYMB pSymAlias ); -extern ERRCODE hb_rddGetFieldValue( HB_ITEM_PTR pItem, PHB_SYMB pFieldSymbol ); -extern ERRCODE hb_rddPutFieldValue( HB_ITEM_PTR pItem, PHB_SYMB pFieldSymbol ); -extern ERRCODE hb_rddFieldGet( HB_ITEM_PTR pItem, PHB_SYMB pFieldSymbol ); -extern ERRCODE hb_rddFieldPut( HB_ITEM_PTR pItem, PHB_SYMB pFieldSymbol ); -extern void hb_rddShutDown( void ); +extern HB_EXPORT USHORT hb_rddInsertAreaNode( char *szDriver ); +extern HB_EXPORT USHORT hb_rddGetCurrentFieldPos( char * szName ); +extern HB_EXPORT void * hb_rddAllocWorkAreaAlias( char * szAlias, int iArea ); +extern HB_EXPORT int hb_rddGetCurrentWorkAreaNumber( void ); +extern HB_EXPORT void * hb_rddGetCurrentWorkAreaPointer( void ); +extern HB_EXPORT ERRCODE hb_rddSelectWorkAreaAlias( char * szAlias ); +extern HB_EXPORT ERRCODE hb_rddSelectWorkAreaNumber( int iArea ); +extern HB_EXPORT ERRCODE hb_rddSelectWorkAreaSymbol( PHB_SYMB pSymAlias ); +extern HB_EXPORT ERRCODE hb_rddGetFieldValue( HB_ITEM_PTR pItem, PHB_SYMB pFieldSymbol ); +extern HB_EXPORT ERRCODE hb_rddPutFieldValue( HB_ITEM_PTR pItem, PHB_SYMB pFieldSymbol ); +extern HB_EXPORT ERRCODE hb_rddFieldGet( HB_ITEM_PTR pItem, PHB_SYMB pFieldSymbol ); +extern HB_EXPORT ERRCODE hb_rddFieldPut( HB_ITEM_PTR pItem, PHB_SYMB pFieldSymbol ); +extern HB_EXPORT void hb_rddShutDown( void ); +extern HB_EXPORT void hb_rddReleaseCurrentArea( void ); @@ -169,6 +178,7 @@ typedef struct BOOL fShared; /* Share mode of the data store */ BOOL fReadonly; /* Readonly mode of the data store */ BYTE * cdpId; /* Id of a codepage */ + ULONG ulConnection; /* connection handler for RDDs which support it */ void * lpdbHeader; /* Pointer to a header of the data store */ } DBOPENINFO; @@ -191,16 +201,21 @@ typedef struct _DBORDERCONDINFO PHB_ITEM itmCobWhile; PHB_ITEM itmCobEval; LONG lStep; - LONG lStartRecno; + PHB_ITEM itmStartRecID; LONG lNextCount; - LONG lRecno; + PHB_ITEM itmRecID; BOOL fRest; BOOL fDescending; + BOOL fScoped; BOOL fAll; BOOL fAdditive; BOOL fUseCurrent; BOOL fCustom; BOOL fNoOptimize; + BOOL fCompound; + BOOL fUseFilter; + BOOL fTemporary; + BOOL fExclusive; void * lpvCargo; } DBORDERCONDINFO; @@ -262,18 +277,19 @@ typedef struct PHB_ITEM itmCobWhile; /* Code Block representation of a WHILE clause */ PHB_ITEM lpstrWhile; /* String representation of a WHILE clause */ PHB_ITEM lNext; /* NEXT record */ - PHB_ITEM itmRecID; + PHB_ITEM itmRecID; /* single record ID */ PHB_ITEM fRest; /* TRUE if start from the current record */ - BOOL fIgnoreFilter; - BOOL fIncludeDeleted; - BOOL fLast; - BOOL fIgnoreDuplicates; + BOOL fIgnoreFilter; /* process should ignore any filter condition */ + BOOL fIncludeDeleted; /* process should include deleted records */ + BOOL fLast; /* last record of the current scope required */ + BOOL fIgnoreDuplicates; /* process should ignore duplicate key value */ + BOOL fBackword; /* skip backword */ + BOOL fOptimized; /* Is (should be) scope optimized */ } DBSCOPEINFO; typedef DBSCOPEINFO * LPDBSCOPEINFO; - /* * DBORDSCOPEINFO * -------------- @@ -289,7 +305,6 @@ typedef struct typedef DBORDSCOPEINFO * LPDBORDSCOPEINFO; - /* * DBFILTERINFO * ------------ @@ -300,7 +315,9 @@ typedef struct { PHB_ITEM itmCobExpr; /* Block representation of the FILTER expression */ PHB_ITEM abFilterText; /* String representation of FILTER expression */ - BOOL fFilter; + BOOL fFilter; /* flag to indicate that filter is active */ + BOOL fOptimized; /* Is (should be) filter optimized */ + void * lpvCargo; /* RDD specific extended filter info */ } DBFILTERINFO; typedef DBFILTERINFO * LPDBFILTERINFO; @@ -318,6 +335,7 @@ typedef struct _DBRELINFO PHB_ITEM itmCobExpr; /* Block representation of the relational SEEK key */ PHB_ITEM abKey; /* String representation of the relational SEEK key */ BOOL isScoped; /* Is this relation scoped */ + BOOL isOptimized; /* Is relation optimized */ struct _AREA * lpaParent; /* The parent of this relation */ struct _AREA * lpaChild; /* The parents children */ struct _DBRELINFO * lpdbriNext; /* Next child or parent */ @@ -338,12 +356,17 @@ typedef DBRELINFO * LPDBRELINFO; typedef struct { - PHB_ITEM itmBlock; /* The block to be evaluated */ - DBSCOPEINFO dbsci; /* Scope info that limits the evaluation */ + PHB_ITEM itmBlock; /* The block to be evaluated */ + PHB_ITEM abBlock; /* String representation of evaluated block */ + DBSCOPEINFO dbsci; /* Scope info that limits the evaluation */ } DBEVALINFO; typedef DBEVALINFO * LPDBEVALINFO; +/* + * NOTE: If your redefine EVAL() method then you may use itmBlock as + * string ITEM to make some operations on server side of remote RDD. + */ /* @@ -476,6 +499,11 @@ typedef struct _FIELD typedef FIELD * LPFIELD; +/* + * prototype for function to evaluate against index keys + * only for local RDDs (DBFNTX, DBFCDX, ...) + */ +typedef void ( * HB_EVALSCOPE_FUNC )( ULONG, BYTE *, ULONG, void * ); /*--------------------* WORKAREA structure *----------------------*/ @@ -491,6 +519,10 @@ typedef FIELD * LPFIELD; typedef struct _AREA { struct _RDDFUNCS * lprfsHost; /* Virtual method table for this workarea */ +#if 0 + /* I'll add this soon, Druzus */ + struct _RDDFUNCS * lprfsSuper;/* Virtual super method table for this workarea */ +#endif USHORT uiArea; /* The number assigned to this workarea */ void * atomAlias; /* Pointer to the alias symbol for this workarea */ USHORT uiFieldExtent; /* Total number of fields allocated */ @@ -551,7 +583,7 @@ typedef USHORT ( * DBENTRYP_S )( AREAP area, USHORT param ); typedef USHORT ( * DBENTRYP_LP )( AREAP area, LONG * param ); typedef USHORT ( * DBENTRYP_ULP )( AREAP area, ULONG * param ); typedef USHORT ( * DBENTRYP_SVP )( AREAP area, USHORT index, void * param ); -typedef USHORT ( * DBENTRYP_SVPB )( AREAP area, USHORT index, void * param, BOOL p3 ); +typedef USHORT ( * DBENTRYP_SVPB )( AREAP area, USHORT index, void * param, USHORT p3 ); typedef USHORT ( * DBENTRYP_VSP )( AREAP area, USHORT action, ULONG lRecord ); typedef USHORT ( * DBENTRYP_SVL )( AREAP area, USHORT index, ULONG * param ); typedef USHORT ( * DBENTRYP_SSI )( AREAP area, USHORT p1, USHORT p2, PHB_ITEM p3 ); @@ -559,13 +591,13 @@ typedef USHORT ( * DBENTRYP_ISI )( AREAP area, PHB_ITEM p1, USHORT p2, PHB_ITEM typedef USHORT ( * DBENTRYP_BIB )( AREAP area, BOOL p1, PHB_ITEM p2, BOOL p3 ); typedef USHORT ( * DBENTRYP_VPL )( AREAP area, void * p1, LONG p2 ); typedef USHORT ( * DBENTRYP_VPLP )( AREAP area, void * p1, LONG * p2 ); -typedef USHORT ( * DBENTRYP_LSP )( AREAP area, LONG p1, USHORT * p2 ); +typedef USHORT ( * DBENTRYP_LSP )( AREAP area, LONG p1, BOOL * p2 ); /* this methods DO USE take a Workarea but an RDDNODE */ -typedef USHORT ( * DBENTRYP_I0 )( void ); -typedef USHORT ( * DBENTRYP_I1 )( PHB_ITEM p1 ); -typedef USHORT ( * DBENTRYP_I2 )( PHB_ITEM p1, PHB_ITEM p2 ); +typedef USHORT ( * DBENTRYP_R )( struct _RDDNODE * pRDD ); +typedef USHORT ( * DBENTRYP_RVV )( struct _RDDNODE * pRDD, PHB_ITEM p1, PHB_ITEM p2 ); +typedef USHORT ( * DBENTRYP_RSLV )( struct _RDDNODE * pRDD, USHORT index, ULONG p1, PHB_ITEM p2 ); /*--------------------* Virtual Method Table *----------------------*/ typedef struct _RDDFUNCS @@ -607,7 +639,8 @@ typedef struct _RDDFUNCS DBENTRYP_V recall; /* Undelete the current record. */ DBENTRYP_ULP reccount; /* Obtain number of records in WorkArea. */ DBENTRYP_ISI recInfo; /* */ - DBENTRYP_I recno; /* Obtain physical row number at current WorkArea cursor position. */ + DBENTRYP_ULP recno; /* Obtain physical row number at current WorkArea cursor position. */ + DBENTRYP_I recid; /* Obtain physical row ID at current WorkArea cursor position. */ DBENTRYP_S setFieldExtent; /* Establish the extent of the array of fields for a WorkArea. */ @@ -649,7 +682,7 @@ typedef struct _RDDFUNCS DBENTRYP_OI orderListAdd; /* */ DBENTRYP_V orderListClear; /* */ - DBENTRYP_VP orderListDelete; /* */ + DBENTRYP_OI orderListDelete; /* */ DBENTRYP_OI orderListFocus; /* */ DBENTRYP_V orderListRebuild; /* */ DBENTRYP_VOI orderCondition; /* */ @@ -670,6 +703,7 @@ typedef struct _RDDFUNCS DBENTRYP_VLO setLocate; /*-Set the locate scope for the specified WorkArea. */ DBENTRYP_VOS setScope; /* */ DBENTRYP_VPL skipScope; /* */ + DBENTRYP_B locate; /* reposition cursor to postions set by setLocate */ /* Miscellaneous */ @@ -683,7 +717,7 @@ typedef struct _RDDFUNCS DBENTRYP_VSP rawlock; /* Perform a lowlevel network lock in the specified WorkArea. */ DBENTRYP_VL lock; /* Perform a network lock in the specified WorkArea. */ - DBENTRYP_UL unlock; /* Release network locks in the specified WorkArea. */ + DBENTRYP_I unlock; /* Release network locks in the specified WorkArea. */ /* Memofile functions */ @@ -692,7 +726,7 @@ typedef struct _RDDFUNCS DBENTRYP_VP createMemFile; /* Create a memo file in the WorkArea. */ DBENTRYP_SVPB getValueFile; /* */ DBENTRYP_VP openMemFile; /* Open a memo file in the specified WorkArea. */ - DBENTRYP_SVP putValueFile; /* */ + DBENTRYP_SVPB putValueFile; /* */ /* Database file header handling */ @@ -702,9 +736,11 @@ typedef struct _RDDFUNCS /* non WorkArea functions */ - DBENTRYP_I0 exit; /* */ - DBENTRYP_I1 drop; /* remove table */ - DBENTRYP_I2 exists; /* check if table exist */ + DBENTRYP_R init; /* init RDD after registration */ + DBENTRYP_R exit; /* unregister RDD */ + DBENTRYP_RVV drop; /* remove table */ + DBENTRYP_RVV exists; /* check if table exist */ + DBENTRYP_RSLV rddInfo; /* RDD info */ /* Special and reserved methods */ @@ -720,11 +756,13 @@ typedef RDDFUNCS * PRDDFUNCS; typedef struct _RDDNODE { char szName[ HARBOUR_MAX_RDD_DRIVERNAME_LENGTH + 1 ]; /* Name of RDD */ - USHORT uiType; /* Type of RDD */ - RDDFUNCS pTable; /* Table of functions */ - RDDFUNCS pSuperTable; /* Table of super functions */ - USHORT uiAreaSize; /* Size of the WorkArea */ - struct _RDDNODE * pNext; /* Next RDD in the list */ + USHORT uiType; /* Type of RDD */ + USHORT rddID; /* Type of RDD */ + RDDFUNCS pTable; /* Table of functions */ + RDDFUNCS pSuperTable; /* Table of super functions */ + USHORT uiAreaSize; /* Size of the WorkArea */ + void *lpvCargo; /* RDD specific extended data, if used then + RDD should free it in EXIT() non WA method */ } RDDNODE; typedef RDDNODE * LPRDDNODE; @@ -750,7 +788,7 @@ typedef RDDNODE * LPRDDNODE; /* Data management */ #define SELF_ADDFIELD(w, ip) ((*(w)->lprfsHost->addField)(w, ip)) -#define SELF_APPEND(w,l) ((*(w)->lprfsHost->append)(w,l)) +#define SELF_APPEND(w, b) ((*(w)->lprfsHost->append)(w, b)) #define SELF_CREATEFIELDS(w, v) ((*(w)->lprfsHost->createFields)(w, v)) #define SELF_DELETE(w) ((*(w)->lprfsHost->deleterec)(w)) #define SELF_DELETED(w, sp) ((*(w)->lprfsHost->deleted)(w, sp)) @@ -767,9 +805,10 @@ typedef RDDNODE * LPRDDNODE; #define SELF_PUTVALUE(w, i, v) ((*(w)->lprfsHost->putValue)(w, i, v)) #define SELF_PUTREC(w, bp) ((*(w)->lprfsHost->putRec)(w, bp)) #define SELF_RECALL(w) ((*(w)->lprfsHost->recall)(w)) -#define SELF_RECCOUNT(w, sp) ((*(w)->lprfsHost->reccount)(w, sp)) +#define SELF_RECCOUNT(w, lp) ((*(w)->lprfsHost->reccount)(w, lp)) #define SELF_RECINFO(w,v1,i,v2) ((*(w)->lprfsHost->recInfo)(w,v1,i,v2)) -#define SELF_RECNO(w, i) ((*(w)->lprfsHost->recno)(w, i)) +#define SELF_RECNO(w, lp) ((*(w)->lprfsHost->recno)(w, lp)) +#define SELF_RECID(w, i) ((*(w)->lprfsHost->recid)(w, i)) #define SELF_SETFIELDEXTENT(w, s) ((*(w)->lprfsHost->setFieldExtent)(w, s)) @@ -840,6 +879,7 @@ typedef RDDNODE * LPRDDNODE; #define SELF_SETLOCATE(w, ip) ((*(w)->lprfsHost->setLocate)(w, ip)) #define SELF_SETSCOPE(w, ip) ((*(w)->lprfsHost->setScope)(w, ip)) #define SELF_SKIPSCOPE(w, bp, l) ((*(w)->lprfsHost->skipScope)(w, bp, l)) +#define SELF_LOCATE(w, b) ((*(w)->lprfsHost->locate)(w, b)) /* Miscellaneous */ @@ -854,16 +894,16 @@ typedef RDDNODE * LPRDDNODE; #define SELF_GETLOCKS(w, g) ((*(w)->lprfsHost->info)(w, DBI_GETLOCKARRAY, g)) #define SELF_RAWLOCK(w, i, l) ((*(w)->lprfsHost->rawlock)(w, i, l)) #define SELF_LOCK(w, sp) ((*(w)->lprfsHost->lock)(w, sp)) -#define SELF_UNLOCK(w, l) ((*(w)->lprfsHost->unlock)(w, l)) +#define SELF_UNLOCK(w, i) ((*(w)->lprfsHost->unlock)(w, i)) /* Memofile functions */ #define SELF_CLOSEMEMFILE(w) ((*(w)->lprfsHost->closeMemFile)(w)) #define SELF_CREATEMEMFILE(w,bp) ((*(w)->lprfsHost->createMemFile)(w,bp)) -#define SELF_GETVALUEFILE(w,i,bp,b) ((*(w)->lprfsHost->getValueFile)(w,i,bp,b)) +#define SELF_GETVALUEFILE(w,i,bp,u) ((*(w)->lprfsHost->getValueFile)(w,i,bp,u)) #define SELF_OPENMEMFILE(w,bp) ((*(w)->lprfsHost->openMemFile)(w,bp)) -#define SELF_PUTVALUEFILE(w,i,bp) ((*(w)->lprfsHost->putValueFile)(w,i,bp)) +#define SELF_PUTVALUEFILE(w,i,bp,u) ((*(w)->lprfsHost->putValueFile)(w,i,bp,u)) /* Database file header handling */ @@ -881,11 +921,14 @@ typedef RDDNODE * LPRDDNODE; #define SELF_GETDELIM(w, fp) ((*(w)->lprfsHost->info)(w, DBI_GETDELIMITER, fp)) #define SELF_TABLEEXT(w, fp) ((*(w)->lprfsHost->info)(w, DBI_TABLEEXT, fp)) +#define SELF_RDDNODE(w) hb_rddGetNode((w)->rddID) /* non WorkArea functions */ -#define SELF_EXIT(r) ((*(r)->pTable.exit)()) -#define SELF_DROP(r, i) ((*(r)->pTable.drop)(i)) -#define SELF_EXISTS(r, it, ii) ((*(r)->pTable.exists)(it,ii)) +#define SELF_INIT(r) ((*(r)->pTable.init)(r)) +#define SELF_EXIT(r) ((*(r)->pTable.exit)(r)) +#define SELF_DROP(r, it, ii) ((*(r)->pTable.drop)(r, it, ii)) +#define SELF_EXISTS(r, it, ii) ((*(r)->pTable.exists)(r, it, ii)) +#define SELF_RDDINFO(r, i, l, g) ((*(r)->pTable.rddInfo)(r, i, l, g)) /*--------------------* SUPER Methods *------------------------*/ @@ -909,7 +952,7 @@ typedef RDDNODE * LPRDDNODE; /* Data management */ #define SUPER_ADDFIELD(w, ip) ((*(SUPERTABLE)->addField)(w, ip)) -#define SUPER_APPEND(w,l) ((*(SUPERTABLE)->append)(w,l)) +#define SUPER_APPEND(w, b) ((*(SUPERTABLE)->append)(w, b)) #define SUPER_CREATEFIELDS(w, v) ((*(SUPERTABLE)->createFields)(w, v)) #define SUPER_DELETE(w) ((*(SUPERTABLE)->deleterec)(w)) #define SUPER_DELETED(w, sp) ((*(SUPERTABLE)->deleted)(w, sp)) @@ -926,9 +969,10 @@ typedef RDDNODE * LPRDDNODE; #define SUPER_PUTVALUE(w, i, v) ((*(SUPERTABLE)->putValue)(w, i, v)) #define SUPER_PUTREC(w, bp) ((*(SUPERTABLE)->putRec)(w, bp)) #define SUPER_RECALL(w) ((*(SUPERTABLE)->recall)(w)) -#define SUPER_RECCOUNT(w, sp) ((*(SUPERTABLE)->reccount)(w, sp)) +#define SUPER_RECCOUNT(w, lp) ((*(SUPERTABLE)->reccount)(w, lp)) #define SUPER_RECINFO(w,v1,i,v2) ((*(SUPERTABLE)->recInfo)(w,v1,i,v2)) -#define SUPER_RECNO(w, sp) ((*(SUPERTABLE)->recno)(w, sp)) +#define SUPER_RECNO(w, lp) ((*(SUPERTABLE)->recno)(w, lp)) +#define SUPER_RECID(w, i) ((*(SUPERTABLE)->recid)(w, i)) #define SUPER_SETFIELDEXTENT(w, s) ((*(SUPERTABLE)->setFieldExtent)(w, s)) @@ -999,6 +1043,7 @@ typedef RDDNODE * LPRDDNODE; #define SUPER_SETLOCATE(w, ip) ((*(SUPERTABLE)->setLocate)(w, ip)) #define SUPER_SETSCOPE(w, ip) ((*(SUPERTABLE)->setScope)(w, ip)) #define SUPER_SKIPSCOPE(w, bp, l) ((*(SUPERTABLE)->skipScope)(w, bp, l)) +#define SUPER_LOCATE(w, b) ((*(SUPERTABLE)->locate)(w, b)) /* Miscellaneous */ @@ -1013,16 +1058,16 @@ typedef RDDNODE * LPRDDNODE; #define SUPER_GETLOCKS(w, g) ((*(SUPERTABLE)->info)(w, DBI_GETLOCKARRAY, g)) #define SUPER_RAWLOCK(w, i, l) ((*(SUPERTABLE)->rawlock)(w, i, l)) #define SUPER_LOCK(w, sp) ((*(SUPERTABLE)->lock)(w, sp)) -#define SUPER_UNLOCK(w,l) ((*(SUPERTABLE)->unlock)(w,l)) +#define SUPER_UNLOCK(w, i) ((*(SUPERTABLE)->unlock)(w, i)) /* Memofile functions */ #define SUPER_CLOSEMEMFILE(w) ((*(SUPERTABLE)->closeMemFile)(w)) #define SUPER_CREATEMEMFILE(w,bp) ((*(SUPERTABLE)->createMemFile)(w,bp)) -#define SUPER_GETVALUEFILE(w,i,bp,b) ((*(SUPERTABLE)->getValueFile)(w,i,bp,b)) +#define SUPER_GETVALUEFILE(w,i,bp,u) ((*(SUPERTABLE)->getValueFile)(w,i,bp,u)) #define SUPER_OPENMEMFILE(w,bp) ((*(SUPERTABLE)->openMemFile)(w,bp)) -#define SUPER_PUTVALUEFILE(w,i,bp) ((*(SUPERTABLE)->putValueFile)(w,i,bp)) +#define SUPER_PUTVALUEFILE(w,i,bp,u) ((*(SUPERTABLE)->putValueFile)(w,i,bp,u)) /* Database file header handling */ @@ -1041,23 +1086,30 @@ typedef RDDNODE * LPRDDNODE; #define SUPER_TABLEEXT(w, fp) ((*(SUPERTABLE)->info)(w, DBI_TABLEEXT, fp)) /* non WorkArea functions */ -#define SUPER_EXIT() ((*(SUPERTABLE)->exit)()) -#define SUPER_DROP(i) ((*(SUPERTABLE)->drop)(i)) -#define SUPER_EXISTS(it, ii) ((*(SUPERTABLE)->exists)(it, ii)) +#define SUPER_INIT(r) ((*(SUPERTABLE)->init)(r)) +#define SUPER_EXIT(r) ((*(SUPERTABLE)->exit)(r)) +#define SUPER_DROP(r, it, ii) ((*(SUPERTABLE)->drop)(r, it, ii)) +#define SUPER_EXISTS(r, it, ii) ((*(SUPERTABLE)->exists)(r, it, ii)) +#define SUPER_RDDINFO(r, i, l, g) ((*(SUPERTABLE)->rddInfo)(r, i, l, g)) + +#define ISSUPER_INIT(r) ((SUPERTABLE)->init != NULL) +#define ISSUPER_EXIT(r) ((SUPERTABLE)->exit != NULL) /* * PROTOTYPES * ---------- */ -extern ERRCODE hb_rddInherit( PRDDFUNCS pTable, PRDDFUNCS pSubTable, PRDDFUNCS pSuperTable, BYTE * szDrvName ); -extern ERRCODE hb_rddDisinherit( BYTE * drvName ); -extern USHORT hb_rddExtendType( USHORT fieldType ); -extern USHORT hb_rddFieldType( USHORT extendType ); +extern ERRCODE HB_EXPORT hb_rddInherit( PRDDFUNCS pTable, PRDDFUNCS pSubTable, PRDDFUNCS pSuperTable, BYTE * szDrvName ); +extern ERRCODE HB_EXPORT hb_rddDisinherit( BYTE * drvName ); +extern USHORT HB_EXPORT hb_rddExtendType( USHORT fieldType ); +extern USHORT HB_EXPORT hb_rddFieldType( USHORT extendType ); +extern LPRDDNODE HB_EXPORT hb_rddGetNode( USHORT uiNode ); typedef short (* WACALLBACK )( AREA *, int ); -extern ERRCODE hb_rddIterateWorkAreas ( WACALLBACK pCallBack, int data ); -USHORT hb_rddFieldIndex( AREAP pArea, char * szName); -ERRCODE hb_rddGetTempAlias( char * szAliasTmp ); +extern ERRCODE HB_EXPORT hb_rddIterateWorkAreas ( WACALLBACK pCallBack, int data ); +extern USHORT HB_EXPORT hb_rddFieldIndex( AREAP pArea, char * szName ); +extern USHORT HB_EXPORT hb_rddFieldExpIndex( AREAP pArea, char * szField ); +extern ERRCODE HB_EXPORT hb_rddGetTempAlias( char * szAliasTmp ); HB_EXTERN_END diff --git a/harbour/include/hbdbf.h b/harbour/include/hbdbf.h index 8afd8fea0a..5c4a5f0b7e 100644 --- a/harbour/include/hbdbf.h +++ b/harbour/include/hbdbf.h @@ -68,10 +68,13 @@ typedef struct _DBFHEADER BYTE ulRecCount[ 4 ]; BYTE uiHeaderLen[ 2 ]; BYTE uiRecordLen[ 2 ]; - BYTE bReserved1[ 16 ]; - BYTE bHasTags; + BYTE bReserved1[ 2 ]; + BYTE bTransaction; /* 1-transaction begin */ + BYTE bEncrypted; /* 1-encryptpted table */ + BYTE bReserved2[ 12 ]; + BYTE bHasTags; /* bit filed: 1-production index, 2-memo file in VFP */ BYTE bCodePage; - BYTE bReserved2[ 2 ]; + BYTE bReserved3[ 2 ]; } DBFHEADER; typedef DBFHEADER * LPDBFHEADER; @@ -84,15 +87,32 @@ typedef struct _DBFFIELD { BYTE bName[ 11 ]; BYTE bType; - BYTE bReserved1[ 4 ]; + BYTE bReserved1[ 4 ]; /* offset from record begin in FP */ BYTE bLen; BYTE bDec; - BYTE bReserved2[ 13 ]; + BYTE bFieldFlags; /* 1-system column, 2-nullable, 4-binary */ + BYTE bCounter[4]; /* autoincrement counter */ + BYTE bStep; /* autoincrement step */ + BYTE bReserved2[ 7 ]; BYTE bHasTag; } DBFFIELD; typedef DBFFIELD * LPDBFFIELD; + + +/* SMT MEMO field */ + +typedef struct _SMTFIELD +{ + BYTE type[2]; + BYTE length[4]; + BYTE block[4]; +} SMTFIELD; + +typedef SMTFIELD * LPSMTFIELD; + + HB_EXTERN_END #endif /* HB_DBF_H_ */ diff --git a/harbour/include/hbdbferr.h b/harbour/include/hbdbferr.h index 0ce7a721a3..4adae80887 100644 --- a/harbour/include/hbdbferr.h +++ b/harbour/include/hbdbferr.h @@ -57,8 +57,12 @@ HB_EXTERN_BEGIN /* DBF errors */ #define EDBF_OPEN_DBF 1001 +#define EDBF_OPEN_MEMO 1002 +#define EDBF_OPEN_INDEX 1003 #define EDBF_CREATE_DBF 1004 -#define EDBF_CREATE 1006 +#define EDBF_CREATE_MEMO 1005 +#define EDBF_CREATE_INDEX 1006 +#define EDBF_CREATE EDBF_CREATE_INDEX #define EDBF_READ 1010 #define EDBF_WRITE 1011 #define EDBF_CORRUPT 1012 @@ -68,9 +72,21 @@ HB_EXTERN_BEGIN #define EDBF_SHARED 1023 #define EDBF_APPENDLOCK 1024 #define EDBF_READONLY 1025 +#define EDBF_LIMITEXCEEDED 1027 +#define EDBF_LOCKTIMEOUT 1035 #define EDBF_LOCK 1038 /* ORDER errors */ #define EDBF_INVALIDKEY 1026 +#define EDBF_NOTINDEXED 1201 +#define EDBF_INVALIDORDER 1050 +#define EDBF_SCOPETYPE 1051 +#define EDBF_NOTCUSTOM 1052 +#define EDBF_INVALIDFOR 1053 +#define EDBF_KEYLENGTH 1054 +#define EDBF_SIGNATURE 1055 + +#define EDBF_MEMOTYPE 1056 +#define EDBF_MEMOTOOLONG 1057 HB_EXTERN_END diff --git a/harbour/include/hbdefs.h b/harbour/include/hbdefs.h index 32877b3501..5fc4bef326 100644 --- a/harbour/include/hbdefs.h +++ b/harbour/include/hbdefs.h @@ -690,6 +690,21 @@ typedef unsigned long HB_COUNTER; (( BYTE * )( p ))[1] = ( BYTE )( (w) >> 8 ); \ (( BYTE * )( p ))[2] = ( BYTE )( (w) >> 16 ); \ } while ( 0 ) +#define HB_GET_BE_INT24( p ) ( ( INT32 ) \ + ( ( INT32 ) (( BYTE * )( p ))[2] | \ + ( INT32 ) (( BYTE * )( p ))[1] << 8 | \ + ( INT32 ) (( BYTE * )( p ))[0] << 16 | \ + ( INT32 ) ((( BYTE * )( p ))[0] & 0x80 ? 0xFF : 0x00 ) << 24 ) ) +#define HB_GET_BE_UINT24( p ) ( ( UINT32 ) \ + ( ( UINT32 ) (( BYTE * )( p ))[2] | \ + ( UINT32 ) (( BYTE * )( p ))[1] << 8 | \ + ( UINT32 ) (( BYTE * )( p ))[0] << 16 ) ) +#define HB_PUT_BE_UINT24( p, w ) do { \ + (( BYTE * )( p ))[2] = ( BYTE )( w ); \ + (( BYTE * )( p ))[1] = ( BYTE )( (w) >> 8 ); \ + (( BYTE * )( p ))[0] = ( BYTE )( (w) >> 16 ); \ + } while ( 0 ) + #if defined( HB_PDP_ENDIAN ) diff --git a/harbour/include/hbrddcdx.h b/harbour/include/hbrddcdx.h index 4bb0e930e9..5639310f77 100644 --- a/harbour/include/hbrddcdx.h +++ b/harbour/include/hbrddcdx.h @@ -67,9 +67,11 @@ HB_EXTERN_BEGIN /* CDX constants and defaults */ #define CDX_INDEXEXT ".cdx" #define CDX_MAXKEY 240 +#define CDX_MAXEXP 255 #define CDX_MAXTAGNAMELEN 10 #define CDX_PAGELEN 512 #define CDX_HEADERLEN 1024 +#define CDX_HEADEREXPLEN (CDX_HEADERLEN - 512) #define CDX_HEADERPAGES ((CDX_HEADERLEN+CDX_PAGELEN-1)/CDX_PAGELEN) #define CDX_INT_FREESPACE (CDX_PAGELEN-12) /* 500 */ #define CDX_EXT_FREESPACE (CDX_PAGELEN-24) /* 488 */ @@ -150,7 +152,39 @@ HB_EXTERN_BEGIN #define CDX_TYPE_COMPOUND 0x40 /* FoxPro */ #define CDX_TYPE_STRUCTURE 0x80 /* FoxPro */ -typedef void ( * HB_EVALSCOPE_FUNC )( ULONG, BYTE *, ULONG, void * ); +/* + TODO like in SIXCDX: + switch ( indexOpt & ( CDX_TYPE_TEMPORARY | CDX_TYPE_CUSTOM ) ) + case CDX_TYPE_TEMPORARY: + PARTIAL_RYO + case CDX_TYPE_CUSTOM: + PARTIAL_RYO | CHGONLY_RYO + case CDX_TYPE_TEMPORARY | CDX_TYPE_CUSTOM: + PARTIAL_RYO | NOUPDATE_RYO + if index key begin with: + 'SXCHAR(' or 'SXNUM(' or 'SXDATE(' or 'SXLOG(' + then + | TEMPLATE_RYO + + sx_chill() if ( ! NOUPDATE_RYO ) then set ( CHGONLY_RYO | PARTIAL_RYO ) + if ( indexOpt & ( CDX_TYPE_TEMPORARY | CDX_TYPE_CUSTOM ) != + CDX_TYPE_TEMPORARY | CDX_TYPE_CUSTOM ) + { + indexOpt &= ~CDX_TYPE_CUSTOM; + indexOpt |= CDX_TYPE_TEMPORARY + } + + sx_warm() if ( ! NOUPDATE_RYO ) then clear CHGONLY_RYO + if ( indexOpt & ( CDX_TYPE_TEMPORARY | CDX_TYPE_CUSTOM ) != + CDX_TYPE_TEMPORARY | CDX_TYPE_CUSTOM ) + { + indexOpt |= CDX_TYPE_CUSTOM; + indexOpt &= ~CDX_TYPE_TEMPORARY + } + + sx_freeze() set NOUPDATE_RYO + indexOpt |= CDX_TYPE_TEMPORARY | CDX_TYPE_CUSTOM; +*/ /* CDX index node strucutres */ /* Compact Index Header Record */ @@ -162,13 +196,14 @@ typedef struct _CDXTAGHEADER BYTE keySize [ 2 ]; /* key length */ BYTE indexOpt; /* index options see CDX_TYPE_* */ BYTE indexSig; /* index signature */ - BYTE reserved2[ 486 ]; + BYTE reserved2[ 484 ]; + BYTE ignoreCase[ 2 ]; /* 1 = ignore case, key converted to upper */ BYTE ascendFlg[ 2 ]; /* 0 = ascending 1 = descending */ BYTE forExpPos[ 2 ]; /* offset of filter expression */ BYTE forExpLen[ 2 ]; /* length of filter expression */ BYTE keyExpPos[ 2 ]; /* offset of key expression */ BYTE keyExpLen[ 2 ]; /* length of key expression */ - BYTE keyExpPool[ CDX_HEADERLEN - 512 ]; + BYTE keyExpPool[ CDX_HEADEREXPLEN ]; } CDXTAGHEADER; typedef CDXTAGHEADER * LPCDXTAGHEADER; @@ -287,6 +322,7 @@ typedef struct _CDXTAG USHORT uiType; /* a type of key expression value */ USHORT uiLen; /* length of the key expression value */ USHORT nField; /* Field number for simple (one field) key expersion */ + BYTE bTrail; /* trailing character for shorter key value */ BYTE OptFlags; /* index options flag */ BOOL AscendKey; /* ascending/descending order flag */ BOOL UniqueKey; /* unique order flag */ @@ -333,27 +369,29 @@ typedef CDXTAG * LPCDXTAG; typedef struct _CDXINDEX { - char * szFileName; /* Name of index file */ - FHANDLE hFile; /* Index file handle */ + char * szFileName; /* Name of index file */ + char * szRealName; /* Real name of index file */ + FHANDLE hFile; /* Index file handle */ struct _CDXAREA * pArea; /* Parent WorkArea */ struct _CDXINDEX * pNext; /* The next index in the list */ - LPCDXTAG pCompound; /* Compound Tag (index of tags) */ - LPCDXTAG TagList; /* List of tags in index file */ - BOOL fShared; /* Shared file */ - BOOL fReadonly; /* Read only file */ - ULONG nextAvail; /* offset to next free page in the end of index file */ - ULONG freePage; /* offset to next free page inside index file */ - LPCDXLIST freeLst; /* list of free pages in index file */ - int lockWrite; /* number of write lock set */ - int lockRead; /* number of read lock set */ - ULONG ulLockPos; /* readlock position for CL53 lock scheme */ + LPCDXTAG pCompound; /* Compound tag */ + LPCDXTAG TagList; /* List of tags in index file */ + BOOL fShared; /* Shared file */ + BOOL fReadonly; /* Read only file */ + BOOL fDelete; /* delete on close flag */ + ULONG nextAvail; /* offset to next free page in the end of index file */ + ULONG freePage; /* offset to next free page inside index file */ + LPCDXLIST freeLst; /* list of free pages in index file */ + int lockWrite; /* number of write lock set */ + int lockRead; /* number of read lock set */ + HB_FOFFSET ulLockPos; /* readlock position for CL53 lock scheme */ #ifdef HB_CDX_DBGCODE - BOOL RdLck; - BOOL WrLck; + BOOL RdLck; + BOOL WrLck; #endif - BOOL fChanged; /* changes written to index, need upadte ulVersion */ - ULONG ulVersion; /* network version/update flag */ - BOOL fFlush; /* changes written to index, need upadte ulVersion */ + BOOL fChanged; /* changes written to index, need upadte ulVersion */ + ULONG ulVersion; /* network version/update flag */ + BOOL fFlush; /* changes written to index, need upadte ulVersion */ } CDXINDEX; typedef CDXINDEX * LPCDXINDEX; @@ -376,6 +414,7 @@ typedef struct int keyLen; /* key length */ BYTE bTrl; /* filler char for shorter keys */ BOOL fUnique; /* TRUE if index is unique */ + BOOL fReindex; /* TRUE if reindexing is in process */ ULONG ulMaxRec; /* the highest record number */ ULONG ulTotKeys; /* total number of keys indexed */ ULONG ulKeys; /* keys in curently created page */ @@ -439,43 +478,47 @@ typedef struct _CDXAREA * example. */ - FHANDLE hDataFile; /* Data file handle */ - FHANDLE hMemoFile; /* Memo file handle */ - USHORT uiHeaderLen; /* Size of header */ - USHORT uiRecordLen; /* Size of record */ - ULONG ulRecCount; /* Total records */ - char * szDataFileName; /* Name of data file */ - char * szMemoFileName; /* Name of memo file */ - USHORT uiMemoBlockSize; /* Size of memo block */ - BYTE bMemoType; /* MEMO type used in DBF memo fields */ - BOOL fHasMemo; /* WorkArea with Memo fields */ - BOOL fHasTags; /* WorkArea with MDX or CDX index */ - BOOL fDataFlush; /* data was written to DBF and not commited */ - BOOL fMemoFlush; /* data was written to MEMO and not commited */ - BYTE bVersion; /* DBF version ID byte */ - BYTE bCodePage; /* DBF codepage ID */ - BOOL fShared; /* Shared file */ - BOOL fReadonly; /* Read only file */ - USHORT * pFieldOffset; /* Pointer to field offset array */ - BYTE * pRecord; /* Buffer of record data */ - BOOL fValidBuffer; /* State of buffer */ - BOOL fPositioned; /* Positioned record */ - ULONG ulRecNo; /* Current record */ - BOOL fRecordChanged; /* Record changed */ - BOOL fAppend; /* TRUE if new record is added */ - BOOL fDeleted; /* TRUE if record is deleted */ - BOOL fUpdateHeader; /* Update header of file */ - BOOL fFLocked; /* TRUE if file is locked */ - BOOL fHeaderLocked; /* TRUE if DBF header is locked */ - LPDBRELINFO lpdbPendingRel; /* Pointer to parent rel struct */ - BYTE bYear; /* Last update */ - BYTE bMonth; - BYTE bDay; - BYTE bLockType; /* Type of locking shemes */ - ULONG * pLocksPos; /* List of records locked */ - ULONG ulNumLocksPos; /* Number of records locked */ + FHANDLE hDataFile; /* Data file handle */ + FHANDLE hMemoFile; /* Memo file handle */ + char * szDataFileName; /* Name of data file */ + char * szMemoFileName; /* Name of memo file */ + USHORT uiHeaderLen; /* Size of header */ + USHORT uiRecordLen; /* Size of record */ + USHORT uiMemoBlockSize; /* Size of memo block */ + USHORT uiMemoVersion; /* MEMO file version */ + DBFHEADER dbfHeader; /* DBF header buffer */ + 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 */ + USHORT * pFieldOffset; /* Pointer to field offset array */ + BYTE * pRecord; /* Buffer of record data */ + ULONG ulRecCount; /* Total records */ + ULONG ulRecNo; /* Current record */ + BOOL fAutoInc; /* WorkArea with auto increment fields */ + BOOL fHasMemo; /* WorkArea with Memo fields */ + BOOL fHasTags; /* WorkArea with MDX or CDX index */ + BOOL fDataFlush; /* data was written to DBF and not commited */ + BOOL fMemoFlush; /* data was written to MEMO and not commited */ + BOOL fShared; /* Shared file */ + BOOL fReadonly; /* Read only file */ + BOOL fValidBuffer; /* State of buffer */ + BOOL fPositioned; /* Positioned record */ + BOOL fRecordChanged; /* Record changed */ + BOOL fAppend; /* TRUE if new record is added */ + BOOL fDeleted; /* TRUE if record is deleted */ + BOOL fEncrypted; /* TRUE if record is encrypted */ + BOOL fTableEncrypted; /* TRUE if table is encrypted */ + BOOL fUpdateHeader; /* Update header of file */ + BOOL fFLocked; /* TRUE if file is locked */ + BOOL fHeaderLocked; /* TRUE if DBF header is locked */ + LPDBRELINFO lpdbPendingRel; /* Pointer to parent rel struct */ + ULONG * pLocksPos; /* List of records locked */ + ULONG ulNumLocksPos; /* Number of records locked */ + BYTE * pCryptKey; /* Pointer to encryption key */ + PHB_DYNS pTriggerSym; /* DynSym pointer to trigger function */ #ifndef HB_CDP_SUPPORT_OFF - PHB_CODEPAGE cdPage; /* Area's codepage pointer */ + PHB_CODEPAGE cdPage; /* Area's codepage pointer */ #endif /* @@ -489,8 +532,8 @@ typedef struct _CDXAREA BOOL fCdxAppend; /* Appended record changed */ LPCDXINDEX lpIndexes; /* Pointer to indexes array */ USHORT uiTag; /* current tag focus */ + LPCDXSORTINFO pSort; /* Index build structure */ BYTE * bCdxSortTab; /* Table with storted characters */ - LPCDXSORTINFO pSort; /* Index build structur */ } CDXAREA; @@ -539,6 +582,7 @@ static ERRCODE hb_cdxGoHot( CDXAREAP pArea ); #define hb_cdxRecCount NULL #define hb_cdxRecInfo NULL #define hb_cdxRecNo NULL +#define hb_cdxRecId NULL #define hb_cdxSetFieldExtent NULL #define hb_cdxAlias NULL static ERRCODE hb_cdxClose( CDXAREAP pArea ); @@ -577,14 +621,15 @@ static ERRCODE hb_cdxOrderDestroy( CDXAREAP pArea, LPDBORDERINFO pOrderInfo ); static ERRCODE hb_cdxOrderInfo( CDXAREAP pArea, USHORT uiIndex, LPDBORDERINFO pOrderInfo ); static ERRCODE hb_cdxClearFilter( CDXAREAP pArea ); #define hb_cdxClearLocate NULL -static ERRCODE hb_cdxClearScope( CDXAREAP pArea ); +#define hb_cdxClearScope NULL static ERRCODE hb_cdxCountScope( CDXAREAP pArea, void * pPtr, LONG * plRec ); #define hb_cdxFilterText NULL -static ERRCODE hb_cdxScopeInfo( CDXAREAP pArea, USHORT nScope, PHB_ITEM pItem ); +#define hb_cdxScopeInfo NULL static ERRCODE hb_cdxSetFilter( CDXAREAP pArea, LPDBFILTERINFO pFilterInfo ); #define hb_cdxSetLocate NULL -static ERRCODE hb_cdxSetScope( CDXAREAP pArea, LPDBORDSCOPEINFO sInfo ); +#define hb_cdxSetScope NULL #define hb_cdxSkipScope NULL +#define hb_cdxLocate NULL #define hb_cdxCompile NULL #define hb_cdxError NULL #define hb_cdxEvalBlock NULL @@ -598,9 +643,11 @@ static ERRCODE hb_cdxSetScope( CDXAREAP pArea, LPDBORDSCOPEINFO sInfo ); #define hb_cdxPutValueFile NULL #define hb_cdxReadDBHeader NULL #define hb_cdxWriteDBHeader NULL +#define hb_cdxInit NULL #define hb_cdxExit NULL #define hb_cdxDrop NULL #define hb_cdxExists NULL +static ERRCODE hb_cdxRddInfo( LPRDDNODE pRDD, USHORT uiIndex, ULONG ulConnect, PHB_ITEM pItem ); #define hb_cdxWhoCares NULL HB_EXTERN_END diff --git a/harbour/include/hbrdddbf.h b/harbour/include/hbrdddbf.h index 3321101dc8..2d87990682 100644 --- a/harbour/include/hbrdddbf.h +++ b/harbour/include/hbrdddbf.h @@ -56,6 +56,7 @@ #include "hbsetup.h" #include "hbapirdd.h" #include "hbdbferr.h" +#include "hbdbf.h" #ifndef HB_CDP_SUPPORT_OFF #include "hbapicdp.h" #endif @@ -64,39 +65,68 @@ HB_EXTERN_BEGIN /* DBF default file extensions */ #define DBF_TABLEEXT ".dbf" + /* DBF locking schemes */ -#define DBF_LOCKPOS_CLIP 1000000000L -#define DBF_LOCKPOS_CL53 1000000000L -#define DBF_LOCKPOS_VFP 0x40000000L -#define DBF_LOCKPOS_VFPX 0x7ffffffeL +#define DBF_LOCKPOS_CLIP 1000000000UL +#define DBF_LOCKPOS_CL53 1000000000UL +#define DBF_LOCKPOS_VFP 0x40000000UL +#define DBF_LOCKPOS_VFPX 0x7ffffffeUL +#define DBF_LOCKPOS_CL53EXT 4000000000UL +#define DBF_LOCKPOS_XHB64 HB_LL( 0x7FFFFFFF00000001 ) #define DBF_LOCKDIR_CLIP 1 #define DBF_LOCKDIR_CL53 1 #define DBF_LOCKDIR_VFP 2 /* lock forward at at record offset */ #define DBF_LOCKDIR_VFPX -1 +#define DBF_LOCKDIR_CL53EXT 1 +#define DBF_LOCKDIR_XHB64 1 -#define DBF_FLCKSIZE_CLIP 1000000000L -#define DBF_FLCKSIZE_CL53 1000000000L -#define DBF_FLCKSIZE_VFP 0x3ffffffdL -#define DBF_FLCKSIZE_VFPX 0x07ffffffL +#define DBF_FLCKSIZE_CLIP 1000000000UL +#define DBF_FLCKSIZE_CL53 1000000000UL +#define DBF_FLCKSIZE_VFP 0x3ffffffdUL +#define DBF_FLCKSIZE_VFPX 0x07ffffffUL +#define DBF_FLCKSIZE_CL53EXT 294967295UL +#define DBF_FLCKSIZE_XHB64 0x7ffffffeUL -#define DBF_RLCKSIZE_CLIP 1L -#define DBF_RLCKSIZE_CL53 1L -#define DBF_RLCKSIZE_VFP 1L -#define DBF_RLCKSIZE_VFPX 1L +#define DBF_RLCKSIZE_CLIP 1UL +#define DBF_RLCKSIZE_CL53 1UL +#define DBF_RLCKSIZE_VFP 1UL +#define DBF_RLCKSIZE_VFPX 1UL +#define DBF_RLCKSIZE_CL53EXT 1UL +#define DBF_RLCKSIZE_XHB64 1UL -#define IDX_LOCKPOS_CLIP 1000000000L -#define IDX_LOCKPOS_CL53 0xfffeffffL -#define IDX_LOCKPOS_VFP 0x7ffffffeL +#define IDX_LOCKPOS_CLIP 1000000000UL +#define IDX_LOCKPOS_CL53 0xfffeffffUL +#define IDX_LOCKPOS_VFP 0x7ffffffeUL +#define IDX_LOCKPOS_CL53EXT 0xfffeffffUL +#define IDX_LOCKPOS_XHB64 HB_LL( 0x7FFFFFFF00000001 ) + +#define IDX_LOCKPOOL_CLIP 0UL +#define IDX_LOCKPOOL_CL53 0x00010000UL +#define IDX_LOCKPOOL_VFP 0UL +#define IDX_LOCKPOOL_CL53EXT 0x00010000UL +#define IDX_LOCKPOOL_XHB64 0UL + +/* + * Private DBF* RDD data kept in RDDNODE + */ +typedef struct _DBFDATA +{ + char szTableExt[ HB_MAX_FILE_EXT + 1 ]; + char szIndexExt[ HB_MAX_FILE_EXT + 1 ]; + char szMemoExt[ HB_MAX_FILE_EXT + 1 ]; + + BYTE bLockType; //= 0; + BYTE bTableType; //= DB_DBF_STD; + BYTE bCryptType; //= DB_CRYPT_NONE; + BYTE bMemoType; // = DB_MEMO_FPT; + BYTE bMemoExtType;// = DB_MEMOVER_FLEX; + USHORT uiMemoBlockSize; // = 0; +} DBFDATA; + +typedef DBFDATA * LPDBFDATA; -#define IDX_LOCKPOOL_CLIP 0L -#define IDX_LOCKPOOL_CL53 0x00010000L -#define IDX_LOCKPOOL_VFP 0L -#ifdef OS_UNIX_COMPATIBLE -#define DBF_EXLUSIVE_LOCKPOS 0x7fffffffL -#define DBF_EXLUSIVE_LOCKSIZE 1L -#endif /* * DBF WORKAREA @@ -138,43 +168,47 @@ typedef struct _DBFAREA * example. */ - FHANDLE hDataFile; /* Data file handle */ - FHANDLE hMemoFile; /* Memo file handle */ - USHORT uiHeaderLen; /* Size of header */ - USHORT uiRecordLen; /* Size of record */ - ULONG ulRecCount; /* Total records */ - char * szDataFileName; /* Name of data file */ - char * szMemoFileName; /* Name of memo file */ - USHORT uiMemoBlockSize; /* Size of memo block */ - BYTE bMemoType; /* MEMO type used in DBF memo fields */ - BOOL fHasMemo; /* WorkArea with Memo fields */ - BOOL fHasTags; /* WorkArea with MDX or CDX index */ - BOOL fDataFlush; /* data was written to DBF and not commited */ - BOOL fMemoFlush; /* data was written to MEMO and not commited */ - BYTE bVersion; /* DBF version ID byte */ - BYTE bCodePage; /* DBF codepage ID */ - BOOL fShared; /* Shared file */ - BOOL fReadonly; /* Read only file */ - USHORT * pFieldOffset; /* Pointer to field offset array */ - BYTE * pRecord; /* Buffer of record data */ - BOOL fValidBuffer; /* State of buffer */ - BOOL fPositioned; /* Positioned record */ - ULONG ulRecNo; /* Current record */ - BOOL fRecordChanged; /* Record changed */ - BOOL fAppend; /* TRUE if new record is added */ - BOOL fDeleted; /* TRUE if record is deleted */ - BOOL fUpdateHeader; /* Update header of file */ - BOOL fFLocked; /* TRUE if file is locked */ - BOOL fHeaderLocked; /* TRUE if DBF header is locked */ - LPDBRELINFO lpdbPendingRel; /* Pointer to parent rel struct */ - BYTE bYear; /* Last update */ - BYTE bMonth; - BYTE bDay; - BYTE bLockType; /* Type of locking shemes */ - ULONG * pLocksPos; /* List of records locked */ - ULONG ulNumLocksPos; /* Number of records locked */ + FHANDLE hDataFile; /* Data file handle */ + FHANDLE hMemoFile; /* Memo file handle */ + char * szDataFileName; /* Name of data file */ + char * szMemoFileName; /* Name of memo file */ + USHORT uiHeaderLen; /* Size of header */ + USHORT uiRecordLen; /* Size of record */ + USHORT uiMemoBlockSize; /* Size of memo block */ + USHORT uiMemoVersion; /* MEMO file version */ + DBFHEADER dbfHeader; /* DBF header buffer */ + 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 */ + USHORT * pFieldOffset; /* Pointer to field offset array */ + BYTE * pRecord; /* Buffer of record data */ + ULONG ulRecCount; /* Total records */ + ULONG ulRecNo; /* Current record */ + BOOL fAutoInc; /* WorkArea with auto increment fields */ + BOOL fHasMemo; /* WorkArea with Memo fields */ + BOOL fHasTags; /* WorkArea with MDX or CDX index */ + BOOL fDataFlush; /* data was written to DBF and not commited */ + BOOL fMemoFlush; /* data was written to MEMO and not commited */ + BOOL fShared; /* Shared file */ + BOOL fReadonly; /* Read only file */ + BOOL fValidBuffer; /* State of buffer */ + BOOL fPositioned; /* Positioned record */ + BOOL fRecordChanged; /* Record changed */ + BOOL fAppend; /* TRUE if new record is added */ + BOOL fDeleted; /* TRUE if record is deleted */ + BOOL fEncrypted; /* TRUE if record is encrypted */ + BOOL fTableEncrypted; /* TRUE if table is encrypted */ + BOOL fUpdateHeader; /* Update header of file */ + BOOL fFLocked; /* TRUE if file is locked */ + BOOL fHeaderLocked; /* TRUE if DBF header is locked */ + LPDBRELINFO lpdbPendingRel; /* Pointer to parent rel struct */ + ULONG * pLocksPos; /* List of records locked */ + ULONG ulNumLocksPos; /* Number of records locked */ + BYTE * pCryptKey; /* Pointer to encryption key */ + PHB_DYNS pTriggerSym; /* DynSym pointer to trigger function */ #ifndef HB_CDP_SUPPORT_OFF - PHB_CODEPAGE cdPage; /* Area's codepage pointer */ + PHB_CODEPAGE cdPage; /* Area's codepage pointer */ #endif } DBFAREA; @@ -223,7 +257,8 @@ static ERRCODE hb_dbfPutValue( DBFAREAP pArea, USHORT uiIndex, PHB_ITEM pItem ); static ERRCODE hb_dbfRecall( DBFAREAP pArea ); static ERRCODE hb_dbfRecCount( DBFAREAP pArea, ULONG * pRecCount ); static ERRCODE hb_dbfRecInfo( DBFAREAP pArea, PHB_ITEM pRecID, USHORT uiInfoType, PHB_ITEM pInfo ); -static ERRCODE hb_dbfRecNo( DBFAREAP pArea, PHB_ITEM pRecNo ); +static ERRCODE hb_dbfRecNo( DBFAREAP pArea, ULONG * pRecNo ); +static ERRCODE hb_dbfRecId( DBFAREAP pArea, PHB_ITEM pRecNo ); static ERRCODE hb_dbfSetFieldExtent( DBFAREAP pArea, USHORT uiFieldExtent ); #define hb_dbfAlias NULL static ERRCODE hb_dbfClose( DBFAREAP pArea ); @@ -236,10 +271,10 @@ static ERRCODE hb_dbfStructSize( DBFAREAP pArea, USHORT * uiSize ); static ERRCODE hb_dbfSysName( DBFAREAP pArea, BYTE * pBuffer ); #define hb_dbfEval NULL static ERRCODE hb_dbfPack( DBFAREAP pArea ); -#define hb_dbfPackRec NULL +static ERRCODE hb_dbfPackRec( DBFAREAP pArea, ULONG ulRecNo, BOOL *fWritten ); static ERRCODE hb_dbfSort( DBFAREAP pArea, LPDBSORTINFO pSortInfo ); static ERRCODE hb_dbfTrans( DBFAREAP pArea, LPDBTRANSINFO pTransInfo ); -static ERRCODE hb_dbfTransRec( DBFAREAP pArea, LPDBTRANSINFO pTransInfo ); +#define hb_dbfTransRec NULL static ERRCODE hb_dbfZap( DBFAREAP pArea ); static ERRCODE hb_dbfChildEnd( DBFAREAP pArea, LPDBRELINFO pRelInfo ); static ERRCODE hb_dbfChildStart( DBFAREAP pArea, LPDBRELINFO pRelInfo ); @@ -270,33 +305,44 @@ static ERRCODE hb_dbfSetFilter( DBFAREAP pArea, LPDBFILTERINFO pFilterInfo ); #define hb_dbfSetLocate NULL #define hb_dbfSetScope NULL #define hb_dbfSkipScope NULL +#define hb_dbfLocate NULL #define hb_dbfCompile NULL #define hb_dbfError NULL #define hb_dbfEvalBlock NULL static ERRCODE hb_dbfRawLock( DBFAREAP pArea, USHORT uiAction, ULONG lRecNo ); static ERRCODE hb_dbfLock( DBFAREAP pArea, LPDBLOCKINFO pLockInfo ); -static ERRCODE hb_dbfUnLock( DBFAREAP pArea, ULONG ulRecNo ); +static ERRCODE hb_dbfUnLock( DBFAREAP pArea, PHB_ITEM pRecNo ); #define hb_dbfCloseMemFile NULL static ERRCODE hb_dbfCreateMemFile( DBFAREAP pArea, LPDBOPENINFO pCreateInfo ); -#define hb_dbfGetValueFile NULL +static ERRCODE hb_dbfGetValueFile( DBFAREAP pArea, USHORT uiIndex, BYTE * szFile, USHORT uiMode ); static ERRCODE hb_dbfOpenMemFile( DBFAREAP pArea, LPDBOPENINFO pOpenInfo ); -#define hb_dbfPutValueFile NULL +static ERRCODE hb_dbfPutValueFile( DBFAREAP pArea, USHORT uiIndex, BYTE * szFile, USHORT uiMode ); + static ERRCODE hb_dbfReadDBHeader( DBFAREAP pArea ); static ERRCODE hb_dbfWriteDBHeader( DBFAREAP pArea ); -#define hb_dbfExit NULL -static ERRCODE hb_dbfDrop( PHB_ITEM pItemTable ); +static ERRCODE hb_dbfInit( LPRDDNODE pRDD ); +static ERRCODE hb_dbfExit( LPRDDNODE pRDD ); +static ERRCODE hb_dbfDrop( LPRDDNODE pRDD, PHB_ITEM pItemTable, PHB_ITEM pItemIndex ); +static ERRCODE hb_dbfExists( LPRDDNODE pRDD, PHB_ITEM pItemTable, PHB_ITEM pItemIndex ); +static ERRCODE hb_dbfRddInfo( LPRDDNODE pRDD, USHORT uiIndex, ULONG ulConnect, PHB_ITEM pItem ); #define hb_dbfWhoCares NULL #endif /* HB_EXTERNAL_RDDDBF_USE */ -extern BOOL HB_EXPORT hb_dbfExists( PHB_ITEM pItemTable, PHB_ITEM pItemIndex ); -extern ULONG HB_EXPORT hb_dbfGetMemoBlock( DBFAREAP pArea, USHORT uiIndex ); -extern void HB_EXPORT hb_dbfPutMemoBlock( DBFAREAP pArea, USHORT uiIndex, ULONG ulBlock ); +extern ULONG HB_EXPORT hb_dbfGetMemoBlock( DBFAREAP pArea, USHORT uiIndex ); +extern void HB_EXPORT hb_dbfPutMemoBlock( DBFAREAP pArea, USHORT uiIndex, + ULONG ulBlock ); +extern ERRCODE HB_EXPORT hb_dbfGetMemoData( DBFAREAP pArea, USHORT uiIndex, + ULONG * pulBlock, ULONG * pulSize, + ULONG * pulType ); +extern ERRCODE HB_EXPORT hb_dbfSetMemoData( DBFAREAP pArea, USHORT uiIndex, + ULONG ulBlock, ULONG ulSize, + ULONG ulType ); extern ERRCODE HB_EXPORT hb_dbfGetEGcode( ERRCODE errCode ); -extern BOOL HB_EXPORT hb_dbfLockIdxFile( FHANDLE hFile, BYTE bScheme, USHORT usMode, ULONG *pPoolPos ); -extern BOOL HB_EXPORT hb_dbfLockIdxGetData( BYTE bScheme, ULONG *ulPos, ULONG *ulPool ); +extern BOOL HB_EXPORT hb_dbfLockIdxFile( FHANDLE hFile, BYTE bScheme, USHORT usMode, HB_FOFFSET *pPoolPos ); +extern BOOL HB_EXPORT hb_dbfLockIdxGetData( BYTE bScheme, HB_FOFFSET *ulPos, HB_FOFFSET *ulPool ); HB_EXTERN_END diff --git a/harbour/include/hbrdddbt.h b/harbour/include/hbrdddbt.h index e80e548ba3..882981011b 100644 --- a/harbour/include/hbrdddbt.h +++ b/harbour/include/hbrdddbt.h @@ -68,8 +68,8 @@ HB_EXTERN_BEGIN /* MEMO constants and defaults */ #define DBT_MEMOEXT ".dbt" #define DBT_BLOCKSIZE 512 -#define DBT_LOCKPOS 0x00000001L -#define DBT_LOCKSIZE 0x7FFFFFFFL +#define DBT_LOCKPOS 0x00000000L +#define DBT_LOCKSIZE 0x00000001L /* * DBFDBT WORKAREA @@ -124,6 +124,7 @@ static ERRCODE hb_dbtPutValue( DBTAREAP pArea, USHORT uiIndex, PHB_ITEM pItem ); #define hb_dbtRecCount NULL #define hb_dbtRecInfo NULL #define hb_dbtRecNo NULL +#define hb_dbtRecId NULL #define hb_dbtSetFieldExtent NULL #define hb_dbtAlias NULL #define hb_dbtClose NULL @@ -170,6 +171,7 @@ static ERRCODE hb_dbtSysName( DBTAREAP pArea, BYTE * pBuffer ); #define hb_dbtSetLocate NULL #define hb_dbtSetScope NULL #define hb_dbtSkipScope NULL +#define hb_dbtLocate NULL #define hb_dbtCompile NULL #define hb_dbtError NULL #define hb_dbtEvalBlock NULL @@ -181,11 +183,13 @@ static ERRCODE hb_dbtCreateMemFile( DBTAREAP pArea, LPDBOPENINFO pCreateInfo ); #define hb_dbtGetValueFile NULL static ERRCODE hb_dbtOpenMemFile( DBTAREAP pArea, LPDBOPENINFO pOpenInfo ); #define hb_dbtPutValueFile NULL -static ERRCODE hb_dbtReadDBHeader( DBTAREAP pArea ); -static ERRCODE hb_dbtWriteDBHeader( DBTAREAP pArea ); +#define hb_dbtReadDBHeader NULL +#define hb_dbtWriteDBHeader NULL +#define hb_dbtInit NULL #define hb_dbtExit NULL #define hb_dbtDrop NULL #define hb_dbtExists NULL +static ERRCODE hb_dbtRddInfo( LPRDDNODE pRDD, USHORT uiIndex, ULONG ulConnect, PHB_ITEM pItem ); #define hb_dbtWhoCares NULL HB_EXTERN_END diff --git a/harbour/include/hbrdddel.h b/harbour/include/hbrdddel.h index 7d4617c838..5ca2bb7655 100644 --- a/harbour/include/hbrdddel.h +++ b/harbour/include/hbrdddel.h @@ -93,6 +93,7 @@ HB_EXTERN_BEGIN #define hb_delimRecCount NULL #define hb_delimRecInfo NULL #define hb_delimRecNo NULL +#define hb_delimRecId NULL #define hb_delimSetFieldExtent NULL #define hb_delimAlias NULL #define hb_delimClose NULL @@ -139,6 +140,7 @@ HB_EXTERN_BEGIN #define hb_delimSetLocate NULL #define hb_delimSetScope NULL #define hb_delimSkipScope NULL +#define hb_delimLocate NULL #define hb_delimCompile NULL #define hb_delimError NULL #define hb_delimEvalBlock NULL @@ -152,9 +154,11 @@ HB_EXTERN_BEGIN #define hb_delimPutValueFile NULL #define hb_delimReadDBHeader NULL #define hb_delimWriteDBHeader NULL +#define hb_delimInit NULL #define hb_delimExit NULL #define hb_delimDrop NULL #define hb_delimExists NULL +#define hb_delimRddInfo NULL #define hb_delimWhoCares NULL HB_EXTERN_END diff --git a/harbour/include/hbrddfpt.h b/harbour/include/hbrddfpt.h index 29d9fe15fd..b7abd5c065 100644 --- a/harbour/include/hbrddfpt.h +++ b/harbour/include/hbrddfpt.h @@ -66,24 +66,43 @@ HB_EXTERN_BEGIN /* MEMO constants and defaults */ +#define DBT_MEMOEXT ".dbt" #define FPT_MEMOEXT ".fpt" -#define FPT_LOCKPOS 0x00000000L -#define FPT_LOCKSIZE 0x7FFFFFFFL +#define SMT_MEMOEXT ".smt" +#define DBT_DEFBLOCKSIZE 512 #define FPT_DEFBLOCKSIZE 64 +#define SMT_DEFBLOCKSIZE 32 + +#define FPT_LOCKPOS 0x00000000L +#define FPT_LOCKSIZE 0x00000001L + #define SIX_ITEM_BUFSIZE 14 #define FLEX_ITEM_BUFSIZE 8 #define MAX_SIXFREEBLOCKS 82 #define MAX_FLEXFREEBLOCKS 126 #define FLEXGCPAGE_SIZE 1010 -/* usMemoType */ -#define MEMO_DBT 1 -#define MEMO_FPT_HB 2 -#define MEMO_FPT_SIX 3 -#define MEMO_FPT_SIXHB 4 -#define MEMO_FPT_FLEX 5 -#define MEMO_FPT_CLIP 6 +/* "V" filed types */ +#define HB_VF_CHAR 64000 +#define HB_VF_DATE 64001 +#define HB_VF_INT 64002 +#define HB_VF_LOG 64003 +#define HB_VF_DNUM 64004 +#define HB_VF_ARRAY 64005 +#define HB_VF_BLOB 64006 +#define HB_VF_BLOBCOMPRESS 64007 +#define HB_VF_BLOBENCRYPT 64008 +/* SMT types */ +#define SMT_IT_NIL 0 +#define SMT_IT_CHAR 1 +#define SMT_IT_INT 2 +#define SMT_IT_DOUBLE 3 +#define SMT_IT_DATE 4 +#define SMT_IT_LOGICAL 5 +#define SMT_IT_ARRAY 6 + +#define FPTIT_DUMMY 0xDEADBEAF #define FPTIT_BINARY 0x0000 #define FPTIT_PICT 0x0000 /* Picture */ #define FPTIT_TEXT 0x0001 /* Text */ @@ -118,7 +137,13 @@ HB_EXTERN_BEGIN #define FPTIT_FLEX_ULONG 0x03F7 // 1015 * #define FPTIT_FLEX_DOUBLE 0x03F8 // 1016 #define FPTIT_FLEX_LDOUBLE 0x03F9 // 1017 * -#define FPTIT_FLEX_COMPCH 0x03FA // 1018 * +#define FPTIT_FLEX_COMPRCH 0x03FA // 1018 * + +/* Flex II types */ +#define FPTIT_FLEX_DBLITEM 0x2710 // 10000 14-bytes Clipper double item +#define FPTIT_FLEX_LOGICAL 0x2711 // 10001 4-bytes logical value +#define FPTIT_FLEX_NULSTR 0x2722 // 10002 empty string + #define FPTIT_FLEXAR_NIL 0x00 #define FPTIT_FLEXAR_STR 0x07 @@ -138,24 +163,11 @@ HB_EXTERN_BEGIN #define FPTIT_FLEXAR_LONG2 0x20 #define FPTIT_FLEXAR_ULONG 0x21 -/* -#define HB_IT_NIL ( ( USHORT ) 0x0000 ) -#define HB_IT_POINTER ( ( USHORT ) 0x0001 ) -#define HB_IT_LONGLONG ( ( USHORT ) 0x0040 ) -#define HB_IT_SYMBOL ( ( USHORT ) 0x0100 ) -#define HB_IT_ALIAS ( ( USHORT ) 0x0200 ) -#define HB_IT_BLOCK ( ( USHORT ) 0x1000 ) -#define HB_IT_BYREF ( ( USHORT ) 0x2000 ) -#define HB_IT_MEMVAR ( ( USHORT ) 0x4000 ) -#define HB_IT_ANY ( ( USHORT ) 0xFFFF ) -*/ - /* MEMO file strucutres */ typedef struct _FPTHEADER { BYTE nextBlock[ 4 ]; /* Next free block in the file */ - BYTE reserved1[ 2 ]; /* */ - BYTE blockSize[ 2 ]; /* Size of block */ + BYTE blockSize[ 4 ]; /* Size of block */ BYTE signature1[ 10 ]; /* Signature: "SixMemo", "Harbour", "Made by CLIP"-overwrites next bytes*/ BYTE nGCitems[ 2 ]; /* number of GC items in reserved2 (max 82)*/ BYTE reserved2[ 492 ]; /* */ @@ -191,6 +203,7 @@ typedef struct _MEMOGCTABLE BYTE bType; /* MEMO_FPT_SIX or MEMO_FPT_FLEX */ BYTE bChanged; /* Should we write GC data to disk */ ULONG ulNextBlock; /* Next free block in the file */ + ULONG ulPrevBlock; /* Previous next free block in the file */ ULONG ulRevPage; /* FLEX Rev GC page offset */ ULONG ulDirPage; /* FLEX Dir GC page offset */ ULONG ulCounter; /* FLEX cyclic counter */ @@ -255,6 +268,7 @@ static ERRCODE hb_fptPutValue( FPTAREAP pArea, USHORT uiIndex, PHB_ITEM pItem ); #define hb_fptRecCount NULL #define hb_fptRecInfo NULL #define hb_fptRecNo NULL +#define hb_fptRecId NULL #define hb_fptSetFieldExtent NULL #define hb_fptAlias NULL #define hb_fptClose NULL @@ -301,6 +315,7 @@ static ERRCODE hb_fptSysName( FPTAREAP pArea, BYTE * pBuffer ); #define hb_fptSetLocate NULL #define hb_fptSetScope NULL #define hb_fptSkipScope NULL +#define hb_fptLocate NULL #define hb_fptCompile NULL #define hb_fptError NULL #define hb_fptEvalBlock NULL @@ -309,14 +324,16 @@ static ERRCODE hb_fptSysName( FPTAREAP pArea, BYTE * pBuffer ); #define hb_fptUnLock NULL #define hb_fptCloseMemFile NULL static ERRCODE hb_fptCreateMemFile( FPTAREAP pArea, LPDBOPENINFO pCreateInfo ); -#define hb_fptGetValueFile NULL +static ERRCODE hb_fptGetValueFile( FPTAREAP pArea, USHORT uiIndex, BYTE * szFile, USHORT uiMode ); static ERRCODE hb_fptOpenMemFile( FPTAREAP pArea, LPDBOPENINFO pOpenInfo ); -#define hb_fptPutValueFile NULL -static ERRCODE hb_fptReadDBHeader( FPTAREAP pArea ); -static ERRCODE hb_fptWriteDBHeader( FPTAREAP pArea ); +static ERRCODE hb_fptPutValueFile( FPTAREAP pArea, USHORT uiIndex, BYTE * szFile, USHORT uiMode ); +#define hb_fptReadDBHeader NULL +#define hb_fptWriteDBHeader NULL +#define hb_fptInit NULL #define hb_fptExit NULL #define hb_fptDrop NULL #define hb_fptExists NULL +static ERRCODE hb_fptRddInfo( LPRDDNODE pRDD, USHORT uiIndex, ULONG ulConnect, PHB_ITEM pItem ); #define hb_fptWhoCares NULL HB_EXTERN_END diff --git a/harbour/include/hbrddntx.h b/harbour/include/hbrddntx.h index fd6d3c367e..a27feb6998 100644 --- a/harbour/include/hbrddntx.h +++ b/harbour/include/hbrddntx.h @@ -58,24 +58,106 @@ #ifndef HB_CDP_SUPPORT_OFF #include "hbapicdp.h" #endif +#define HB_EXTERNAL_RDDDBF_USE +#include "hbrdddbf.h" HB_EXTERN_BEGIN /* DBFNTX default extensions */ -#define NTX_INDEXEXT ".ntx" +#define NTX_INDEXEXT ".ntx" /* DBFNTX constants declarations */ -#define TOP_RECORD 1 -#define BTTM_RECORD 2 -#define PREV_RECORD 3 -#define NEXT_RECORD 4 +#define NTX_IGNORE_REC_NUM 0x0UL +#define NTX_MAX_REC_NUM 0xFFFFFFFFUL + +#define NTX_DUMMYNODE 0xFFFFFFFFUL + +#define NTX_FLAG_DEFALUT 0x0006 +#define NTX_FLAG_OLDDEFALUT 0x0003 +#define NTX_FLAG_FORITEM 0x0001 +#define NTX_FLAG_PARTIAL 0x0008 +#define NTX_FLAG_EXTLOCK 0x0010 +#define NTX_FLAG_CUSTOM 0x0020 +#define NTX_FLAG_CHGONLY 0x0040 +#define NTX_FLAG_TEMPLATE 0x0080 +#define NTX_FLAG_SORTRECNO 0x0100 +#define NTX_FLAG_LARGEFILE 0x0200 +#define NTX_FLAG_MULTIKEY 0x0400 +#define NTX_FLAG_COMPOUND 0x8000 +#define NTX_FLAG_MASK 0x87FF + +#define CTX_MAX_TAGS 63 + +#define NTX_MAX_KEY 256 /* Max len of key */ +#define NTX_MAX_EXP 256 /* Max len of KEY/FOR expression */ +#define NTXBLOCKBITS 10 /* Size of NTX block in bits */ +#define NTXBLOCKSIZE (1< + * www - http://www.xharbour.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/). + * + * As a special exception, the Harbour Project gives permission for + * additional uses of the text contained in its release of Harbour. + * + * The exception is that, if you link the Harbour libraries with other + * files to produce an executable, this does not by itself cause the + * resulting executable to be covered by the GNU General Public License. + * Your use of that executable is in no way restricted on account of + * linking the Harbour library code into it. + * + * This exception does not however invalidate any other reasons why + * the executable file might be covered by the GNU General Public License. + * + * This exception applies only to the code released by the Harbour + * Project under the name Harbour. If you copy code from other + * Harbour Project or Free Software Foundation releases into a copy of + * Harbour, as the General Public License permits, the exception does + * not apply to the code that you add in this way. To avoid misleading + * anyone as to the status of such modified files, you must delete + * this exception notice from them. + * + * If you write modifications of your own for Harbour, it is your choice + * whether to permit this exception to apply to your modifications. + * If you do not wish that, delete this exception notice. + * + */ + +#ifndef HB_SXFUNC_H_ +#define HB_SXFUNC_H_ + +#include "hbapi.h" +#include "hbapifs.h" +#include "hbapirdd.h" +#include "hbapierr.h" +#include "hbdate.h" + +HB_EXTERN_BEGIN + +char * hb_sxDtoP( char * pDate, LONG lJulian ); +LONG hb_sxPtoD( char * pDate ); + +void hb_sxEnCrypt( BYTE * pSrc, BYTE * pDst, BYTE * pKeyVal, ULONG ulLen ); +void hb_sxDeCrypt( BYTE * pSrc, BYTE * pDst, BYTE * pKeyVal, ULONG ulLen ); + +BOOL hb_LZSSxDecompressMem( BYTE * pSrcBuf, ULONG ulSrcLen, BYTE * pDstBuf, ULONG ulDstLen ); +BOOL hb_LZSSxDecompressMem( BYTE * pSrcBuf, ULONG ulSrcLen, BYTE * pDstBuf, ULONG ulDstLen ); +BOOL hb_LZSSxCompressFile( FHANDLE hInput, FHANDLE hOutput, ULONG * pulSize ); +BOOL hb_LZSSxDecompressFile( FHANDLE hInput, FHANDLE hOutput ); + +HB_EXTERN_END + +#endif /* HB_SXFUNC_H_ */ diff --git a/harbour/include/hbvm.h b/harbour/include/hbvm.h index dff6688abf..fa6a3ba756 100644 --- a/harbour/include/hbvm.h +++ b/harbour/include/hbvm.h @@ -88,6 +88,7 @@ extern void hb_vmSend( USHORT uiParams ); /* sends a message to an object */ extern PHB_ITEM hb_vmEvalBlock( PHB_ITEM pBlockItem ); /* executes passed codeblock with no arguments */ /* executes passed codeblock with variable number of arguments */ extern PHB_ITEM hb_vmEvalBlockV( PHB_ITEM pBlockItem, ULONG ulArgCount, ... ); +extern PHB_ITEM hb_vmEvalBlockOrMacro( HB_ITEM_PTR pItem ); /* execute a codeblock or a macro */ /* Push */ extern void hb_vmPush( PHB_ITEM pItem ); /* pushes a generic item onto the stack */ diff --git a/harbour/source/common/hbstr.c b/harbour/source/common/hbstr.c index 3e684fb208..678feff3e9 100644 --- a/harbour/source/common/hbstr.c +++ b/harbour/source/common/hbstr.c @@ -218,6 +218,28 @@ HB_EXPORT char * hb_strncat( char * pDest, const char * pSource, ULONG ulLen ) return pBuf; } +char HB_EXPORT * hb_strndup( const char * pszText, ULONG ulLen ) +{ + char * pszDup; + ULONG ul; + + HB_TRACE(HB_TR_DEBUG, ("hb_strndup(%s, %ld)", pszText, ulLen)); + + ul = 0; + pszDup = ( char * ) pszText; + while( ulLen-- && *pszDup++ ) + { + ++ul; + } + + pszDup = ( char * ) hb_xgrab( ul + 1 ); + memcpy( pszDup, pszText, ul ); + pszDup[ ul ] = '\0'; + + return pszDup; +} + + /* This function copies and converts szText to upper case. * NOTE: Unlike the documentation for strncpy, this routine will always append * a null @@ -598,3 +620,78 @@ double hb_strVal( const char * szText, ULONG ulLen ) dVal = ( double ) lVal; return dVal; } + +/* +AJ: 2004-02-23 +Concatenates multiple strings into a single result. +Eg. hb_xstrcat (buffer, "A", "B", NULL) stores "AB" in buffer. +*/ +char HB_EXPORT * hb_xstrcat ( char *szDest, const char *szSrc, ... ) +{ + char *szResult = szDest; + va_list va; + + HB_TRACE(HB_TR_DEBUG, ("hb_xstrcat(%p, %p, ...)", szDest, szSrc)); + + while( *szDest ) + szDest++; + + va_start(va, szSrc); + + while( szSrc ) + { + while ( *szSrc ) + *szDest++ = *szSrc++; + szSrc = va_arg ( va, char* ); + } + + *szDest = '\0'; + va_end ( va ); + return ( szResult ); +} + +/* +AJ: 2004-02-23 +Concatenates multiple strings into a single result. +Eg. hb_xstrcpy (buffer, "A", "B", NULL) stores "AB" in buffer. +Returns szDest. +Any existing contents of szDest are cleared. If the szDest buffer is NULL, +allocates a new buffer with the required length and returns that. The +buffer is allocated using hb_xgrab(), and should eventually be freed +using hb_xfree(). +*/ +char HB_EXPORT * hb_xstrcpy ( char *szDest, const char *szSrc, ...) +{ + const char *szSrc_Ptr; + va_list va; + size_t dest_size; + + HB_TRACE(HB_TR_DEBUG, ("hb_xstrcpy(%p, %p, ...)", szDest, szSrc)); + + if (szDest == NULL) + { + va_start (va, szSrc); + szSrc_Ptr = szSrc; + dest_size = 1; + while (szSrc_Ptr) + { + dest_size += strlen (szSrc_Ptr); + szSrc_Ptr = va_arg (va, char *); + } + va_end (va); + + szDest = (char *) hb_xgrab( dest_size ); + } + + va_start (va, szSrc); + szSrc_Ptr = szSrc; + szDest [0] = '\0'; + while (szSrc_Ptr) + { + hb_xstrcat (szDest, szSrc_Ptr, NULL ); + szSrc_Ptr = va_arg (va, char *); + } + va_end (va); + return (szDest); +} + diff --git a/harbour/source/rdd/Makefile b/harbour/source/rdd/Makefile index c5b86da6f4..64a863ca83 100644 --- a/harbour/source/rdd/Makefile +++ b/harbour/source/rdd/Makefile @@ -15,8 +15,8 @@ C_SOURCES=\ PRG_SOURCES=\ dbf0.prg \ - dbtotal.prg \ - dbfuncs.prg \ + dbfuncs.prg \ + dbtotal.prg \ dblist.prg \ dbsort.prg \ dbstrux.prg \ @@ -25,9 +25,14 @@ PRG_SOURCES=\ delim0.prg \ rddord.prg \ rddsys.prg \ + +ifeq ($(HB_MT),MT) + MT_LIBNAME=rddmt +endif LIBNAME=rdd + # The list of all valid DB drivers is defined in config/global.cf. DIRS=$(HB_DB_DRIVERS) diff --git a/harbour/source/rdd/dbcmd.c b/harbour/source/rdd/dbcmd.c index df5a3ec310..4723925e12 100644 --- a/harbour/source/rdd/dbcmd.c +++ b/harbour/source/rdd/dbcmd.c @@ -58,55 +58,89 @@ * ordKeyDel() * hb_rddIterateWorkAreas() * hb_rddGetTempAlias + * __RDDGETTEMPALIAS * */ #include -#include "hbvm.h" +#include "hbapi.h" #include "hbstack.h" +#include "hbvm.h" #include "hbapifs.h" #include "hbset.h" #include "hbapierr.h" #include "hbapilng.h" #include "hbapiitm.h" #include "hbrddwrk.h" -#include "hbapicdp.h" - -#ifndef min -#define min(a,b) (((a) < (b)) ? (a) : (b)) +#if defined(__XHARBOUR__) +#include "hbfast.h" +#else +# define HB_THREAD_STUB +# define HB_ITEM_NEW(hb) HB_ITEM hb = HB_ITEM_NIL +#endif +#ifndef HB_CDP_SUPPORT_OFF +# include "hbapicdp.h" #endif -typedef struct _AREANODE -{ - void * pArea; /* WorkAreas with different sizes */ - struct _AREANODE * pPrev; /* Prev WorkArea in the list */ - struct _AREANODE * pNext; /* Next WorkArea in the list */ -} AREANODE; - -typedef AREANODE * LPAREANODE; - -HB_FUNC_EXTERN( _DBF ); -HB_FUNC_EXTERN( _SDF ); -HB_FUNC_EXTERN( _DELIM ); HB_FUNC_EXTERN( RDDSYS ); -static char * s_szDefDriver = NULL; /* Default RDD name */ -static USHORT s_uiCurrArea = 1; /* Selectd area */ -static LPRDDNODE s_pRddList = NULL; /* Registered RDD's */ -static BOOL s_bNetError = FALSE; /* Error on Networked environments */ +static char s_szDefDriver[HARBOUR_MAX_RDD_DRIVERNAME_LENGTH + 1] = ""; /* Default RDD name */ +static LPRDDNODE * s_RddList = NULL; /* Registered RDDs */ +static USHORT s_uiRddMax = 0; /* Number of registered RDD */ -static LPAREANODE s_pWorkAreas = NULL; /* WorkAreas */ -static LPAREANODE s_pCurrArea = NULL; /* Pointer to a selected and valid area */ +static AREAP * s_WaList = NULL; /* Allocated WorkAreas */ +static USHORT s_uiWaMax = 0; /* Number of allocated WA */ +static USHORT s_uiWaSpace = 0; /* Number of allocated WA */ + +static USHORT * s_WaNums = NULL; /* Allocated WorkAreas */ +static USHORT s_uiWaNumMax = 0; /* Number of allocated WA */ + +static BOOL s_bNetError = FALSE; /* Error on Networked environments */ +#ifndef HB_THREAD_SUPPORT + static USHORT s_uiCurrArea = 1; /* Selected area */ + static AREAP s_pCurrArea = NULL; /* Selected area */ + #define LOCK_AREA + #define UNLOCK_AREA + #define LOCK_AREA_INIT + #define LOCK_AREA_DESTROY +#else + #define s_uiCurrArea HB_VM_STACK.uiCurrArea + #define s_pCurrArea HB_VM_STACK.pCurrArea + HB_CRITICAL_T s_mtxWorkArea; + #if defined (HB_OS_WIN_32) || defined(HB_OS_OS2) + static BOOL s_fMtLockInit = FALSE; + #define LOCK_AREA if ( s_fMtLockInit ) HB_CRITICAL_LOCK( s_mtxWorkArea ); + #define UNLOCK_AREA if ( s_fMtLockInit ) HB_CRITICAL_UNLOCK( s_mtxWorkArea ); + #define LOCK_AREA_INIT if ( !s_fMtLockInit ) { HB_CRITICAL_INIT( s_mtxWorkArea ); s_fMtLockInit = TRUE; } + #define LOCK_AREA_DESTROY if ( s_fMtLockInit ) { HB_CRITICAL_DESTROY( s_mtxWorkArea ); s_fMtLockInit = FALSE; } + #else + #define LOCK_AREA HB_CRITICAL_LOCK( s_mtxWorkArea ); + #define UNLOCK_AREA HB_CRITICAL_UNLOCK( s_mtxWorkArea ); + #define LOCK_AREA_INIT + #define LOCK_AREA_DESTROY + #endif +#endif + +#define HB_SET_WA( n ) do \ + { \ + s_uiCurrArea = n; \ + s_pCurrArea = ( ( s_uiCurrArea < s_uiWaNumMax ) ? \ + s_WaList[ s_WaNums[ s_uiCurrArea ] ] : \ + NULL ); \ + } while ( 0 ); + +#define HB_GET_WA( n ) ( ( (n) < s_uiWaNumMax ) ? s_WaList[ s_WaNums[ ( n ) ] ] : NULL ) +//#define HB_CURRENT_WA HB_GET_WA( s_uiCurrArea ) +#define HB_CURRENT_WA s_pCurrArea /* * -- DEFAULT METHODS -- */ +#if 0 /* * Empty method. */ - -#if 0 static ERRCODE hb_waNull( AREAP pArea ) { HB_TRACE(HB_TR_DEBUG, ("hb_waNull(%p)", pArea)); @@ -125,11 +159,37 @@ static ERRCODE hb_waUnsupported( AREAP pArea ) HB_TRACE(HB_TR_DEBUG, ("hb_waUnsupported(%p)", pArea)); + if( !pArea ) + { + HB_FUNCNAME( RDDSYS )(); + } + pError = hb_errNew(); hb_errPutGenCode( pError, EG_UNSUPPORTED ); hb_errPutDescription( pError, hb_langDGetErrorDesc( EG_UNSUPPORTED ) ); SELF_ERROR( pArea, pError ); - hb_errRelease( pError ); + hb_itemRelease( pError ); + + return FAILURE; +} + +/* + * Raise a runtime error if an method is not defined. + */ +static ERRCODE hb_waRddUnsupported( LPRDDNODE pRDD ) +{ + PHB_ITEM pError; + + HB_TRACE(HB_TR_DEBUG, ("hb_waRDDUnsupported(%p)", pRDD)); + + pError = hb_errNew(); + hb_errPutGenCode( pError, EG_UNSUPPORTED ); + hb_errPutDescription( pError, hb_langDGetErrorDesc( EG_UNSUPPORTED ) ); + + hb_errPutSeverity( pError, ES_ERROR ); + hb_errPutSubSystem( pError, pRDD->szName ); + hb_errLaunch( pError ); + hb_itemRelease( pError ); return FAILURE; } @@ -169,6 +229,7 @@ static RDDFUNCS waTable = { hb_waBof, hb_waRecCount, hb_waRecInfo, hb_waRecNo, + hb_waRecId, hb_waSetFieldExtent, hb_waAlias, hb_waClose, @@ -215,6 +276,7 @@ static RDDFUNCS waTable = { hb_waBof, hb_waSetLocate, hb_waSetScope, hb_waSkipScope, + hb_waLocate, hb_waCompile, hb_waError, hb_waEvalBlock, @@ -228,80 +290,22 @@ static RDDFUNCS waTable = { hb_waBof, hb_waPutValueFile, hb_waReadDBHeader, hb_waWriteDBHeader, + hb_rddInit, hb_rddExit, hb_rddDrop, hb_rddExists, + hb_rddInfo, hb_waWhoCares }; - - /* - * -- BASIC RDD METHODS -- + * Get RDD node poionter */ - -/* - * Force link the built-in RDD's. - */ -static void hb_rddCheck( void ) +LPRDDNODE HB_EXPORT hb_rddGetNode( USHORT uiNode ) { - HB_TRACE(HB_TR_DEBUG, ("hb_rddCheck()")); + HB_TRACE(HB_TR_DEBUG, ("hb_rddGetNode(%hu)", uiNode)); - if( !s_szDefDriver ) - { - s_szDefDriver = ( char * ) hb_xgrab( 1 ); - s_szDefDriver[ 0 ] = '\0'; - - /* Force link the built-in RDD's */ - HB_FUNCNAME( _DBF )(); - HB_FUNCNAME( _SDF )(); - HB_FUNCNAME( _DELIM )(); - HB_FUNCNAME( RDDSYS )(); - } -} - -/* - * Closes all WorkAreas. - */ -static void hb_rddCloseAll( void ) -{ - BOOL isParents = TRUE, isFinish = FALSE; - LPAREANODE pAreaNode,pCurrArea; - HB_TRACE(HB_TR_DEBUG, ("hb_rddCloseAll()")); - - while( isParents ) - { - pAreaNode = s_pWorkAreas; - isParents = FALSE; - while( pAreaNode ) - { - pCurrArea = pAreaNode; - pAreaNode = pAreaNode->pNext; - s_pCurrArea = pCurrArea; - s_uiCurrArea = ( ( AREAP ) pCurrArea->pArea )->uiArea; - if ( isFinish ) - { - SELF_RELEASE( ( AREAP ) pCurrArea->pArea ); - pCurrArea->pArea = NULL; - hb_xfree( pCurrArea ); - } - else if( pCurrArea->pArea ) - { - if( ( ( AREAP ) pCurrArea->pArea )->uiParents ) - isParents = TRUE; - else - { - SELF_CLOSE( ( AREAP ) pCurrArea->pArea ); - } - } - } - if( !isParents && !isFinish ) - isParents = isFinish = TRUE; - } - - s_uiCurrArea = 1; - s_pCurrArea = NULL; - s_pWorkAreas = NULL; + return uiNode < s_uiRddMax ? s_RddList[ uiNode ] : NULL; } /* @@ -309,35 +313,31 @@ static void hb_rddCloseAll( void ) */ static LPRDDNODE hb_rddFindNode( char * szDriver, USHORT * uiIndex ) { - LPRDDNODE pRddNode; USHORT uiCount; HB_TRACE(HB_TR_DEBUG, ("hb_rddFindNode(%s, %p)", szDriver, uiIndex)); - uiCount = 0; - pRddNode = s_pRddList; - while( pRddNode ) + for ( uiCount = 0; uiCount < s_uiRddMax; uiCount++ ) { - if( strcmp( pRddNode->szName, szDriver ) == 0 ) /* Matched RDD */ + if( strcmp( s_RddList[ uiCount ]->szName, szDriver ) == 0 ) /* Matched RDD */ { if( uiIndex ) * uiIndex = uiCount; - return pRddNode; + return s_RddList[ uiCount ]; } - pRddNode = pRddNode->pNext; - uiCount++; } if( uiIndex ) * uiIndex = 0; return NULL; } + /* * Register a RDD driver. */ static int hb_rddRegister( char * szDriver, USHORT uiType ) { - LPRDDNODE pRddNode, pRddNewNode; + LPRDDNODE pRddNewNode; PHB_DYNS pGetFuncTable; char * szGetFuncTable; USHORT uiFunctions; @@ -345,7 +345,9 @@ static int hb_rddRegister( char * szDriver, USHORT uiType ) HB_TRACE(HB_TR_DEBUG, ("hb_rddRegister(%s, %hu)", szDriver, uiType)); if( hb_rddFindNode( szDriver, NULL ) ) /* Duplicated RDD */ + { return 1; + } szGetFuncTable = ( char * ) hb_xgrab( strlen( szDriver ) + 14 ); strcpy( szGetFuncTable, szDriver ); @@ -353,89 +355,59 @@ static int hb_rddRegister( char * szDriver, USHORT uiType ) pGetFuncTable = hb_dynsymFindName( szGetFuncTable ); hb_xfree( szGetFuncTable ); if( !pGetFuncTable ) + { return 2; /* Not valid RDD */ + } /* Create a new RDD node */ pRddNewNode = ( LPRDDNODE ) hb_xgrab( sizeof( RDDNODE ) ); memset( pRddNewNode, 0, sizeof( RDDNODE ) ); /* Fill the new RDD node */ - - strncat( pRddNewNode->szName, szDriver, HARBOUR_MAX_RDD_DRIVERNAME_LENGTH ); pRddNewNode->uiType = uiType; + pRddNewNode->rddID = s_uiRddMax; /* Call _GETFUNCTABLE() */ hb_vmPushSymbol( pGetFuncTable->pSymbol ); hb_vmPushNil(); hb_vmPushPointer( ( void * ) &uiFunctions ); hb_vmPushPointer( ( void * ) &pRddNewNode->pTable ); - hb_vmDo( 2 ); - if ( hb_parni( -1 ) != SUCCESS ) + hb_vmPushPointer( ( void * ) &pRddNewNode->pSuperTable ); + hb_vmPushInteger( s_uiRddMax ); + hb_vmDo( 4 ); + if( hb_parni( -1 ) != SUCCESS ) { hb_xfree( pRddNewNode ); /* Delete de new RDD node */ return 3; /* Invalid FUNCTABLE */ } - if( !s_pRddList ) /* First RDD node */ - s_pRddList = pRddNewNode; - else + if( s_uiRddMax == 0 ) /* First RDD node */ { - pRddNode = s_pRddList; - while( pRddNode->pNext ) - pRddNode = pRddNode->pNext; /* Locate the last RDD node */ - pRddNode->pNext = pRddNewNode; /* Add the new RDD node */ + LOCK_AREA_INIT + s_RddList = (LPRDDNODE *) hb_xgrab( sizeof(LPRDDNODE) ); } + else + s_RddList = (LPRDDNODE *) hb_xrealloc( s_RddList, sizeof(LPRDDNODE) * ( s_uiRddMax + 1 ) ); + + s_RddList[ s_uiRddMax++ ] = pRddNewNode; /* Add the new RDD node */ + + if( pRddNewNode->pTable.init != NULL ) + { + SELF_INIT( pRddNewNode ); + } + return 0; /* Ok */ } -/* - * Find a WorkArea by the alias. - */ -static USHORT hb_rddSelect( char * szAlias ) -{ - PHB_DYNS pSymAlias; - - HB_TRACE(HB_TR_DEBUG, ("hb_rddSelect(%s)", szAlias)); - - pSymAlias = hb_dynsymFindName( szAlias ); - if( pSymAlias && pSymAlias->hArea ) - return ( USHORT ) pSymAlias->hArea; - else - return 0; -} - -/* - * Return the next free WorkArea for later use. - */ -static void hb_rddSelectFirstAvailable( void ) -{ - LPAREANODE pAreaNode; - - HB_TRACE(HB_TR_DEBUG, ("hb_rddSelectFirstAvailable()")); - - s_uiCurrArea = 1; - pAreaNode = s_pWorkAreas; - while( pAreaNode ) - { - if( ( ( AREAP ) pAreaNode->pArea )->uiArea > s_uiCurrArea ) - break; - else if( ( ( AREAP ) pAreaNode->pArea )->uiArea == s_uiCurrArea ) - s_uiCurrArea++; - pAreaNode = pAreaNode->pNext; - } - s_pCurrArea = NULL; /* Selected WorkArea must be created */ -} - /* * pTable - a table in new RDDNODE that will be filled * pSubTable - a table with a list of supported functions * pSuperTable - a current table in a RDDNODE * szDrvName - a driver name that will be inherited -*/ -ERRCODE hb_rddInherit( PRDDFUNCS pTable, PRDDFUNCS pSubTable, PRDDFUNCS pSuperTable, BYTE * szDrvName ) + */ +ERRCODE HB_EXPORT hb_rddInherit( PRDDFUNCS pTable, PRDDFUNCS pSubTable, PRDDFUNCS pSuperTable, BYTE * szDrvName ) { - char * szSuperName; LPRDDNODE pRddNode; USHORT uiCount; DBENTRYP_V * pFunction, * pSubFunction; @@ -443,10 +415,12 @@ ERRCODE hb_rddInherit( PRDDFUNCS pTable, PRDDFUNCS pSubTable, PRDDFUNCS pSuperTa HB_TRACE(HB_TR_DEBUG, ("hb_rddInherit(%p, %p, %p, %s)", pTable, pSubTable, pSuperTable, szDrvName)); if( !pTable ) + { return FAILURE; + } /* Copy the pSuperTable into pTable */ - if( !szDrvName || ( uiCount = strlen( ( const char * ) szDrvName ) ) == 0 ) + if( !szDrvName || ! *szDrvName ) { /* no name for inherited driver - use the default one */ memcpy( pTable, &waTable, sizeof( RDDFUNCS ) ); @@ -454,12 +428,15 @@ ERRCODE hb_rddInherit( PRDDFUNCS pTable, PRDDFUNCS pSubTable, PRDDFUNCS pSuperTa } else { - szSuperName = ( char * ) hb_xgrab( uiCount + 1 ); - hb_strncpyUpper( szSuperName, ( char * ) szDrvName, uiCount ); + char szSuperName[ HARBOUR_MAX_RDD_DRIVERNAME_LENGTH + 1 ]; + hb_strncpyUpper( szSuperName, ( char * ) szDrvName, HARBOUR_MAX_RDD_DRIVERNAME_LENGTH ); pRddNode = hb_rddFindNode( szSuperName, NULL ); - hb_xfree( szSuperName ); + if( !pRddNode ) + { return FAILURE; + } + memcpy( pTable, &pRddNode->pTable, sizeof( RDDFUNCS ) ); memcpy( pSuperTable, &pRddNode->pTable, sizeof( RDDFUNCS ) ); } @@ -478,161 +455,267 @@ ERRCODE hb_rddInherit( PRDDFUNCS pTable, PRDDFUNCS pSubTable, PRDDFUNCS pSuperTa } /* - * Closes and releases the current WorkArea preparing it - * to be used with a new database. + * check if a given name can be used as alias expression */ -void hb_rddReleaseCurrentArea( void ) +static ERRCODE hb_rddVerifyAliasName( char * szAlias ) { - HB_TRACE(HB_TR_DEBUG, ("hb_rddReleaseCurrentArea()")); - SELF_CLOSE( ( AREAP ) s_pCurrArea->pArea ); - SELF_RELEASE( ( AREAP ) s_pCurrArea->pArea ); + char c; - if( s_pWorkAreas == s_pCurrArea ) + if( szAlias ) { - s_pWorkAreas = s_pCurrArea->pNext; - if( s_pWorkAreas ) - s_pWorkAreas->pPrev = NULL; + while( *szAlias == ' ' ) + { + szAlias++; + } + c = *szAlias; + if( c >= 'a' && c <= 'z' ) + { + c -= 'a' - 'A'; + } + if( ( c >= 'A' && c <= 'Z' ) || c == '_' ) + { + c = *(++szAlias); + while( c != 0 && c != ' ' ) + { + if( c != '_' && ! ( c >= '0' && c <= '9' ) && + ! ( c >= 'A' && c <= 'Z' ) && ! ( c >= 'a' && c <= 'z' ) ) + { + return FAILURE; + } + c = *(++szAlias); + } + return SUCCESS; + } + } + return FAILURE; +} + +/* + * Find a WorkArea by the alias, return FAILURE if not found + */ +static ERRCODE hb_rddGetAliasNumber( char * szAlias, int * iArea ) +{ + BOOL fOneLetter; + char c; + + HB_TRACE(HB_TR_DEBUG, ("hb_rddGetAliasNumber(%s, %p)", szAlias, iArea)); + + while ( *szAlias == ' ' ) + { + szAlias++; + } + c = szAlias[ 0 ]; + if ( c >= 'a' && c <= 'z' ) + { + c -= 'a' - 'A'; + } + + fOneLetter = c && ( szAlias[ 1 ] == 0 || szAlias[ 1 ] == ' ' ); + + if( c >= '0' && c <= '9' ) + { + *iArea = atoi( szAlias ); + } + else if ( fOneLetter && c >= 'A' && c <= 'K' ) + { + *iArea = c - 'A' + 1; + } + else if ( fOneLetter && c == 'M' ) + { + *iArea = 0; } else { - if( s_pCurrArea->pPrev ) - s_pCurrArea->pPrev->pNext = s_pCurrArea->pNext; - if( s_pCurrArea->pNext ) - s_pCurrArea->pNext->pPrev = s_pCurrArea->pPrev; + PHB_DYNS pSymAlias = hb_dynsymFindName( szAlias ); + + if( pSymAlias && pSymAlias->hArea ) + { + *iArea = pSymAlias->hArea; + } + else + { + *iArea = 0; + return FAILURE; + } } - hb_xfree( s_pCurrArea ); - s_pCurrArea = NULL; + return SUCCESS; +} + +/* + * Return the next free WorkArea for later use. + */ +static ERRCODE hb_rddSelectFirstAvailable( void ) +{ + HB_THREAD_STUB + USHORT uiArea; + + HB_TRACE(HB_TR_DEBUG, ("hb_rddSelectFirstAvailable()")); + + LOCK_AREA + uiArea = 1; + while ( uiArea < s_uiWaNumMax ) + { + if ( s_WaNums[ uiArea ] == 0 ) + break; + uiArea++; + } + HB_SET_WA( uiArea ); + UNLOCK_AREA + return SUCCESS; } /* * Prepares a new WorkArea node. */ -LPAREANODE hb_rddNewAreaNode( LPRDDNODE pRddNode, USHORT uiRddID ) +static AREAP hb_rddNewAreaNode( LPRDDNODE pRddNode, USHORT uiRddID ) { - LPAREANODE pCurrArea; - USHORT uiSize; + AREAP pArea; + + HB_TRACE(HB_TR_DEBUG, ("hb_rddNewAreaNode(%p %d)", pRddNode, uiRddID)); - HB_TRACE(HB_TR_DEBUG, ("hb_rddNewAreaNode(%p %d)", pRddNode,uiRddID)); - pCurrArea = ( LPAREANODE ) hb_xgrab( sizeof( AREANODE ) ); if( pRddNode->uiAreaSize == 0 ) /* Calculate the size of WorkArea */ { - pCurrArea->pArea = ( AREAP ) hb_xgrab( sizeof( AREA ) ); - memset( pCurrArea->pArea, 0, sizeof( AREA ) ); - ( ( AREAP ) pCurrArea->pArea )->lprfsHost = &pRddNode->pTable; + USHORT uiSize; + + pArea = ( AREAP ) hb_xgrab( sizeof( AREA ) ); + memset( pArea, 0, sizeof( AREA ) ); + pArea->lprfsHost = &pRddNode->pTable; /* Need more space? */ - SELF_STRUCTSIZE( ( AREAP ) pCurrArea->pArea, &uiSize ); + SELF_STRUCTSIZE( pArea, &uiSize ); if( uiSize > sizeof( AREA ) ) /* Size of Area changed */ { - pCurrArea->pArea = ( AREAP ) hb_xrealloc( pCurrArea->pArea, uiSize ); - memset( pCurrArea->pArea, 0, uiSize ); - ( ( AREAP ) pCurrArea->pArea )->lprfsHost = &pRddNode->pTable; + pArea = ( AREAP ) hb_xrealloc( pArea, uiSize ); + memset( pArea, 0, uiSize ); + pArea->lprfsHost = &pRddNode->pTable; } 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; + pArea = ( AREAP ) hb_xgrab( pRddNode->uiAreaSize ); + memset( pArea, 0, pRddNode->uiAreaSize ); + pArea->lprfsHost = &pRddNode->pTable; } - ( ( AREAP ) pCurrArea->pArea )->rddID = uiRddID; + pArea->rddID = uiRddID; + SELF_NEW( pArea ); - pCurrArea->pPrev = NULL; - pCurrArea->pNext = NULL; - - SELF_NEW( ( AREAP ) pCurrArea->pArea ); - return pCurrArea; + return pArea; } /* - * Insert the new WorkArea node + * Closes and releases the current WorkArea preparing it + * to be used with a new database. */ -USHORT hb_rddInsertAreaNode( char *szDriver ) +void HB_EXPORT hb_rddReleaseCurrentArea( void ) { - USHORT uiRddID; - LPRDDNODE pRddNode; - LPAREANODE pAreaNode; + HB_THREAD_STUB + USHORT uiWaPos; + AREAP pArea = HB_CURRENT_WA; - HB_TRACE(HB_TR_DEBUG, ("hb_rddInsertAreaNode(%s)", szDriver)); - pRddNode = hb_rddFindNode( szDriver, &uiRddID ); - if( !pRddNode ) - return FALSE; + HB_TRACE(HB_TR_DEBUG, ("hb_rddReleaseCurrentArea()")); - s_pCurrArea = hb_rddNewAreaNode( pRddNode, uiRddID ); - if( !s_pWorkAreas ) - s_pWorkAreas = s_pCurrArea; /* The new WorkArea node is the first */ + if( !pArea ) + { + return; + } + + if( SELF_CLOSE( pArea ) == FAILURE ) + { + return; + } + SELF_RELEASE( pArea ); + + LOCK_AREA + + uiWaPos = s_WaNums[ s_uiCurrArea ]; + s_WaNums[ s_uiCurrArea ] = 0; + s_uiWaMax--; + if ( s_uiWaMax <= 1 ) + { + s_uiWaSpace = s_uiWaMax = s_uiWaNumMax = 0; + hb_xfree( s_WaList ); + hb_xfree( s_WaNums ); + s_WaList = NULL; + s_WaNums = NULL; + } else { - pAreaNode = s_pWorkAreas; - while( pAreaNode ) + while ( uiWaPos < s_uiWaMax ) { - if( ( ( AREAP ) pAreaNode->pArea )->uiArea > s_uiCurrArea ) - { - /* Insert the new WorkArea node */ - s_pCurrArea->pPrev = pAreaNode->pPrev; - s_pCurrArea->pNext = pAreaNode; - pAreaNode->pPrev = s_pCurrArea; - if( s_pCurrArea->pPrev ) - s_pCurrArea->pPrev->pNext = s_pCurrArea; - else - s_pWorkAreas = s_pCurrArea; - break; - } - if( pAreaNode->pNext ) - pAreaNode = pAreaNode->pNext; - else - { - /* Append the new WorkArea node */ - pAreaNode->pNext = s_pCurrArea; - s_pCurrArea->pPrev = pAreaNode; - break; - } + s_WaList[ uiWaPos ] = s_WaList[ uiWaPos + 1 ]; + s_WaNums[ s_WaList[ uiWaPos ]->uiArea ] = uiWaPos; + uiWaPos++; + } + s_WaList[ s_uiWaMax ] = NULL; + if ( s_uiWaSpace - s_uiWaMax >= 256 ) + { + s_uiWaSpace = ( ( s_uiWaMax + 256 ) >> 8 ) << 8; + s_WaList = (AREAP *) hb_xrealloc( s_WaList, s_uiWaSpace * sizeof(AREAP) ); } } - return TRUE; + s_pCurrArea = NULL; + + UNLOCK_AREA } /* - * Find a field. + * Closes all WorkAreas. */ -USHORT hb_rddFieldIndex( AREAP pArea, char * szName ) +static void hb_rddCloseAll( void ) { - USHORT uiCount; - LPFIELD pField; + HB_THREAD_STUB - HB_TRACE(HB_TR_DEBUG, ("hb_rddFieldIndex(%s)", szName)); - uiCount = 0; - pField = pArea->lpFields; - while( pField ) + HB_TRACE(HB_TR_DEBUG, ("hb_rddCloseAll()")); + + if ( s_uiWaMax > 0 ) { - ++uiCount; - if( strcmp( szName, ( ( PHB_DYNS ) pField->sym )->pSymbol->szName ) == 0 ) - return uiCount; - pField = pField->lpfNext; + BOOL isParents = TRUE, isFinish = FALSE; + AREAP pArea; + USHORT uiIndex; + + LOCK_AREA + + while( isParents ) + { + isParents = FALSE; + for ( uiIndex = 1; uiIndex < s_uiWaMax; uiIndex++ ) + { + pArea = s_WaList[ uiIndex ]; + HB_SET_WA( pArea->uiArea ); + if ( isFinish ) + { + SELF_RELEASE( pArea ); + s_WaNums[ s_uiCurrArea ] = 0; + s_pCurrArea = NULL; + } + else if( pArea->uiParents ) + { + isParents = TRUE; + } + else + { + SELF_CLOSE( pArea ); + } + } + if( !isParents && !isFinish ) + { + isParents = isFinish = TRUE; + } + } + + s_uiWaSpace = s_uiWaMax = s_uiWaNumMax = 0; + hb_xfree( s_WaList ); + hb_xfree( s_WaNums ); + s_WaList = NULL; + s_WaNums = NULL; + HB_SET_WA( 1 ); + + UNLOCK_AREA } - return 0; -} - - - -ERRCODE hb_rddIterateWorkAreas ( WACALLBACK pCallBack, int data ) -{ - LPAREANODE pAreaNode; - - HB_TRACE(HB_TR_DEBUG, ("hb_rddIterateWorkAreas(%p)", pCallBack)); - - pAreaNode = s_pWorkAreas; - while( pAreaNode ) - { - if ( ! (*pCallBack)( ( AREAP ) pAreaNode->pArea, data ) ) - break; - pAreaNode = pAreaNode->pNext; - } - return SUCCESS; } @@ -640,11 +723,176 @@ ERRCODE hb_rddIterateWorkAreas ( WACALLBACK pCallBack, int data ) * -- FUNCTIONS ACCESSED FROM VIRTUAL MACHINE -- */ +/* + * Shutdown the RDD system. + */ +void HB_EXPORT hb_rddShutDown( void ) +{ + USHORT uiCount; + + HB_TRACE(HB_TR_DEBUG, ("hb_rddShutDown()")); + + hb_rddCloseAll(); + + s_szDefDriver[ 0 ] = '\0'; + + if ( s_uiRddMax > 0 ) + { + for ( uiCount = 0; uiCount < s_uiRddMax; uiCount++ ) + { + if ( s_RddList[ uiCount ]->pTable.exit != NULL ) + { + SELF_EXIT( s_RddList[ uiCount ] ); + } + hb_xfree( s_RddList[ uiCount ] ); + } + hb_xfree( s_RddList ); + s_RddList = NULL; + + LOCK_AREA_DESTROY + } +} + +/* + * Insert the new WorkArea node + */ +USHORT HB_EXPORT hb_rddInsertAreaNode( char *szDriver ) +{ + HB_THREAD_STUB + + USHORT uiRddID, uiWaPos; + LPRDDNODE pRddNode; + + HB_TRACE(HB_TR_DEBUG, ("hb_rddInsertAreaNode(%s)", szDriver)); + + pRddNode = hb_rddFindNode( szDriver, &uiRddID ); + + if( !pRddNode ) + { + return FALSE; + } + + LOCK_AREA + + if ( s_uiCurrArea == 0 ) + { + USHORT uiArea = 1; + while ( uiArea < s_uiWaNumMax ) + { + if ( s_WaNums[ uiArea ] == 0 ) + break; + uiArea++; + } + HB_SET_WA( uiArea ); + } + else if( s_pCurrArea ) + { + return FALSE; + } + + if ( s_uiCurrArea >= s_uiWaNumMax ) + { + int iSize = ( ( s_uiCurrArea + 256 ) >> 8 ) << 8; + + if ( s_uiWaNumMax == 0 ) + { + s_WaNums = (USHORT *) hb_xgrab( iSize * sizeof(USHORT) ); + } + else + { + s_WaNums = (USHORT *) hb_xrealloc( s_WaNums, iSize * sizeof(USHORT) ); + } + memset( &s_WaNums[ s_uiWaNumMax ], 0, ( iSize - s_uiWaNumMax ) * sizeof(USHORT) ); + s_uiWaNumMax = iSize; + } + + if ( s_uiWaSpace == 0 ) + { + s_uiWaSpace = 256; + s_WaList = (AREAP *) hb_xgrab( s_uiWaSpace * sizeof(AREAP) ); + memset( &s_WaList[ 0 ], 0, s_uiWaSpace * sizeof(AREAP) ); + s_WaList[ 0 ] = NULL; + uiWaPos = 1; + s_uiWaMax = 2; + } + else + { + uiWaPos = s_uiWaMax++; + if ( s_uiWaMax > s_uiWaSpace ) + { + s_uiWaSpace = ( ( s_uiWaMax + 256 ) >> 8 ) << 8; + s_WaList = (AREAP *) hb_xrealloc( s_WaList, s_uiWaSpace * sizeof(AREAP) ); + memset( &s_WaList[ s_uiWaMax ], 0, ( s_uiWaSpace - s_uiWaMax ) * sizeof(AREAP) ); + } + while ( uiWaPos > 1 ) + { + if ( s_WaList[ uiWaPos - 1 ]->uiArea < s_uiCurrArea ) + break; + s_WaList[ uiWaPos ] = s_WaList[ uiWaPos - 1 ]; + s_WaNums[ s_WaList[ uiWaPos ]->uiArea ] = uiWaPos; + uiWaPos--; + } + } + s_WaList[ uiWaPos ] = hb_rddNewAreaNode( pRddNode, uiRddID ); + s_WaNums[ s_uiCurrArea ] = uiWaPos; + s_WaList[ uiWaPos ]->uiArea = s_uiCurrArea; + s_pCurrArea = s_WaList[ uiWaPos ]; + + UNLOCK_AREA + + return TRUE; +} + +/* + * allocate and return atomAlias for new workarea or NULL if alias already exist + */ +HB_EXPORT void * hb_rddAllocWorkAreaAlias( char * szAlias, int iArea ) +{ + PHB_DYNS pSymAlias; + int iDummyArea; + + HB_TRACE(HB_TR_DEBUG, ("hb_rddAllocWorkAreaAlias(%s, %d)", szAlias, iArea)); + + /* Verify if the alias name is valid symbol */ + if( hb_rddVerifyAliasName( szAlias ) != SUCCESS ) + { + hb_errRT_DBCMD_Ext( EG_BADALIAS, EDBCMD_BADALIAS, NULL, szAlias, EF_CANDEFAULT ); + return NULL; + } + /* Verify if the alias is already in use */ + if( hb_rddGetAliasNumber( szAlias, &iDummyArea ) == SUCCESS ) + { + hb_errRT_DBCMD_Ext( EG_DUPALIAS, EDBCMD_DUPALIAS, NULL, szAlias, EF_CANDEFAULT ); + return NULL; + } + + LOCK_AREA + pSymAlias = hb_dynsymGet( szAlias ); + if( pSymAlias->hArea ) + { + pSymAlias = NULL; + } + else + { + pSymAlias->hArea = iArea; + } + UNLOCK_AREA + + if( ! pSymAlias ) + { + hb_errRT_DBCMD_Ext( EG_DUPALIAS, EDBCMD_DUPALIAS, NULL, szAlias, EF_CANDEFAULT ); + } + + return pSymAlias; +} + /* * Return the current WorkArea number. */ -int hb_rddGetCurrentWorkAreaNumber( void ) +int HB_EXPORT hb_rddGetCurrentWorkAreaNumber( void ) { + HB_THREAD_STUB + HB_TRACE(HB_TR_DEBUG, ("hb_rddGetCurrentWorkAreaNumber()")); return s_uiCurrArea; @@ -653,32 +901,30 @@ int hb_rddGetCurrentWorkAreaNumber( void ) /* * Select a WorkArea by the number. */ -ERRCODE hb_rddSelectWorkAreaNumber( int iArea ) +ERRCODE HB_EXPORT hb_rddSelectWorkAreaNumber( int iArea ) { - LPAREANODE pAreaNode; + HB_THREAD_STUB HB_TRACE(HB_TR_DEBUG, ("hb_rddSelectWorkAreaNumber(%d)", iArea)); - s_uiCurrArea = iArea; - - pAreaNode = s_pWorkAreas; - while( pAreaNode ) + LOCK_AREA + if ( iArea < 1 || iArea > HARBOUR_MAX_RDD_AREA_NUM ) { - if( ( ( AREAP ) pAreaNode->pArea )->uiArea == s_uiCurrArea ) - { - s_pCurrArea = pAreaNode; /* Select a valid WorkArea */ - return SUCCESS; - } - pAreaNode = pAreaNode->pNext; + HB_SET_WA( 0 ); } - s_pCurrArea = NULL; /* Selected WorkArea is closed */ - return FAILURE; + else + { + HB_SET_WA( iArea ); + } + UNLOCK_AREA + + return ( HB_CURRENT_WA == NULL ) ? FAILURE : SUCCESS; } /* * Select a WorkArea by the symbol name. */ -ERRCODE hb_rddSelectWorkAreaSymbol( PHB_SYMB pSymAlias ) +ERRCODE HB_EXPORT hb_rddSelectWorkAreaSymbol( PHB_SYMB pSymAlias ) { ERRCODE bResult; char * szName; @@ -686,13 +932,17 @@ ERRCODE hb_rddSelectWorkAreaSymbol( PHB_SYMB pSymAlias ) HB_TRACE(HB_TR_DEBUG, ("hb_rddSelectWorkAreaSymbol(%p)", pSymAlias)); if( pSymAlias->pDynSym->hArea ) + { bResult = hb_rddSelectWorkAreaNumber( pSymAlias->pDynSym->hArea ); + } else { szName = pSymAlias->pDynSym->pSymbol->szName; - if( strlen( szName ) == 1 && toupper( szName[ 0 ] ) >= 'A' && toupper( szName[ 0 ] ) <= 'K' ) + if( szName[ 0 ] && ! szName[ 1 ] && toupper( szName[ 0 ] ) >= 'A' && toupper( szName[ 0 ] ) <= 'K' ) + { bResult = hb_rddSelectWorkAreaNumber( toupper( szName[ 0 ] ) - 'A' + 1 ); + } else { /* @@ -702,75 +952,69 @@ ERRCODE hb_rddSelectWorkAreaSymbol( PHB_SYMB pSymAlias ) USHORT uiAction = E_RETRY; HB_ITEM_PTR pError; - pError = hb_errRT_New( ES_ERROR, NULL, EG_NOALIAS, EDBCMD_NOALIAS, - NULL, pSymAlias->szName, 0, EF_CANRETRY ); + pError = hb_errRT_New( ES_ERROR, NULL, EG_NOALIAS, EDBCMD_NOALIAS, NULL, pSymAlias->szName, 0, EF_CANRETRY ); bResult = FAILURE; while( uiAction == E_RETRY ) { uiAction = hb_errLaunch( pError ); + if( uiAction == E_RETRY ) + { if( pSymAlias->pDynSym->hArea ) { bResult = hb_rddSelectWorkAreaNumber( pSymAlias->pDynSym->hArea ); uiAction = E_DEFAULT; } + } } - hb_errRelease( pError ); + + hb_itemRelease( pError ); } } + return bResult; } /* * Select a WorkArea by the name. */ -ERRCODE hb_rddSelectWorkAreaAlias( char * szName ) +ERRCODE HB_EXPORT hb_rddSelectWorkAreaAlias( char * szAlias ) { ERRCODE bResult; - ULONG ulLen; - PHB_DYNS pSymArea; - USHORT uiAction; - HB_ITEM_PTR pError; + int iArea; - HB_TRACE(HB_TR_DEBUG, ("hb_rddSelectWorkAreaAlias(%s)", szName)); + HB_TRACE(HB_TR_DEBUG, ("hb_rddSelectWorkAreaAlias(%s)", szAlias)); - ulLen = strlen( szName ); - if( ulLen >= 1 && toupper( szName[ 0 ] ) > '0' && toupper( szName[ 0 ] ) <= '9' ) - bResult = hb_rddSelectWorkAreaNumber( atoi( szName ) ); - else if( ulLen == 1 && toupper( szName[ 0 ] ) >= 'A' && toupper( szName[ 0 ] ) <= 'K' ) - bResult = hb_rddSelectWorkAreaNumber( toupper( szName[ 0 ] ) - 'A' + 1 ); - else + bResult = hb_rddGetAliasNumber( szAlias, &iArea ); + + if ( bResult == FAILURE ) { - pSymArea = hb_dynsymFindName( szName ); - if( pSymArea && pSymArea->hArea ) - bResult = hb_rddSelectWorkAreaNumber( pSymArea->hArea ); - else - { - /* - * generate an error with retry possibility - * (user created error handler can open a missing database) - */ - uiAction = E_RETRY; - pError = hb_errRT_New( ES_ERROR, NULL, EG_NOALIAS, EDBCMD_NOALIAS, - NULL, szName, 0, EF_CANRETRY ); + /* + * generate an error with retry possibility + * (user created error handler can open a missing database) + */ + HB_ITEM_PTR pError = hb_errRT_New( ES_ERROR, NULL, EG_NOALIAS, EDBCMD_NOALIAS, NULL, szAlias, 0, EF_CANRETRY ); - bResult = FAILURE; - while( uiAction == E_RETRY ) + do + { + if( hb_errLaunch( pError ) != E_RETRY ) { - uiAction = hb_errLaunch( pError ); - if( uiAction == E_RETRY ) - { - pSymArea = hb_dynsymFindName( szName ); - if( pSymArea && pSymArea->hArea ) - { - bResult = hb_rddSelectWorkAreaNumber( pSymArea->hArea ); - uiAction = E_DEFAULT; - } - } + break; } - hb_errRelease( pError ); + bResult = hb_rddGetAliasNumber( szAlias, &iArea ); } + while( bResult == FAILURE ); + + hb_itemRelease( pError ); + } + + if ( bResult == SUCCESS ) + { + if( iArea < 1 || iArea > HARBOUR_MAX_RDD_AREA_NUM ) + bResult = hb_rddSelectFirstAvailable(); + else + bResult = hb_rddSelectWorkAreaNumber( iArea ); } return bResult; @@ -779,17 +1023,189 @@ ERRCODE hb_rddSelectWorkAreaAlias( char * szName ) /* * Function for getting current workarea pointer */ -void * hb_rddGetCurrentWorkAreaPointer( void ) +HB_EXPORT void * hb_rddGetCurrentWorkAreaPointer( void ) { + HB_THREAD_STUB + HB_TRACE(HB_TR_DEBUG, ("hb_rddGetCurrentWorkAreaPointer()")); - return ( s_pCurrArea )? s_pCurrArea->pArea:NULL; + return HB_CURRENT_WA; +} + +/* + * call a pCallBack function with all open workareas ### + */ +ERRCODE HB_EXPORT hb_rddIterateWorkAreas( WACALLBACK pCallBack, int data ) +{ + USHORT uiIndex; + + HB_TRACE(HB_TR_DEBUG, ("hb_rddIterateWorkAreas(%p)", pCallBack)); + + LOCK_AREA + for ( uiIndex = 1; uiIndex < s_uiWaMax; uiIndex++ ) + { + if ( ! (*pCallBack)( s_WaList[ uiIndex ], data ) ) + { + break; + } + } + UNLOCK_AREA + return SUCCESS; +} + +/* + * Find a field index by name + */ +USHORT HB_EXPORT hb_rddFieldIndex( AREAP pArea, char * szName ) +{ + USHORT uiCount = 0; + LPFIELD pField; + + HB_TRACE(HB_TR_DEBUG, ("hb_rddFieldIndex(%p, %s)", pArea, szName)); + + while( HB_ISSPACE( *szName ) ) + { + ++szName; + } + + if( *szName ) + { + char szSym[ HB_SYMBOL_NAME_LEN + 1 ]; + hb_strncpyUpperTrim( szSym, szName, HB_SYMBOL_NAME_LEN ); + + pField = pArea->lpFields; + while( pField ) + { + ++uiCount; + if( strcmp( szSym, ( ( PHB_DYNS ) pField->sym )->pSymbol->szName ) == 0 ) + return uiCount; + pField = pField->lpfNext; + } + } + return 0; +} + +/* + * find a field expression index, this function strips _FIELD->, FIELD->, + * alias-> prefixes + */ +USHORT HB_EXPORT hb_rddFieldExpIndex( AREAP pArea, char * szField ) +{ + int n; + + while( HB_ISSPACE( *szField ) ) + { + ++szField; + } + + if( strchr( szField, '>' ) != NULL ) + { + char szAlias[ HARBOUR_MAX_RDD_ALIAS_LENGTH + 1 ]; + int i, j, l; + + n = 0; + if ( SELF_ALIAS( pArea, ( BYTE * ) szAlias ) == SUCCESS ) + l = strlen( szAlias ); + else + l = 0; + + /* + * strip the _FIELD-> and FIELD-> prefix, it could be nested + * so repeat this process until all prefixes will be removed + */ + do + { + j = n; + if( hb_strnicmp( &szField[ n ], "FIELD", 5 ) == 0 ) + i = 5; + else if( hb_strnicmp( &szField[ n ], "_FIELD", 6 ) == 0 ) + i = 6; + else if( l > 0 && hb_strnicmp( &szField[ n ], szAlias, l ) == 0 ) + i = l; + else + i = 0; + + if( i > 0 ) + { + i += n; + while( HB_ISSPACE( szField[ i ] ) ) + i++; + if( szField[ i ] == '-' && szField[ i + 1 ] == '>' ) + { + n = i + 2; + while( szField[ n ] == ' ' ) + n++; + } + } + } + while ( n != j ); + szField = &szField[ n ]; + } + return hb_rddFieldIndex( pArea, szField ); } /* * Obtain the current value of a field. */ -ERRCODE hb_rddGetFieldValue( HB_ITEM_PTR pItem, PHB_SYMB pFieldSymbol ) +ERRCODE HB_EXPORT hb_rddFieldGet( HB_ITEM_PTR pItem, PHB_SYMB pFieldSymbol ) +{ + HB_THREAD_STUB + AREAP pArea = HB_CURRENT_WA; + + HB_TRACE(HB_TR_DEBUG, ("hb_rddFieldGet(%p, %p)", pItem, pFieldSymbol)); + + if( pArea ) + { + USHORT uiField = 1; + LPFIELD pField = pArea->lpFields; + PHB_DYNS pDynSym = pFieldSymbol->pDynSym; + + while( pField ) + { + if( ( PHB_DYNS ) pField->sym == pDynSym ) + { + return SELF_GETVALUE( pArea, uiField, pItem ); + } + ++uiField; + pField = pField->lpfNext; + } + } + return FAILURE; +} + +/* + * Assign a value to a field. + */ +ERRCODE HB_EXPORT hb_rddFieldPut( HB_ITEM_PTR pItem, PHB_SYMB pFieldSymbol ) +{ + HB_THREAD_STUB + AREAP pArea = HB_CURRENT_WA; + + HB_TRACE(HB_TR_DEBUG, ("hb_rddFieldPut(%p, %p)", pItem, pFieldSymbol)); + + if( pArea ) + { + USHORT uiField = 1; + LPFIELD pField = pArea->lpFields; + PHB_DYNS pDynSym = pFieldSymbol->pDynSym; + + while( pField ) + { + if( ( PHB_DYNS ) pField->sym == pDynSym ) + { + return SELF_PUTVALUE( pArea, uiField, pItem ); + } + ++uiField; + pField = pField->lpfNext; + } + } + return FAILURE; +} + +/* + * Obtain the current value of a field. + */ +ERRCODE HB_EXPORT hb_rddGetFieldValue( HB_ITEM_PTR pItem, PHB_SYMB pFieldSymbol ) { ERRCODE bSuccess; USHORT uiAction; @@ -798,6 +1214,7 @@ ERRCODE hb_rddGetFieldValue( HB_ITEM_PTR pItem, PHB_SYMB pFieldSymbol ) HB_TRACE(HB_TR_DEBUG, ("hb_rddGetFieldValue(%p, %p)", pItem, pFieldSymbol)); bSuccess = hb_rddFieldGet( pItem, pFieldSymbol ); + if( bSuccess == FAILURE ) { /* @@ -805,8 +1222,7 @@ ERRCODE hb_rddGetFieldValue( HB_ITEM_PTR pItem, PHB_SYMB pFieldSymbol ) * (user created error handler can make this field accessible) */ uiAction = E_RETRY; - pError = hb_errRT_New( ES_ERROR, NULL, EG_NOVAR, EDBCMD_NOVAR, - NULL, pFieldSymbol->szName, 0, EF_CANRETRY ); + pError = hb_errRT_New( ES_ERROR, NULL, EG_NOVAR, EDBCMD_NOVAR, NULL, pFieldSymbol->szName, 0, EF_CANRETRY ); while( uiAction == E_RETRY ) { @@ -814,11 +1230,14 @@ ERRCODE hb_rddGetFieldValue( HB_ITEM_PTR pItem, PHB_SYMB pFieldSymbol ) if( uiAction == E_RETRY ) { bSuccess = hb_rddFieldGet( pItem, pFieldSymbol ); + if( bSuccess == SUCCESS ) + { uiAction = E_DEFAULT; + } } } - hb_errRelease( pError ); + hb_itemRelease( pError ); } return bSuccess; } @@ -826,7 +1245,7 @@ ERRCODE hb_rddGetFieldValue( HB_ITEM_PTR pItem, PHB_SYMB pFieldSymbol ) /* * Assign a value to a field. */ -ERRCODE hb_rddPutFieldValue( HB_ITEM_PTR pItem, PHB_SYMB pFieldSymbol ) +ERRCODE HB_EXPORT hb_rddPutFieldValue( HB_ITEM_PTR pItem, PHB_SYMB pFieldSymbol ) { ERRCODE bSuccess; USHORT uiAction; @@ -835,6 +1254,7 @@ ERRCODE hb_rddPutFieldValue( HB_ITEM_PTR pItem, PHB_SYMB pFieldSymbol ) HB_TRACE(HB_TR_DEBUG, ("hb_rddPutFieldValue(%p, %p)", pItem, pFieldSymbol)); bSuccess = hb_rddFieldPut( pItem, pFieldSymbol ); + if( bSuccess == FAILURE ) { /* @@ -851,95 +1271,25 @@ ERRCODE hb_rddPutFieldValue( HB_ITEM_PTR pItem, PHB_SYMB pFieldSymbol ) if( uiAction == E_RETRY ) { bSuccess = hb_rddFieldPut( pItem, pFieldSymbol ); + if( bSuccess == SUCCESS ) + { uiAction = E_DEFAULT; + } } } - hb_errRelease( pError ); + hb_itemRelease( pError ); } return bSuccess; } /* - * Assign a value to a field. + * -- END OF FUNCTIONS ACCESSED FROM VIRTUAL MACHINE -- */ -ERRCODE hb_rddFieldPut( HB_ITEM_PTR pItem, PHB_SYMB pFieldSymbol ) -{ - LPFIELD pField; - USHORT uiField; - - HB_TRACE(HB_TR_DEBUG, ("hb_rddFieldPut(%p, %p)", pItem, pFieldSymbol)); - - if( s_pCurrArea ) - { - uiField = 1; - pField = ( ( AREAP ) s_pCurrArea->pArea )->lpFields; - while( pField ) - { - if( ( PHB_DYNS ) pField->sym == pFieldSymbol->pDynSym ) - { - SELF_PUTVALUE( ( AREAP ) s_pCurrArea->pArea, uiField, pItem ); - return SUCCESS; - } - pField = pField->lpfNext; - uiField++; - } - } - return FAILURE; -} /* - * Obtain the current value of a field. + * -- BASIC RDD METHODS -- */ -ERRCODE hb_rddFieldGet( HB_ITEM_PTR pItem, PHB_SYMB pFieldSymbol ) -{ - LPFIELD pField; - USHORT uiField; - - HB_TRACE(HB_TR_DEBUG, ("hb_rddFieldGet(%p, %p)", pItem, pFieldSymbol)); - - if( s_pCurrArea ) - { - uiField = 1; - pField = ( ( AREAP ) s_pCurrArea->pArea )->lpFields; - while( pField ) - { - if( ( PHB_DYNS ) pField->sym == pFieldSymbol->pDynSym ) - { - SELF_GETVALUE( ( AREAP ) s_pCurrArea->pArea, uiField, pItem ); - return SUCCESS; - } - pField = pField->lpfNext; - uiField++; - } - } - return FAILURE; -} - -/* - * Shutdown the RDD system. - */ -void hb_rddShutDown( void ) -{ - LPRDDNODE pRddNode; - - HB_TRACE(HB_TR_DEBUG, ("hb_rddShutDown()")); - - hb_rddCloseAll(); - if( s_szDefDriver ) - hb_xfree( s_szDefDriver ); - - s_szDefDriver = NULL; - - while( s_pRddList ) - { - pRddNode = s_pRddList; - s_pRddList = s_pRddList->pNext; - if ( pRddNode->pTable.exit != NULL ) - SELF_EXIT( pRddNode ); - hb_xfree( pRddNode ); - } -} /* * -- HARBOUR FUNCTIONS -- @@ -947,10 +1297,12 @@ void hb_rddShutDown( void ) HB_FUNC( AFIELDS ) { - PHB_ITEM pName, pType, pLen, pDec, pItem; + HB_THREAD_STUB + PHB_ITEM pName, pType, pLen, pDec; USHORT uiFields, uiArrayLen, uiCount; + AREAP pArea = HB_CURRENT_WA; - if( !s_pCurrArea ) + if( !pArea ) { hb_retni( 0 ); return; @@ -967,17 +1319,16 @@ HB_FUNC( AFIELDS ) } uiArrayLen = 0; - pItem = hb_itemNew( NULL ); - SELF_FIELDCOUNT( ( AREAP ) s_pCurrArea->pArea, &uiFields ); + SELF_FIELDCOUNT( pArea, &uiFields ); if( pName ) { uiArrayLen = ( USHORT ) hb_arrayLen( pName ); if( uiArrayLen > uiFields ) uiArrayLen = uiFields; - for( uiCount = 1; uiCount <= uiArrayLen; uiCount++ ) + for( uiCount = 1; uiCount <= uiArrayLen; ++uiCount ) { - SELF_FIELDINFO( ( AREAP ) s_pCurrArea->pArea, uiCount, DBS_NAME, pItem ); - hb_arraySet( pName, uiCount, pItem ); + SELF_FIELDINFO( pArea, uiCount, DBS_NAME, + hb_arrayGetItemPtr( pName, uiCount ) ); } } if( pType ) @@ -985,10 +1336,10 @@ HB_FUNC( AFIELDS ) uiArrayLen = ( USHORT ) hb_arrayLen( pType ); if( uiArrayLen > uiFields ) uiArrayLen = uiFields; - for( uiCount = 1; uiCount <= uiArrayLen; uiCount++ ) + for( uiCount = 1; uiCount <= uiArrayLen; ++uiCount ) { - SELF_FIELDINFO( ( AREAP ) s_pCurrArea->pArea, uiCount, DBS_TYPE, pItem ); - hb_arraySet( pType, uiCount, pItem ); + SELF_FIELDINFO( pArea, uiCount, DBS_TYPE, + hb_arrayGetItemPtr( pType, uiCount ) ); } } if( pLen ) @@ -996,10 +1347,10 @@ HB_FUNC( AFIELDS ) uiArrayLen = ( USHORT ) hb_arrayLen( pLen ); if( uiArrayLen > uiFields ) uiArrayLen = uiFields; - for( uiCount = 1; uiCount <= uiArrayLen; uiCount++ ) + for( uiCount = 1; uiCount <= uiArrayLen; ++uiCount ) { - SELF_FIELDINFO( ( AREAP ) s_pCurrArea->pArea, uiCount, DBS_LEN, pItem ); - hb_arraySet( pLen, uiCount, pItem ); + SELF_FIELDINFO( pArea, uiCount, DBS_LEN, + hb_arrayGetItemPtr( pLen, uiCount ) ); } } if( pDec ) @@ -1007,52 +1358,47 @@ HB_FUNC( AFIELDS ) uiArrayLen = ( USHORT ) hb_arrayLen( pDec ); if( uiArrayLen > uiFields ) uiArrayLen = uiFields; - for( uiCount = 1; uiCount <= uiArrayLen; uiCount++ ) + for( uiCount = 1; uiCount <= uiArrayLen; ++uiCount ) { - SELF_FIELDINFO( ( AREAP ) s_pCurrArea->pArea, uiCount, DBS_DEC, pItem ); - hb_arraySet( pDec, uiCount, pItem ); + SELF_FIELDINFO( pArea, uiCount, DBS_DEC, + hb_arrayGetItemPtr( pDec, uiCount ) ); } } - hb_itemRelease( pItem ); hb_retni( uiArrayLen ); } HB_FUNC( ALIAS ) { + HB_THREAD_STUB USHORT uiArea; - LPAREANODE pAreaNode; - char * szAlias; + AREAP pArea; uiArea = hb_parni( 1 ); - uiArea = uiArea ? uiArea : s_uiCurrArea; - pAreaNode = s_pWorkAreas; - while( pAreaNode ) + pArea = uiArea ? HB_GET_WA( uiArea ) : HB_CURRENT_WA; + if( pArea ) { - if( ( ( AREAP ) pAreaNode->pArea )->uiArea == uiArea ) + char szAlias[ HARBOUR_MAX_RDD_ALIAS_LENGTH + 1 ]; + + if ( SELF_ALIAS( pArea, ( BYTE * ) szAlias ) == SUCCESS ) { - if( ( ( AREAP ) pAreaNode->pArea )->atomAlias && - ( ( PHB_DYNS ) ( ( AREAP ) pAreaNode->pArea )->atomAlias )->hArea ) - { - szAlias = ( char * ) hb_xgrab( HARBOUR_MAX_RDD_ALIAS_LENGTH + 1 ); - SELF_ALIAS( ( AREAP ) pAreaNode->pArea, ( BYTE * ) szAlias ); - hb_retc( szAlias ); - hb_xfree( szAlias ); - return; - } - break; + hb_retc( szAlias ); + return; } - pAreaNode = pAreaNode->pNext; } hb_retc( NULL ); } HB_FUNC( DBEVAL ) { - DBEVALINFO pEvalInfo; + HB_THREAD_STUB - if( s_pCurrArea ) + DBEVALINFO pEvalInfo; + AREAP pArea = HB_CURRENT_WA; + + if( pArea ) { + memset( &pEvalInfo, 0, sizeof( DBEVALINFO ) ); pEvalInfo.itmBlock = hb_param( 1, HB_IT_BLOCK ); if( !pEvalInfo.itmBlock ) { @@ -1095,7 +1441,7 @@ HB_FUNC( DBEVAL ) return; } - SELF_DBEVAL( ( AREAP ) s_pCurrArea->pArea, &pEvalInfo ); + SELF_DBEVAL( pArea, &pEvalInfo ); } else hb_errRT_DBCMD( EG_NOTABLE, EDBCMD_NOTABLE, NULL, "DBEVAL" ); @@ -1103,47 +1449,45 @@ HB_FUNC( DBEVAL ) HB_FUNC( DBF ) { - LPAREANODE pAreaNode = s_pWorkAreas; - char * szAlias; + HB_THREAD_STUB + AREAP pArea = HB_CURRENT_WA; - while( pAreaNode ) + if( pArea ) { - if( ( ( AREAP ) pAreaNode->pArea )->uiArea == s_uiCurrArea ) + char szAlias[ HARBOUR_MAX_RDD_ALIAS_LENGTH + 1 ]; + + if ( SELF_ALIAS( pArea, ( BYTE * ) szAlias ) == SUCCESS ) { - if( ( ( AREAP ) pAreaNode->pArea )->atomAlias && - ( ( PHB_DYNS ) ( ( AREAP ) pAreaNode->pArea )->atomAlias )->hArea ) - { - szAlias = ( char * ) hb_xgrab( HARBOUR_MAX_RDD_ALIAS_LENGTH + 1 ); - SELF_ALIAS( ( AREAP ) pAreaNode->pArea, ( BYTE * ) szAlias ); - hb_retc( szAlias ); - hb_xfree( szAlias ); - return; - } - break; + hb_retc( szAlias ); + return; } - pAreaNode = pAreaNode->pNext; } hb_retc( NULL ); } HB_FUNC( BOF ) { + HB_THREAD_STUB BOOL bBof = TRUE; + AREAP pArea = HB_CURRENT_WA; + + if( pArea ) + SELF_BOF( pArea, &bBof ); - if( s_pCurrArea ) - SELF_BOF( ( AREAP ) s_pCurrArea->pArea, &bBof ); hb_retl( bBof ); } HB_FUNC( DBAPPEND ) { + HB_THREAD_STUB BOOL bUnLockAll; + AREAP pArea = HB_CURRENT_WA; - if( s_pCurrArea ) + if( pArea ) { bUnLockAll = ISLOG( 1 ) ? hb_parl( 1 ) : TRUE; s_bNetError = FALSE; - if( SELF_APPEND( ( AREAP ) s_pCurrArea->pArea, bUnLockAll ) == FAILURE ) + if( SELF_APPEND( pArea, bUnLockAll ) == FAILURE ) { s_bNetError = TRUE; /* Temp fix! What about other types of errors? */ } @@ -1154,8 +1498,11 @@ HB_FUNC( DBAPPEND ) HB_FUNC( DBCLEARFILTER ) { - if( s_pCurrArea ) - SELF_CLEARFILTER( ( AREAP ) s_pCurrArea->pArea ); + HB_THREAD_STUB + AREAP pArea = HB_CURRENT_WA; + + if( pArea ) + SELF_CLEARFILTER( pArea ); else hb_errRT_DBCMD( EG_NOTABLE, EDBCMD_NOTABLE, NULL, "DBCLEARFILTER" ); } @@ -1167,96 +1514,211 @@ HB_FUNC( DBCLOSEALL ) HB_FUNC( DBCLOSEAREA ) { - if( s_pCurrArea ) + HB_THREAD_STUB + + if( HB_CURRENT_WA ) + { hb_rddReleaseCurrentArea(); + } } HB_FUNC( DBCOMMIT ) { - if( s_pCurrArea ) - SELF_FLUSH( ( AREAP ) s_pCurrArea->pArea ); + HB_THREAD_STUB + AREAP pArea = HB_CURRENT_WA; + if( pArea ) + SELF_FLUSH( pArea ); else hb_errRT_DBCMD( EG_NOTABLE, EDBCMD_NOTABLE, NULL, "DBCOMMIT" ); } HB_FUNC( DBCOMMITALL ) { - LPAREANODE pAreaNode = s_pCurrArea; + HB_THREAD_STUB + USHORT uiArea = hb_rddGetCurrentWorkAreaNumber(), uiIndex; - s_pCurrArea = s_pWorkAreas; - while( s_pCurrArea ) + LOCK_AREA + for ( uiIndex = 1; uiIndex < s_uiWaMax; ++uiIndex ) { - SELF_FLUSH( ( AREAP ) s_pCurrArea->pArea ); - s_pCurrArea = s_pCurrArea->pNext; + hb_rddSelectWorkAreaNumber( s_WaList[ uiIndex ]->uiArea ); + SELF_FLUSH( HB_CURRENT_WA ); } - s_pCurrArea = pAreaNode; + UNLOCK_AREA + hb_rddSelectWorkAreaNumber( uiArea ); } -HB_FUNC( __DBCONTINUE ) +static ERRCODE hb_rddOpenTable( char * szFileName, char * szDriver, + USHORT uiArea, char *szAlias, + BOOL fShared, BOOL fReadonly, + char * szCpId, ULONG ulConnection ) { - if( !s_pCurrArea ) + char szDriverBuffer[ HARBOUR_MAX_RDD_DRIVERNAME_LENGTH + 1 ]; + DBOPENINFO pInfo; + ERRCODE errCode; + USHORT uiPrevArea; + AREAP pArea; + + s_bNetError = FALSE; + + if( szDriver && szDriver[ 0 ] ) { - hb_errRT_DBCMD( EG_NOTABLE, EDBCMD_NOTABLE, NULL, "DBCONTINUE" ); - return; + hb_strncpyUpper( szDriverBuffer, szDriver, HARBOUR_MAX_RDD_DRIVERNAME_LENGTH ); + szDriver = szDriverBuffer; + } + else + { + szDriver = s_szDefDriver; } - if( !( ( AREAP ) s_pCurrArea->pArea )->dbsi.itmCobFor ) - return; + uiPrevArea = hb_rddGetCurrentWorkAreaNumber(); - ( ( AREAP ) s_pCurrArea->pArea )->fFound = FALSE; - while( !( ( AREAP ) s_pCurrArea->pArea )->fFound ) + /* + * 0 means chose first available in hb_rddInsertAreaNode() + * This hack is necessary to avoid race condition in MT + * if we don't want to lock whole RDD subsystem, Druzus + */ + hb_rddSelectWorkAreaNumber( uiArea ); + if( uiArea ) { - SELF_SKIP( ( AREAP ) s_pCurrArea->pArea, 1 ); - if( ( ( AREAP ) s_pCurrArea->pArea )->fEof ) - return; - ( ( AREAP ) s_pCurrArea->pArea )->fFound = hb_itemGetL( hb_vmEvalBlock( ( ( AREAP ) s_pCurrArea->pArea )->dbsi.itmCobFor ) ); + hb_rddReleaseCurrentArea(); } + + s_bNetError = TRUE; + + /* Create a new WorkArea node */ + if( ! hb_rddInsertAreaNode( szDriver ) ) + { + hb_errRT_DBCMD( EG_ARG, EDBCMD_USE_BADPARAMETER, NULL, "DBUSEAREA" ); + return FAILURE; + } + pArea = ( AREAP ) hb_rddGetCurrentWorkAreaPointer(); + + /* Fill pInfo structure */ + pInfo.uiArea = pArea->uiArea; + pInfo.abName = ( BYTE * ) szFileName; + pInfo.atomAlias = ( BYTE * ) szAlias; + pInfo.fShared = fShared; + pInfo.fReadonly = fReadonly; + pInfo.cdpId = ( BYTE * ) szCpId; + pInfo.ulConnection = ulConnection; + pInfo.lpdbHeader = NULL; + + /* Open file */ + errCode = SELF_OPEN( pArea, &pInfo ); + + if( errCode != SUCCESS ) + { + hb_rddReleaseCurrentArea(); + hb_rddSelectWorkAreaNumber( uiPrevArea ); + } + + s_bNetError = errCode != SUCCESS; + + return errCode; +} + +static ERRCODE hb_rddCreateTable( char * szFileName, PHB_ITEM pStruct, + char * szDriver, + BOOL fKeepOpen, USHORT uiArea, char *szAlias, + char * szCpId, ULONG ulConnection ) +{ + char szDriverBuffer[ HARBOUR_MAX_RDD_DRIVERNAME_LENGTH + 1 ]; + DBOPENINFO pInfo; + ERRCODE errCode; + USHORT uiPrevArea; + AREAP pArea; + + if( szDriver && szDriver[ 0 ] ) + { + hb_strncpyUpper( szDriverBuffer, szDriver, HARBOUR_MAX_RDD_DRIVERNAME_LENGTH ); + szDriver = szDriverBuffer; + } + else + { + szDriver = s_szDefDriver; + } + + uiPrevArea = hb_rddGetCurrentWorkAreaNumber(); + + /* + * 0 means chose first available in hb_rddInsertAreaNode() + * This hack is necessary to avoid race condition in MT + * if we don't want to lock whole RDD subsystem, Druzus + */ + hb_rddSelectWorkAreaNumber( uiArea ); + if( uiArea ) + { + hb_rddReleaseCurrentArea(); + } + + s_bNetError = TRUE; + + /* Create a new WorkArea node */ + if( ! hb_rddInsertAreaNode( szDriver ) ) + { + hb_errRT_DBCMD( EG_CREATE, EDBCMD_BADPARAMETER, NULL, "DBCREATE" ); + return FAILURE; + } + pArea = ( AREAP ) hb_rddGetCurrentWorkAreaPointer(); + + /* Fill pInfo structure */ + pInfo.uiArea = pArea->uiArea; + pInfo.abName = ( BYTE * ) szFileName; + pInfo.atomAlias = ( BYTE * ) szAlias; + pInfo.fShared = FALSE; + pInfo.fReadonly = FALSE; + pInfo.cdpId = ( BYTE * ) szCpId; + pInfo.ulConnection = ulConnection; + pInfo.lpdbHeader = NULL; + + errCode = SELF_CREATEFIELDS( pArea, pStruct ); + if( errCode == SUCCESS ) + errCode = SELF_CREATE( pArea, &pInfo ); + + if( !fKeepOpen || errCode != SUCCESS ) + { + hb_rddReleaseCurrentArea(); + hb_rddSelectWorkAreaNumber( uiPrevArea ); + } + + s_bNetError = errCode != SUCCESS; + + return errCode; } HB_FUNC( DBCREATE ) { - char * szDriver, * szFileName; - char cDriverBuffer[ HARBOUR_MAX_RDD_DRIVERNAME_LENGTH ]; - char szAlias[ HARBOUR_MAX_RDD_ALIAS_LENGTH + 1 ]; - char szAliasTmp[ HARBOUR_MAX_RDD_ALIAS_LENGTH + 1 ]; - char szSavedFileName[ _POSIX_PATH_MAX + 1 ]; - USHORT uiSize, uiLen, uiPrevArea; - DBOPENINFO pInfo; - PHB_FNAME pFileName; - PHB_ITEM pStruct, pFieldDesc, pFileExt; - BOOL bOpen; - BYTE * codePageId = (BYTE*) hb_parc(6); + char * szFileName; + USHORT uiSize, uiLen; + PHB_ITEM pStruct, pFieldDesc; + BOOL fKeepOpen, fCurrArea; - hb_ret(); - - if( ISCHAR(1) ) - szFileName = hb_parc( 1 ); - else - szFileName = ""; + /* + * NOTE: 4-th and 5-th parameters are undocumented Clipper ones + * 4-th is boolean flag indicating if file should stay open and + * 5-th is alias - if not given then WA is open without alias + */ + szFileName = hb_parc( 1 ); pStruct = hb_param( 2 , HB_IT_ARRAY ); - if( pStruct ) - uiLen = ( USHORT ) hb_arrayLen( pStruct ); - else - uiLen = 0; + fKeepOpen = ISLOG( 4 ); + fCurrArea = fKeepOpen && !hb_parl( 4 ); - if( ( strlen( szFileName ) == 0 ) || !pStruct || uiLen == 0 ) + if( !pStruct || hb_arrayLen( pStruct ) == 0 || + !szFileName || !szFileName[ 0 ] ) { hb_errRT_DBCMD( EG_ARG, EDBCMD_DBCMDBADPARAMETER, NULL, "DBCREATE" ); return; } + uiLen = ( USHORT ) hb_arrayLen( pStruct ); - for( uiSize = 0; uiSize < uiLen; uiSize++ ) + for( uiSize = 1; uiSize <= uiLen; ++uiSize ) { - pFieldDesc = hb_arrayGetItemPtr( pStruct, uiSize + 1 ); - if( hb_arrayLen( pFieldDesc ) < 4 ) - { - hb_errRT_DBCMD( EG_ARG, EDBCMD_DBCMDBADPARAMETER, NULL, "DBCREATE" ); - return; - } + pFieldDesc = hb_arrayGetItemPtr( pStruct, uiSize ); /* Validate items types of fields */ - if( !( hb_arrayGetType( pFieldDesc, 1 ) & HB_IT_STRING ) || + if( hb_arrayLen( pFieldDesc ) < 4 || + !( hb_arrayGetType( pFieldDesc, 1 ) & HB_IT_STRING ) || !( hb_arrayGetType( pFieldDesc, 2 ) & HB_IT_STRING ) || !( hb_arrayGetType( pFieldDesc, 3 ) & HB_IT_NUMERIC ) || !( hb_arrayGetType( pFieldDesc, 4 ) & HB_IT_NUMERIC ) ) @@ -1266,177 +1728,37 @@ HB_FUNC( DBCREATE ) } } - uiPrevArea = s_uiCurrArea; - if( !ISLOG( 4 ) ) - { - bOpen = FALSE; - hb_rddSelectFirstAvailable(); - } - else - { - bOpen = TRUE; - if( hb_parl( 4 ) ) - hb_rddSelectFirstAvailable(); - else if( s_pCurrArea ) /* If current WorkArea is used then close it */ - hb_rddReleaseCurrentArea(); - } - - hb_rddCheck(); - if( ISCHAR(3) && hb_parclen( 3 ) ) - { - hb_strncpyUpper( cDriverBuffer, hb_parc( 3 ), - min( hb_parclen( 3 ), HARBOUR_MAX_RDD_DRIVERNAME_LENGTH ) ); - szDriver = cDriverBuffer; - } - else - szDriver = s_szDefDriver; - - pFileName = hb_fsFNameSplit( szFileName ); - - szAlias[0] = '\0'; - if( ISCHAR(5) ) - strncat( szAlias, hb_parc( 5 ), HARBOUR_MAX_RDD_ALIAS_LENGTH ); - - uiLen = strlen( szAlias ); - if( uiLen == 0 ) - strncat( szAlias, pFileName->szName, HARBOUR_MAX_RDD_ALIAS_LENGTH ); - else if( uiLen == 1 ) - { - /* Alias with a single letter. Only are valid 'L' and > 'M' */ - if( toupper( szAlias[ 0 ] ) < 'N' && toupper( szAlias[ 0 ] ) != 'L' ) - { - hb_xfree( pFileName ); - hb_errRT_DBCMD( EG_DUPALIAS, EDBCMD_DUPALIAS, NULL, "DBCREATE" ); - return; - } - } - - if ( hb_rddGetTempAlias( szAliasTmp ) ) - { - hb_xfree( pFileName ); - hb_errRT_DBCMD( EG_ARG, EDBCMD_BADPARAMETER, NULL, "DBCREATE" ); - return; - } - - /* Create a new WorkArea node */ - if( !hb_rddInsertAreaNode( szDriver ) ) - { - hb_xfree( pFileName ); - hb_errRT_DBCMD( EG_ARG, EDBCMD_BADPARAMETER, NULL, "DBCREATE" ); - return; - } - - szFileName = ( char * ) hb_xgrab( _POSIX_PATH_MAX + 1 ); - szFileName[0] = '\0'; - - if( ISCHAR(1) ) - strncat( szFileName, hb_parc( 1 ), _POSIX_PATH_MAX ); - - if( !pFileName->szExtension ) - { - pFileExt = hb_itemPutC( NULL, "" ); - SELF_INFO( ( AREAP ) s_pCurrArea->pArea, DBI_TABLEEXT, pFileExt ); - strncat( szFileName, hb_itemGetCPtr( pFileExt ), _POSIX_PATH_MAX - strlen( szFileName ) ); - hb_itemRelease( pFileExt ); - } - - hb_xfree( pFileName ); - - /* Save filename for later use */ - strcpy( szSavedFileName, szFileName ); - - /* Fill pInfo structure */ - pInfo.uiArea = s_uiCurrArea; - pInfo.abName = ( BYTE * ) szFileName; - /* pInfo.atomAlias = ( BYTE * ) szAlias; */ - pInfo.atomAlias = ( BYTE * ) szAliasTmp; - pInfo.fShared = FALSE; - pInfo.fReadonly = FALSE; - - /* ( ( AREAP ) s_pCurrArea->pArea )->atomAlias = hb_dynsymGet( ( char * ) szAlias ); */ - ( ( AREAP ) s_pCurrArea->pArea )->atomAlias = hb_dynsymGet( ( char * ) szAliasTmp ); - ( ( PHB_DYNS ) ( ( AREAP ) s_pCurrArea->pArea )->atomAlias )->hArea = s_uiCurrArea; - ( ( AREAP ) s_pCurrArea->pArea )->uiArea = s_uiCurrArea; - - if( SELF_CREATEFIELDS( ( AREAP ) s_pCurrArea->pArea, pStruct ) == FAILURE ) - { - hb_xfree( szFileName ); - hb_rddReleaseCurrentArea(); - hb_errRT_DBCMD( EG_ARG, EDBCMD_BADPARAMETER, NULL, "DBCREATE" ); - return; - } - - if( SELF_CREATE( ( AREAP ) s_pCurrArea->pArea, &pInfo ) == FAILURE ) - { - hb_xfree( szFileName ); - hb_rddReleaseCurrentArea(); - hb_errRT_DBCMD( EG_ARG, EDBCMD_BADPARAMETER, NULL, "DBCREATE" ); - return; - } - - hb_xfree( szFileName ); - if( !bOpen ) - { - hb_rddReleaseCurrentArea(); - hb_rddSelectWorkAreaNumber( uiPrevArea ); - } - else - { - USHORT uiAreaSize, uiRddID; - struct _RDDFUNCS * lprfsHost = ( ( AREAP ) s_pCurrArea->pArea )->lprfsHost; - - uiRddID = ( ( AREAP ) s_pCurrArea->pArea )->rddID; - SELF_STRUCTSIZE( ( AREAP ) s_pCurrArea->pArea, &uiAreaSize ); - - /* Close and release WorkArea */ - SELF_CLOSE( ( AREAP ) s_pCurrArea->pArea ); - SELF_RELEASE( ( AREAP ) s_pCurrArea->pArea ); - - /* Prepare WorkArea and open it */ - s_pCurrArea->pArea = ( AREAP ) hb_xgrab( uiAreaSize ); - memset( s_pCurrArea->pArea, 0, uiAreaSize ); - ( ( AREAP ) s_pCurrArea->pArea )->lprfsHost = lprfsHost; - ( ( AREAP ) s_pCurrArea->pArea )->rddID = uiRddID; - SELF_NEW( ( AREAP ) s_pCurrArea->pArea ); - - /*pInfo.abName = ( BYTE * ) hb_xgrab( _POSIX_PATH_MAX + 1 ); */ - szFileName = ( char * ) hb_xgrab( _POSIX_PATH_MAX + 1 ); - pInfo.abName = ( BYTE * ) szFileName; - pInfo.atomAlias = ( BYTE * ) szAlias; - strcpy( ( char * ) pInfo.abName, szSavedFileName ); - pInfo.fShared = !hb_set.HB_SET_EXCLUSIVE; - pInfo.cdpId = codePageId; - ( ( AREAP ) s_pCurrArea->pArea )->uiArea = s_uiCurrArea; - if( SELF_OPEN( ( AREAP ) s_pCurrArea->pArea, &pInfo ) == FAILURE ) - { - s_bNetError = TRUE; /* Temp fix! What about other types of errors? */ - hb_rddReleaseCurrentArea(); - } - else - hb_ret(); - /*hb_xfree( pInfo.abName ); */ - hb_xfree( szFileName ); - } - /*hb_xfree( szFileName ); */ + hb_rddCreateTable( szFileName, pStruct, hb_parc( 3 ), fKeepOpen, + fCurrArea ? hb_rddGetCurrentWorkAreaNumber() : 0, + hb_parc( 5 ), hb_parc( 6 ), hb_parnl( 7 ) ); } HB_FUNC( DBDELETE ) { - if( s_pCurrArea ) - SELF_DELETE( ( AREAP ) s_pCurrArea->pArea ); + HB_THREAD_STUB + AREAP pArea = HB_CURRENT_WA; + + if( pArea ) + { + SELF_DELETE( pArea ); + } else + { hb_errRT_DBCMD( EG_NOTABLE, EDBCMD_NOTABLE, NULL, "DBDELETE" ); + } } HB_FUNC( DBFILTER ) { - PHB_ITEM pFilter; + HB_THREAD_STUB + AREAP pArea = HB_CURRENT_WA; - if( s_pCurrArea ) + if( pArea ) { - pFilter = hb_itemPutC( NULL, "" ); - SELF_FILTERTEXT( ( AREAP ) s_pCurrArea->pArea, pFilter ); - hb_retc( hb_itemGetCPtr( pFilter ) ); + PHB_ITEM pFilter = hb_itemNew( NULL ); + hb_itemPutC( pFilter, "" ); + SELF_FILTERTEXT( pArea, pFilter ); + hb_itemReturn( pFilter ); hb_itemRelease( pFilter ); } else @@ -1445,17 +1767,22 @@ HB_FUNC( DBFILTER ) HB_FUNC( DBGOBOTTOM ) { - if( s_pCurrArea ) - SELF_GOBOTTOM( ( AREAP ) s_pCurrArea->pArea ); + HB_THREAD_STUB + AREAP pArea = HB_CURRENT_WA; + + if( pArea ) + SELF_GOBOTTOM( pArea ); else hb_errRT_DBCMD( EG_NOTABLE, EDBCMD_NOTABLE, NULL, "DBGOBOTTOM" ); } HB_FUNC( DBGOTO ) { + HB_THREAD_STUB PHB_ITEM pItem; + AREAP pArea = HB_CURRENT_WA; - if( !s_pCurrArea ) + if( !pArea ) { hb_errRT_DBCMD( EG_NOTABLE, EDBCMD_NOTABLE, NULL, "DBGOTO" ); return; @@ -1465,222 +1792,95 @@ HB_FUNC( DBGOTO ) if( !pItem ) hb_errRT_DBCMD( EG_ARG, EDBCMD_NOVAR, NULL, "DBGOTO" ); else - SELF_GOTOID( ( AREAP ) s_pCurrArea->pArea, pItem ); + SELF_GOTOID( pArea, pItem ); hb_ret(); } HB_FUNC( DBGOTOP ) { - if( s_pCurrArea ) - SELF_GOTOP( ( AREAP ) s_pCurrArea->pArea ); + HB_THREAD_STUB + AREAP pArea = HB_CURRENT_WA; + + if( pArea ) + SELF_GOTOP( pArea ); else hb_errRT_DBCMD( EG_NOTABLE, EDBCMD_NOTABLE, NULL, "DBGOTOP" ); } HB_FUNC( __DBLOCATE ) { - PHB_ITEM pFor, pNewFor, pWhile, pNext, pRecord, pRest, pNewRest; - DBSCOPEINFO pScopeInfo; - ULONG lNext; - BOOL bFor, bWhile; + HB_THREAD_STUB + DBSCOPEINFO dbScopeInfo; + AREAP pArea = HB_CURRENT_WA; - if( !s_pCurrArea ) + if( !pArea ) { hb_errRT_DBCMD( EG_NOTABLE, EG_NOTABLE, NULL, "__DBLOCATE" ); return; } - ( ( AREAP ) s_pCurrArea->pArea )->fFound = FALSE; - memset( &pScopeInfo, 0, sizeof( DBSCOPEINFO ) ); - pFor = hb_param( 1, HB_IT_BLOCK ); - pWhile = hb_param( 2, HB_IT_BLOCK ); - pNext = hb_param( 3, HB_IT_NUMERIC ); - pRecord = hb_param( 4, HB_IT_NUMERIC ); - pRest = hb_param( 5, HB_IT_LOGICAL ); - pNewRest = NULL; - if( pWhile ) - { - pNewRest = hb_itemPutL( NULL, TRUE ); - pScopeInfo.fRest = pNewRest; - } - if( !pFor ) - pNewFor = hb_itemPutL( NULL, TRUE ); - else - pNewFor = hb_itemNew( pFor ); - pScopeInfo.itmCobFor = pNewFor; - if( !pRest ) - { - pNewRest = hb_itemPutL( pNewRest, FALSE ); - pScopeInfo.fRest = pNewRest; - } - SELF_SETLOCATE( ( AREAP ) s_pCurrArea->pArea, &pScopeInfo ); - ( ( AREAP ) s_pCurrArea->pArea )->fFound = FALSE; - if( pRecord ) - { - SELF_GOTOID( ( AREAP ) s_pCurrArea->pArea, pRecord ); - if( ( ( AREAP ) s_pCurrArea->pArea )->fEof ) - goto ExitLocate ; - if( hb_itemType( pWhile ) == HB_IT_BLOCK ) - bWhile = hb_itemGetL( hb_vmEvalBlock( pWhile ) ); - else - bWhile = TRUE; - if( hb_itemType( pNewFor ) == HB_IT_BLOCK ) - { - bFor = hb_itemGetL( hb_vmEvalBlock( pNewFor ) ); - ( ( AREAP ) s_pCurrArea->pArea )->fFound = ( bWhile && bFor ); - } - else - ( ( AREAP ) s_pCurrArea->pArea )->fFound = ( bWhile && hb_itemGetL( pNewFor ) ); - } - else if( pWhile ) - { - if( hb_itemType( pWhile ) == HB_IT_BLOCK ) - bWhile = hb_itemGetL( hb_vmEvalBlock( pWhile ) ); - else - bWhile = TRUE; - if( hb_itemType( pNewFor ) == HB_IT_BLOCK ) - bFor = hb_itemGetL( hb_vmEvalBlock( pNewFor ) ); - else - bFor = hb_itemGetL( pNewFor ); - if( pNext ) - lNext = hb_parnl( 3 ); - else - lNext = 0xffffffffu; /* maxed out */ - while( !( ( AREAP ) s_pCurrArea->pArea )->fEof && lNext-- != 0 && bWhile && !bFor ) - { - SELF_SKIP( ( AREAP ) s_pCurrArea->pArea, 1 ); - if( ( ( AREAP ) s_pCurrArea->pArea )->fEof ) - bFor = FALSE; - else - { - if( hb_itemType( pWhile ) == HB_IT_BLOCK ) - bWhile = hb_itemGetL( hb_vmEvalBlock( pWhile ) ); - else - bWhile = TRUE; - if( hb_itemType( pNewFor ) == HB_IT_BLOCK ) - bFor = hb_itemGetL( hb_vmEvalBlock( pNewFor ) ); - else - bFor = hb_itemGetL( pNewFor ); - } - } - ( ( AREAP ) s_pCurrArea->pArea )->fFound = bFor; - } - else if( pNext ) - { - lNext = hb_parnl( 3 ); - if( ( ( AREAP ) s_pCurrArea->pArea )->fEof || lNext <= 0 ) - goto ExitLocate ; - if( hb_itemType( pWhile ) == HB_IT_BLOCK ) - bWhile = hb_itemGetL( hb_vmEvalBlock( pWhile ) ); - else - bWhile = TRUE; - if( hb_itemType( pNewFor ) == HB_IT_BLOCK ) - bFor = hb_itemGetL( hb_vmEvalBlock( pNewFor ) ); - else - bFor = hb_itemGetL( pNewFor ); - while( !( ( AREAP ) s_pCurrArea->pArea )->fEof && lNext-- > 0 && bWhile && !bFor ) - { - SELF_SKIP( ( AREAP ) s_pCurrArea->pArea, 1 ); - if( ( ( AREAP ) s_pCurrArea->pArea )->fEof ) - bFor = FALSE; - else - { - if( hb_itemType( pWhile ) == HB_IT_BLOCK ) - bWhile = hb_itemGetL( hb_vmEvalBlock( pWhile ) ); - else - bWhile = TRUE; - if( hb_itemType( pNewFor ) == HB_IT_BLOCK ) - bFor = hb_itemGetL( hb_vmEvalBlock( pNewFor ) ); - else - bFor = hb_itemGetL( pNewFor ); - } - } - ( ( AREAP ) s_pCurrArea->pArea )->fFound = bFor; - } - else if( hb_itemGetL( pRest ) ) - { - if( ( ( AREAP ) s_pCurrArea->pArea )->fEof ) - goto ExitLocate ; - if( hb_itemType( pWhile ) == HB_IT_BLOCK ) - bWhile = hb_itemGetL( hb_vmEvalBlock( pWhile ) ); - else - bWhile = TRUE; - if( hb_itemType( pNewFor ) == HB_IT_BLOCK ) - bFor = hb_itemGetL( hb_vmEvalBlock( pNewFor ) ); - else - bFor = hb_itemGetL( pNewFor ); - while( !( ( AREAP ) s_pCurrArea->pArea )->fEof && bWhile && !bFor ) - { - SELF_SKIP( ( AREAP ) s_pCurrArea->pArea, 1 ); - if( ( ( AREAP ) s_pCurrArea->pArea )->fEof ) - bFor = FALSE; - else - { - if( hb_itemType( pWhile ) == HB_IT_BLOCK ) - bWhile = hb_itemGetL( hb_vmEvalBlock( pWhile ) ); - else - bWhile = TRUE; - if( hb_itemType( pNewFor ) == HB_IT_BLOCK ) - bFor = hb_itemGetL( hb_vmEvalBlock( pNewFor ) ); - else - bFor = hb_itemGetL( pNewFor ); - } - } - ( ( AREAP ) s_pCurrArea->pArea )->fFound = bFor; - } - else - { - SELF_GOTOP( ( AREAP ) s_pCurrArea->pArea ); - if( ( ( AREAP ) s_pCurrArea->pArea )->fEof ) - goto ExitLocate ; - if( hb_itemType( pNewFor ) == HB_IT_BLOCK ) - bFor = hb_itemGetL( hb_vmEvalBlock( pNewFor ) ); - else - bFor = hb_itemGetL( pNewFor ); - while( !( ( AREAP ) s_pCurrArea->pArea )->fEof && !bFor ) - { - SELF_SKIP( ( AREAP ) s_pCurrArea->pArea, 1 ); - if( ( ( AREAP ) s_pCurrArea->pArea )->fEof ) - bFor = FALSE; - else - { - if( hb_itemType( pNewFor ) == HB_IT_BLOCK ) - bFor = hb_itemGetL( hb_vmEvalBlock( pNewFor ) ); - else - bFor = hb_itemGetL( pNewFor ); - } - } - ( ( AREAP ) s_pCurrArea->pArea )->fFound = bFor; - } + dbScopeInfo.itmCobFor = hb_param( 1, HB_IT_BLOCK ); + dbScopeInfo.lpstrFor = NULL; + dbScopeInfo.itmCobWhile = hb_param( 2, HB_IT_BLOCK ); + dbScopeInfo.lpstrWhile = NULL; + dbScopeInfo.lNext = hb_param( 3, HB_IT_NUMERIC ); + dbScopeInfo.itmRecID = hb_param( 4, HB_IT_NUMERIC ); + dbScopeInfo.fRest = hb_param( 5, HB_IT_LOGICAL ); -ExitLocate : - /* Release items */ - hb_itemRelease( pNewFor ); - hb_itemRelease( pNewRest ); + dbScopeInfo.fIgnoreFilter = TRUE; + dbScopeInfo.fIncludeDeleted = TRUE; + dbScopeInfo.fLast = FALSE; + dbScopeInfo.fIgnoreDuplicates = FALSE; + dbScopeInfo.fBackword = FALSE; + + if ( SELF_SETLOCATE( pArea, &dbScopeInfo ) == SUCCESS ) + { + SELF_LOCATE( pArea, FALSE ); + } } HB_FUNC( __DBSETLOCATE ) { + HB_THREAD_STUB PHB_ITEM pLocate; DBSCOPEINFO pScopeInfo; + AREAP pArea = HB_CURRENT_WA; - if( s_pCurrArea ) + if( pArea ) { pLocate = hb_param( 1, HB_IT_BLOCK ); if( pLocate ) { memset( &pScopeInfo, 0, sizeof( DBSCOPEINFO ) ); pScopeInfo.itmCobFor = pLocate; - SELF_SETLOCATE( ( AREAP ) s_pCurrArea->pArea, &pScopeInfo ); + SELF_SETLOCATE( pArea, &pScopeInfo ); } } } +HB_FUNC( __DBCONTINUE ) +{ + HB_THREAD_STUB + AREAP pArea = HB_CURRENT_WA; + + if( pArea ) + { + SELF_LOCATE( pArea, TRUE ); + } + else + { + hb_errRT_DBCMD( EG_NOTABLE, EDBCMD_NOTABLE, NULL, "DBCONTINUE" ); + return; + } +} + HB_FUNC( __DBPACK ) { + HB_THREAD_STUB PHB_ITEM pBlock, pEvery; + AREAP pArea = HB_CURRENT_WA; - if( s_pCurrArea ) + if( pArea ) { /* * Additional feature: __dbPack( [, [] ) @@ -1689,23 +1889,23 @@ HB_FUNC( __DBPACK ) pBlock = hb_param( 1, HB_IT_BLOCK ); if( pBlock ) { - hb_itemRelease( ( ( AREAP ) s_pCurrArea->pArea )->valResult ); - ( ( AREAP ) s_pCurrArea->pArea )->valResult = hb_itemArrayNew( 2 ); - hb_arraySet( ( ( AREAP ) s_pCurrArea->pArea )->valResult, 1, pBlock ); + hb_itemRelease( pArea->valResult ); + pArea->valResult = hb_itemArrayNew( 2 ); + hb_arraySet( pArea->valResult, 1, pBlock ); pEvery = hb_param( 2, HB_IT_ANY ); if( pEvery && HB_IS_NUMERIC( pEvery ) ) - hb_arraySet( ( ( AREAP ) s_pCurrArea->pArea )->valResult, 2, pEvery ); + hb_arraySet( pArea->valResult, 2, pEvery ); } else { - if ( ( ( AREAP ) s_pCurrArea->pArea )->valResult ) - hb_itemClear( ( ( AREAP ) s_pCurrArea->pArea )->valResult ); + if ( pArea->valResult ) + hb_itemClear( pArea->valResult ); else - ( ( AREAP ) s_pCurrArea->pArea )->valResult = hb_itemNew( NULL ); + pArea->valResult = hb_itemNew( NULL ); } - SELF_PACK( ( AREAP ) s_pCurrArea->pArea ); + SELF_PACK( pArea ); if( pBlock ) - hb_itemClear( ( ( AREAP ) s_pCurrArea->pArea )->valResult ); + hb_itemClear( pArea->valResult ); } else hb_errRT_DBCMD( EG_NOTABLE, EDBCMD_NOTABLE, NULL, "__DBPACK" ); @@ -1713,25 +1913,29 @@ HB_FUNC( __DBPACK ) HB_FUNC( DBRECALL ) { - if( s_pCurrArea ) - SELF_RECALL( ( AREAP ) s_pCurrArea->pArea ); + HB_THREAD_STUB + AREAP pArea = HB_CURRENT_WA; + if( pArea ) + SELF_RECALL( pArea ); else hb_errRT_DBCMD( EG_NOTABLE, EDBCMD_NOTABLE, NULL, "DBRECALL" ); } HB_FUNC( DBRLOCK ) { + HB_THREAD_STUB DBLOCKINFO dbLockInfo; + AREAP pArea = HB_CURRENT_WA; dbLockInfo.fResult = FALSE; - if( s_pCurrArea ) + if( pArea ) { dbLockInfo.itmRecID = hb_param( 1, HB_IT_ANY ); - if( !dbLockInfo.itmRecID || !HB_IS_NUMERIC( dbLockInfo.itmRecID ) ) + if( !dbLockInfo.itmRecID || ISNIL( 1 ) ) dbLockInfo.uiMethod = DBLM_EXCLUSIVE; else dbLockInfo.uiMethod = DBLM_MULTIPLE; - SELF_LOCK( ( AREAP ) s_pCurrArea->pArea, &dbLockInfo ); + SELF_LOCK( pArea, &dbLockInfo ); } else hb_errRT_DBCMD( EG_NOTABLE, EDBCMD_NOTABLE, NULL, "DBRLOCK" ); @@ -1741,41 +1945,53 @@ HB_FUNC( DBRLOCK ) HB_FUNC( DBRLOCKLIST ) { + HB_THREAD_STUB PHB_ITEM pList; + AREAP pArea = HB_CURRENT_WA; - pList = hb_itemArrayNew( 0 ); - if( s_pCurrArea ) - SELF_INFO( ( AREAP ) s_pCurrArea->pArea, DBI_GETLOCKARRAY, pList ); + pList = hb_itemNew( NULL ); + hb_arrayNew( pList, 0 ); + if( pArea ) + SELF_INFO( pArea, DBI_GETLOCKARRAY, pList ); else hb_errRT_DBCMD( EG_NOTABLE, EDBCMD_NOTABLE, NULL, "DBRLOCKLIST" ); - hb_itemRelease( hb_itemReturn( pList ) ); + hb_itemReturn( pList ); + hb_itemRelease( pList ); } HB_FUNC( DBRUNLOCK ) { - if( s_pCurrArea ) - SELF_UNLOCK( ( AREAP ) s_pCurrArea->pArea, hb_parnl( 1 ) ); + HB_THREAD_STUB + AREAP pArea = HB_CURRENT_WA; + + if( pArea ) + SELF_UNLOCK( pArea, hb_param( 1, HB_IT_ANY ) ); else hb_errRT_DBCMD( EG_NOTABLE, EDBCMD_NOTABLE, NULL, "DBRUNLOCK" ); } HB_FUNC( DBSEEK ) { + HB_THREAD_STUB PHB_ITEM pKey; - BOOL bSoftSeek, bFindLast; + BOOL bSoftSeek, bFindLast, fFound; + AREAP pArea = HB_CURRENT_WA; - if( s_pCurrArea ) + if( pArea ) { if( !ISNIL( 1 ) ) { pKey = hb_param( 1, HB_IT_ANY ); bSoftSeek = ISLOG( 2 ) ? hb_parl( 2 ) : hb_set.HB_SET_SOFTSEEK; bFindLast = ISLOG( 3 ) ? hb_parl( 3 ) : FALSE; - if( SELF_SEEK( ( AREAP ) s_pCurrArea->pArea, bSoftSeek, pKey, bFindLast ) == SUCCESS ) + if( SELF_SEEK( pArea, bSoftSeek, pKey, bFindLast ) == SUCCESS ) { - hb_retl( ( ( AREAP ) s_pCurrArea->pArea )->fFound ); - return; + if( SELF_FOUND( pArea, &fFound ) != FAILURE ) + { + hb_retl( fFound ); + return; + } } } else @@ -1789,95 +2005,50 @@ HB_FUNC( DBSEEK ) HB_FUNC( DBSELECTAREA ) { - USHORT uiNewArea; - char * szAlias; - LPAREANODE pAreaNode; - ULONG ulLen; if( ISCHAR( 1 ) ) { - szAlias = hb_parc( 1 ); - ulLen = hb_parclen(1); - if( ulLen >= 1 && szAlias[ 0 ] >= '0' && szAlias[ 0 ] <= '9' ) - uiNewArea = atoi( szAlias ); - else if( ulLen == 1 && toupper( szAlias[ 0 ] ) >= 'A' && toupper( szAlias[ 0 ] ) <= 'K' ) - uiNewArea = toupper( szAlias[ 0 ] ) - 'A' + 1; + hb_rddSelectWorkAreaAlias( hb_parc( 1 ) ); + hb_rddGetCurrentWorkAreaNumber(); + } + else + { + LONG lNewArea = hb_parnl( 1 ); + + if( lNewArea < 1 || lNewArea > HARBOUR_MAX_RDD_AREA_NUM ) + { + hb_rddSelectFirstAvailable(); + } else { - if( ( uiNewArea = hb_rddSelect( szAlias ) ) == 0 ) - { - USHORT uiAction = E_RETRY; - HB_ITEM_PTR pError; - - pError = hb_errRT_New( ES_ERROR, NULL, EG_NOALIAS, EDBCMD_NOALIAS, - NULL, szAlias, 0, EF_CANRETRY ); - - while( uiAction == E_RETRY ) - { - uiAction = hb_errLaunch( pError ); - - if( uiAction == E_RETRY ) - { - if( ( uiNewArea = hb_rddSelect( szAlias ) ) != 0 ) - { - uiAction = E_DEFAULT; - } - } - } - - hb_errRelease( pError ); - /* hb_errRT_BASE( EG_NOALIAS, EDBCMD_NOALIAS, NULL, szAlias, 0 ); */ - return; - } + hb_rddSelectWorkAreaNumber( lNewArea ); } } - else - uiNewArea = hb_parni( 1 ); - if( uiNewArea == 0 ) - hb_rddSelectFirstAvailable(); - else - s_uiCurrArea = uiNewArea; - - pAreaNode = s_pWorkAreas; - while( pAreaNode ) - { - if( ( ( AREAP ) pAreaNode->pArea )->uiArea == s_uiCurrArea ) - { - s_pCurrArea = pAreaNode; /* Select a valid WorkArea */ - return; - } - pAreaNode = pAreaNode->pNext; - } - s_pCurrArea = NULL; /* Selected WorkArea is closed */ } HB_FUNC( __DBSETFOUND ) { + HB_THREAD_STUB PHB_ITEM pFound; + AREAP pArea = HB_CURRENT_WA; - if( s_pCurrArea ) + if( pArea ) { pFound = hb_param( 1, HB_IT_LOGICAL ); if( pFound ) - ( ( AREAP ) s_pCurrArea->pArea )->fFound = hb_itemGetL( pFound ); + pArea->fFound = hb_itemGetL( pFound ); } } -HB_FUNC( DBSKIP ) -{ - if( s_pCurrArea ) - SELF_SKIP( ( AREAP ) s_pCurrArea->pArea, ISNUM( 1 ) ? hb_parnl( 1 ) : 1 ); - else - hb_errRT_DBCMD( EG_NOTABLE, EDBCMD_NOTABLE, NULL, "DBSKIP" ); -} - HB_FUNC( DBSETFILTER ) { + HB_THREAD_STUB PHB_ITEM pBlock, pText; DBFILTERINFO pFilterInfo; + AREAP pArea = HB_CURRENT_WA; - if( s_pCurrArea ) + if( pArea ) { pBlock = hb_param( 1, HB_IT_BLOCK ); if( pBlock ) @@ -1888,298 +2059,275 @@ HB_FUNC( DBSETFILTER ) pFilterInfo.abFilterText = pText; else pFilterInfo.abFilterText = hb_itemPutC( NULL, "" ); - SELF_SETFILTER( ( AREAP ) s_pCurrArea->pArea, &pFilterInfo ); + pFilterInfo.fFilter = TRUE; + pFilterInfo.lpvCargo = NULL; + pFilterInfo.fOptimized = FALSE; + SELF_SETFILTER( pArea, &pFilterInfo ); if( !pText ) hb_itemRelease( pFilterInfo.abFilterText ); } + else + { + SELF_CLEARFILTER( pArea ); + } } else hb_errRT_DBCMD( EG_NOTABLE, EDBCMD_NOTABLE, NULL, "DBSETFILTER" ); } -HB_FUNC( DBSTRUCT ) +HB_FUNC( DBSKIP ) +{ + HB_THREAD_STUB + AREAP pArea = HB_CURRENT_WA; + if( pArea ) + SELF_SKIP( pArea, ISNUM( 1 ) ? hb_parnl( 1 ) : 1 ); + else + hb_errRT_DBCMD( EG_NOTABLE, EDBCMD_NOTABLE, NULL, "DBSKIP" ); +} + +static void hb_fldStructure( AREAP pArea, USHORT uiField, PHB_ITEM pField ) +{ + hb_arrayNew( pField, 4 ); + + SELF_FIELDINFO( pArea, uiField, DBS_NAME, hb_arrayGetItemPtr( pField, 1 ) ); + SELF_FIELDINFO( pArea, uiField, DBS_TYPE, hb_arrayGetItemPtr( pField, 2 ) ); + SELF_FIELDINFO( pArea, uiField, DBS_LEN, hb_arrayGetItemPtr( pField, 3 ) ); + SELF_FIELDINFO( pArea, uiField, DBS_DEC, hb_arrayGetItemPtr( pField, 4 ) ); +} + +static void hb_tblStructure( AREAP pArea, PHB_ITEM pStruct ) { - PHB_ITEM pItem, pData; USHORT uiFields, uiCount; - hb_arrayNew( &hb_stack.Return, 0 ); - - if( s_pCurrArea ) + if( SELF_FIELDCOUNT( pArea, &uiFields ) == SUCCESS ) { - SELF_FIELDCOUNT( ( AREAP ) s_pCurrArea->pArea, &uiFields ); - pData = hb_itemNew( NULL ); - pItem = hb_itemNew( NULL ); - for( uiCount = 1; uiCount <= uiFields; uiCount++ ) + if( hb_arraySize( pStruct, uiFields ) ) { - hb_arrayNew( pItem, 4 ); - SELF_FIELDINFO( ( AREAP ) s_pCurrArea->pArea, uiCount, DBS_NAME, pData ); - hb_arraySet( pItem, 1, pData ); - SELF_FIELDINFO( ( AREAP ) s_pCurrArea->pArea, uiCount, DBS_TYPE, pData ); - hb_arraySet( pItem, 2, pData ); - SELF_FIELDINFO( ( AREAP ) s_pCurrArea->pArea, uiCount, DBS_LEN, pData ); - hb_arraySet( pItem, 3, pData ); - SELF_FIELDINFO( ( AREAP ) s_pCurrArea->pArea, uiCount, DBS_DEC, pData ); - hb_arraySet( pItem, 4, pData ); - hb_arrayAdd( &hb_stack.Return, pItem ); + for( uiCount = 1; uiCount <= uiFields; ++uiCount ) + { + hb_fldStructure( pArea, uiCount, + hb_arrayGetItemPtr( pStruct, uiCount ) ); + } } - hb_itemRelease( pItem ); - hb_itemRelease( pData ); } } +HB_FUNC( DBSTRUCT ) +{ + PHB_ITEM pStruct; + AREAP pArea = ( AREAP ) hb_rddGetCurrentWorkAreaPointer(); + + pStruct = hb_itemNew( NULL ); + hb_arrayNew( pStruct, 0 ); + if( pArea ) + { + hb_tblStructure( pArea, pStruct ); + } + hb_itemReturn( pStruct ); + hb_itemRelease( pStruct ); +} + HB_FUNC( DBTABLEEXT ) { - LPRDDNODE pRddNode; - AREAP pTempArea; - USHORT uiSize, uiRddID; - PHB_ITEM pItem; + HB_THREAD_STUB + HB_ITEM_NEW( Item ); + AREAP pArea = HB_CURRENT_WA; - if( !s_pCurrArea ) + hb_itemPutC( &Item, "" ); + + if( !pArea ) { - hb_rddCheck(); + LPRDDNODE pRddNode; + USHORT uiRddID; pRddNode = hb_rddFindNode( s_szDefDriver, &uiRddID ); - if( !pRddNode ) + if( pRddNode ) { - hb_retc( NULL ); - return; - } - uiSize = sizeof( AREA ); /* Default Size Area */ - pTempArea = ( AREAP ) hb_xgrab( uiSize ); - memset( pTempArea, 0, uiSize ); - pTempArea->lprfsHost = &pRddNode->pTable; - - /* Need more space? */ - SELF_STRUCTSIZE( ( AREAP ) pTempArea, &uiSize ); - if( uiSize > sizeof( AREA ) ) /* Size of Area changed */ - { - pTempArea = ( AREAP ) hb_xrealloc( pTempArea, uiSize ); - memset( pTempArea, 0, uiSize ); - pTempArea->lprfsHost = &pRddNode->pTable; - } - - pRddNode->uiAreaSize = uiSize; /* Update the size of WorkArea */ - pTempArea->rddID = uiRddID; - - if( SELF_NEW( ( AREAP ) pTempArea ) == FAILURE ) - hb_retc( NULL ); - else - { - pItem = hb_itemPutC( NULL, "" ); - SELF_INFO( ( AREAP ) pTempArea, DBI_TABLEEXT, pItem ); - hb_retc( hb_itemGetCPtr( pItem ) ); - hb_itemRelease( pItem ); - SELF_RELEASE( pTempArea ); + pArea = hb_rddNewAreaNode( pRddNode, uiRddID ); + if ( pArea ) + { + SELF_INFO( ( AREAP ) pArea, DBI_TABLEEXT, &Item ); + SELF_RELEASE( pArea ); + } } } else { - pItem = hb_itemPutC( NULL, "" ); - SELF_INFO( ( AREAP ) s_pCurrArea->pArea, DBI_TABLEEXT, pItem ); - hb_retc( hb_itemGetCPtr( pItem ) ); - hb_itemRelease( pItem ); + SELF_INFO( pArea, DBI_TABLEEXT, &Item ); } + hb_itemReturnForward( &Item ); } HB_FUNC( DBUNLOCK ) { + HB_THREAD_STUB + AREAP pArea = HB_CURRENT_WA; - if( s_pCurrArea ) - SELF_UNLOCK( ( AREAP ) s_pCurrArea->pArea, 0 ); + if( pArea ) + SELF_UNLOCK( pArea, NULL ); else hb_errRT_DBCMD( EG_NOTABLE, EDBCMD_NOTABLE, NULL, "DBUNLOCK" ); } HB_FUNC( DBUNLOCKALL ) { - LPAREANODE pTempArea = s_pCurrArea; + HB_THREAD_STUB + USHORT uiArea = hb_rddGetCurrentWorkAreaNumber(), uiIndex; - s_pCurrArea = s_pWorkAreas; - while( s_pCurrArea ) + LOCK_AREA + for ( uiIndex = 1; uiIndex < s_uiWaMax; ++uiIndex ) { - SELF_UNLOCK( ( AREAP ) s_pCurrArea->pArea, 0 ); - s_pCurrArea = s_pCurrArea->pNext; + hb_rddSelectWorkAreaNumber( s_WaList[ uiIndex ]->uiArea ); + SELF_UNLOCK( HB_CURRENT_WA, NULL ); } - s_pCurrArea = pTempArea; + UNLOCK_AREA + hb_rddSelectWorkAreaNumber( uiArea ); } HB_FUNC( DBUSEAREA ) { - char * szDriver, * szFileName; - USHORT uiLen; - DBOPENINFO pInfo; - PHB_FNAME pFileName; - PHB_ITEM pFileExt; - BYTE * codePageId = (BYTE*) hb_parc(7); - char szDriverBuffer[ HARBOUR_MAX_RDD_DRIVERNAME_LENGTH + 1 ]; - char szAlias[ HARBOUR_MAX_RDD_ALIAS_LENGTH + 1 ]; + char * szFileName; - szDriverBuffer[0] = '\0'; + szFileName = hb_parc( 3 ); - s_bNetError = FALSE; - - /* New area? */ - if( hb_parl( 1 ) ) - hb_rddSelectFirstAvailable(); - else if( s_pCurrArea ) /* If current WorkArea is in use then close it */ - hb_rddReleaseCurrentArea(); - - hb_rddCheck(); - if( ISCHAR(2) && hb_parclen( 2 ) ) - { - hb_strncpyUpper( szDriverBuffer, hb_parc( 2 ), - min( hb_parclen( 2 ), HARBOUR_MAX_RDD_DRIVERNAME_LENGTH ) ); - szDriver = szDriverBuffer; - } - else - szDriver = s_szDefDriver; - - if( ISCHAR(3) && hb_parclen( 3 ) > 0 ) - szFileName = hb_parc( 3 ); - else + if( !szFileName || !szFileName[ 0 ] ) { hb_errRT_DBCMD( EG_ARG, EDBCMD_USE_BADPARAMETER, NULL, "DBUSEAREA" ); return; } - pFileName = hb_fsFNameSplit( szFileName ); - - szAlias[0] = '\0'; - if( ISCHAR(4) ) - strncat( szAlias, hb_parc( 4 ), HARBOUR_MAX_RDD_ALIAS_LENGTH ); - else - strncat( szAlias, pFileName->szName, HARBOUR_MAX_RDD_ALIAS_LENGTH ); - - uiLen = strlen( szAlias ); - if( szAlias[ 0 ] >= '0' && szAlias[ 0 ] <= '9' ) - { - hb_xfree( pFileName ); - hb_errRT_DBCMD( EG_DUPALIAS, EDBCMD_DUPALIAS, NULL, "DBUSEAREA" ); - return; - } - - if( uiLen == 1 ) - { - /* Alias with a single letter. Only are valid 'L' and > 'M' */ - if( toupper( szAlias[ 0 ] ) < 'N' && toupper( szAlias[ 0 ] ) != 'L' ) - { - hb_xfree( pFileName ); - hb_errRT_DBCMD( EG_DUPALIAS, EDBCMD_DUPALIAS, NULL, "DBUSEAREA" ); - return; - } - } - - /* Create a new WorkArea node */ - if( !hb_rddInsertAreaNode( szDriver ) ) - { - hb_xfree( pFileName ); - hb_errRT_DBCMD( EG_ARG, EDBCMD_BADPARAMETER, NULL, "DBUSEAREA" ); - return; - } - - szFileName = ( char * ) hb_xgrab( _POSIX_PATH_MAX + 1 ); - szFileName[0] = '\0'; - strncat( szFileName, hb_parc( 3 ), _POSIX_PATH_MAX ); - - if( !pFileName->szExtension ) - { - pFileExt = hb_itemPutC( NULL, "" ); - SELF_INFO( ( AREAP ) s_pCurrArea->pArea, DBI_TABLEEXT, pFileExt ); - strncat( szFileName, hb_itemGetCPtr( pFileExt ), _POSIX_PATH_MAX - - strlen( szFileName ) ); - hb_itemRelease( pFileExt ); - } - hb_xfree( pFileName ); - - /* Fill pInfo structure */ - pInfo.uiArea = s_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; - pInfo.cdpId = codePageId; - - ( ( AREAP ) s_pCurrArea->pArea )->uiArea = s_uiCurrArea; - - /* Open file */ - if( SELF_OPEN( ( AREAP ) s_pCurrArea->pArea, &pInfo ) == FAILURE ) - { - s_bNetError = TRUE; /* Temp fix! What about other types of errors? */ - hb_xfree( pInfo.abName ); - hb_rddReleaseCurrentArea(); - return; - } - hb_xfree( szFileName ); + hb_rddOpenTable( szFileName, hb_parc( 2 ), + hb_parl( 1 ) ? 0 : hb_rddGetCurrentWorkAreaNumber(), + hb_parc( 4 ), + ISLOG( 5 ) ? hb_parl( 5 ) : !hb_set.HB_SET_EXCLUSIVE, + hb_parl( 6 ), hb_parc( 7 ), hb_parnl( 8 ) ); } HB_FUNC( __DBZAP ) { - if( s_pCurrArea ) - SELF_ZAP( ( AREAP ) s_pCurrArea->pArea ); + HB_THREAD_STUB + AREAP pArea = HB_CURRENT_WA; + + if( pArea ) + SELF_ZAP( pArea ); else hb_errRT_DBCMD( EG_NOTABLE, EDBCMD_NOTABLE, NULL, "__DBZAP" ); } HB_FUNC( DELETED ) { + HB_THREAD_STUB BOOL bDeleted = FALSE; + AREAP pArea = HB_CURRENT_WA; - if( s_pCurrArea ) - SELF_DELETED( ( AREAP ) s_pCurrArea->pArea, &bDeleted ); + if( pArea ) + SELF_DELETED( pArea, &bDeleted ); hb_retl( bDeleted ); } HB_FUNC( EOF ) { + HB_THREAD_STUB BOOL bEof = TRUE; + AREAP pArea = HB_CURRENT_WA; - if( s_pCurrArea ) - SELF_EOF( ( AREAP ) s_pCurrArea->pArea, &bEof ); + if( pArea ) + SELF_EOF( pArea, &bEof ); hb_retl( bEof ); } HB_FUNC( FCOUNT ) { + HB_THREAD_STUB USHORT uiFields = 0; + AREAP pArea = HB_CURRENT_WA; - if( s_pCurrArea ) - SELF_FIELDCOUNT( ( AREAP ) s_pCurrArea->pArea, &uiFields ); + if( pArea ) + SELF_FIELDCOUNT( pArea, &uiFields ); hb_retni( uiFields ); } +HB_FUNC( FIELDDEC ) +{ + HB_THREAD_STUB + AREAP pArea = HB_CURRENT_WA; + + if( pArea ) + { + USHORT uiIndex; + + if( ( uiIndex = hb_parni( 1 ) ) > 0 ) + { + HB_ITEM_NEW( Item ); + + if( SELF_FIELDINFO( pArea, uiIndex, DBS_DEC, &Item ) == SUCCESS) + { + hb_itemForwardValue( hb_stackReturnItem(), &Item ); + return; + } + } + } + + hb_retni(0); +} + HB_FUNC( FIELDGET ) { - PHB_ITEM pItem; + HB_THREAD_STUB + HB_ITEM_NEW( Item ); USHORT uiField, uiFields; + AREAP pArea = HB_CURRENT_WA; - pItem = hb_itemNew( NULL ); uiField = hb_parni( 1 ); - if( s_pCurrArea && uiField ) + if( pArea && uiField ) { - if( SELF_FIELDCOUNT( ( AREAP ) s_pCurrArea->pArea, &uiFields ) == SUCCESS && + if( SELF_FIELDCOUNT( pArea, &uiFields ) == SUCCESS && uiField > 0 && uiField <= uiFields ) - SELF_GETVALUE( ( AREAP ) s_pCurrArea->pArea, uiField, pItem ); + SELF_GETVALUE( pArea, uiField, &Item ); } - hb_itemRelease( hb_itemReturn( pItem ) ); + hb_itemForwardValue( hb_stackReturnItem(), &Item ); +} + +HB_FUNC( FIELDLEN ) +{ + HB_THREAD_STUB + AREAP pArea = HB_CURRENT_WA; + + if( pArea ) + { + USHORT uiIndex; + if( ( uiIndex = hb_parni( 1 ) ) > 0 ) + { + HB_ITEM_NEW( Item ); + + if( SELF_FIELDINFO( pArea, uiIndex, DBS_LEN, &Item ) == SUCCESS ) + { + hb_itemForwardValue( hb_stackReturnItem(), &Item ); + return; + } + } + } + + hb_retni(0); } HB_FUNC( FIELDNAME ) { + HB_THREAD_STUB char * szName; USHORT uiFields, uiIndex; + AREAP pArea = HB_CURRENT_WA; - if( s_pCurrArea ) + if( pArea ) { uiIndex = hb_parni( 1 ); - if( SELF_FIELDCOUNT( ( AREAP ) s_pCurrArea->pArea, &uiFields ) == SUCCESS && + if( SELF_FIELDCOUNT( pArea, &uiFields ) == SUCCESS && uiIndex > 0 && uiIndex <= uiFields ) { - /* szName = ( char * ) hb_xgrab( HARBOUR_MAX_RDD_FIELDNAME_LENGTH + 1 ); */ - szName = ( char * ) hb_xgrab( ( ( AREAP ) s_pCurrArea->pArea)->uiMaxFieldNameLength + 1 ); - SELF_FIELDNAME( ( AREAP ) s_pCurrArea->pArea, hb_parni( 1 ), szName ); - hb_retc( szName ); - hb_xfree( szName ); + szName = ( char * ) hb_xgrab( pArea->uiMaxFieldNameLength + 1 ); + SELF_FIELDNAME( pArea, hb_parni( 1 ), szName ); + hb_retcAdopt( szName ); return; } /* This is not Clipper compatible! - David G. Holm @@ -2192,57 +2340,72 @@ HB_FUNC( FIELDNAME ) HB_FUNC( FIELDPOS ) { - /* char szName[ HARBOUR_MAX_RDD_FIELDNAME_LENGTH ]; */ - char * szName; - size_t uiMax; - size_t uiLen; + HB_THREAD_STUB + AREAP pArea = HB_CURRENT_WA; - if( s_pCurrArea ) + if( pArea && hb_parclen( 1 ) > 0 ) { - if ( hb_parc( 1 ) ) - { - uiMax = ( ( AREAP ) s_pCurrArea->pArea)->uiMaxFieldNameLength; - uiLen = hb_parclen( 1 ); - if( uiLen > uiMax ) - { - uiLen = uiMax; - } - szName = ( char * ) hb_xgrab( uiLen + 1 ); - hb_strncpyUpperTrim( szName, hb_parc( 1 ), uiLen ); - hb_retni( hb_rddFieldIndex( ( AREAP ) s_pCurrArea->pArea, szName ) ); - hb_xfree( szName ); - } - else - hb_retni( 0 ); + hb_retni( hb_rddFieldIndex( pArea, hb_parc( 1 ) ) ); } else + { hb_retni( 0 ); + } } HB_FUNC( FIELDPUT ) { + HB_THREAD_STUB USHORT uiIndex; - PHB_ITEM pItem; + AREAP pArea = HB_CURRENT_WA; uiIndex = hb_parni( 1 ); - if( s_pCurrArea && uiIndex ) + if( pArea && uiIndex ) { - pItem = hb_param( 2, HB_IT_ANY ); - if( ! HB_IS_NIL( pItem ) && ( SELF_PUTVALUE( ( AREAP ) s_pCurrArea->pArea, uiIndex, pItem ) == SUCCESS ) ) + PHB_ITEM pItem = hb_param( 2, HB_IT_ANY ); + if( SELF_PUTVALUE( pArea, uiIndex, pItem ) == SUCCESS ) + { hb_itemReturn( pItem ); + } } } +HB_FUNC( FIELDTYPE ) +{ + HB_THREAD_STUB + AREAP pArea = HB_CURRENT_WA; + + if( pArea ) + { + USHORT uiIndex; + + if( ( uiIndex = hb_parni( 1 ) ) > 0 ) + { + HB_ITEM_NEW( Item ); + + if( SELF_FIELDINFO( pArea, uiIndex, DBS_TYPE, &Item ) == SUCCESS ) + { + hb_itemForwardValue( hb_stackReturnItem(), &Item ); + return; + } + } + } + + hb_retc(""); +} + HB_FUNC( FLOCK ) { + HB_THREAD_STUB DBLOCKINFO dbLockInfo; + AREAP pArea = HB_CURRENT_WA; dbLockInfo.fResult = FALSE; - if( s_pCurrArea ) + if( pArea ) { dbLockInfo.itmRecID = NULL; dbLockInfo.uiMethod = DBLM_FILE; - SELF_LOCK( ( AREAP ) s_pCurrArea->pArea, &dbLockInfo ); + SELF_LOCK( pArea, &dbLockInfo ); } else hb_errRT_DBCMD( EG_NOTABLE, EDBCMD_NOTABLE, NULL, "FLOCK" ); @@ -2252,36 +2415,42 @@ HB_FUNC( FLOCK ) HB_FUNC( FOUND ) { + HB_THREAD_STUB BOOL bFound = FALSE; + AREAP pArea = HB_CURRENT_WA; - if( s_pCurrArea ) - SELF_FOUND( ( AREAP ) s_pCurrArea->pArea, &bFound ); + if( pArea ) + SELF_FOUND( pArea, &bFound ); hb_retl( bFound ); } HB_FUNC( HEADER ) { - PHB_ITEM pRecSize; + HB_THREAD_STUB + AREAP pArea = HB_CURRENT_WA; - if( !s_pCurrArea ) + if( !pArea ) hb_retni( 0 ); else { - pRecSize = hb_itemNew( NULL ); - SELF_INFO( ( AREAP ) s_pCurrArea->pArea, DBI_GETHEADERSIZE, pRecSize ); - hb_itemRelease( hb_itemReturn( pRecSize ) ); + HB_ITEM_NEW( RecSize ); + SELF_INFO( pArea, DBI_GETHEADERSIZE, &RecSize ); + hb_itemForwardValue( hb_stackReturnItem(), &RecSize ); } } HB_FUNC( INDEXORD ) { - DBORDERINFO pInfo; + HB_THREAD_STUB + AREAP pArea = HB_CURRENT_WA; - if( s_pCurrArea ) + if( pArea ) { + DBORDERINFO pInfo; pInfo.itmResult = hb_itemPutNI( NULL, 0 ); pInfo.itmOrder = NULL; - SELF_ORDINFO( ( AREAP ) s_pCurrArea->pArea, DBOI_NUMBER, &pInfo ); + pInfo.atomBagName = NULL; + SELF_ORDINFO( pArea, DBOI_NUMBER, &pInfo ); hb_retni( hb_itemGetNI( pInfo.itmResult ) ); hb_itemRelease( pInfo.itmResult ); } @@ -2292,22 +2461,28 @@ HB_FUNC( INDEXORD ) /* Same as RECCOUNT() */ HB_FUNC( LASTREC ) { + HB_THREAD_STUB ULONG ulRecCount = 0; + AREAP pArea = HB_CURRENT_WA; + + if( pArea ) + SELF_RECCOUNT( pArea, &ulRecCount ); - if( s_pCurrArea ) - SELF_RECCOUNT( ( AREAP ) s_pCurrArea->pArea, &ulRecCount ); hb_retnl( ulRecCount ); } HB_FUNC( LOCK ) { + HB_THREAD_STUB DBLOCKINFO dbLockInfo; + AREAP pArea = HB_CURRENT_WA; dbLockInfo.fResult = FALSE; - if( s_pCurrArea ) + if( pArea ) { - dbLockInfo.uiMethod = DBLM_FILE; - SELF_LOCK( ( AREAP ) s_pCurrArea->pArea, &dbLockInfo ); + dbLockInfo.itmRecID = NULL; + dbLockInfo.uiMethod = DBLM_EXCLUSIVE; + SELF_LOCK( pArea, &dbLockInfo ); } else hb_errRT_DBCMD( EG_NOTABLE, EDBCMD_NOTABLE, NULL, "LOCK" ); @@ -2317,88 +2492,77 @@ HB_FUNC( LOCK ) HB_FUNC( LUPDATE ) { - if( !s_pCurrArea ) - hb_itemPutDS( &hb_stack.Return, "" ); + HB_THREAD_STUB + AREAP pArea = HB_CURRENT_WA; + + if( pArea ) + { + HB_ITEM_NEW( Item ); + SELF_INFO( pArea, DBI_LASTUPDATE, &Item ); + hb_itemForwardValue( hb_stackReturnItem(), &Item ); + } else - SELF_INFO( ( AREAP ) s_pCurrArea->pArea, DBI_LASTUPDATE, &hb_stack.Return ); + hb_retds( "" ); } HB_FUNC( NETERR ) { - if( ISLOG( 1 ) ) - s_bNetError = hb_parl( 1 ); + HB_THREAD_STUB hb_retl( s_bNetError ); + + if( ISLOG( 1 ) ) + s_bNetError = hb_parl( 1 ); } HB_FUNC( ORDBAGEXT ) { + HB_THREAD_STUB DBORDERINFO pInfo; - LPRDDNODE pRddNode; - AREAP pTempArea; - USHORT uiSize, uiRddID; + AREAP pArea = HB_CURRENT_WA; pInfo.itmOrder = NULL; - if( !s_pCurrArea ) + pInfo.atomBagName = NULL; + pInfo.itmResult = hb_itemPutC( NULL, "" ); + if( !pArea ) { - hb_rddCheck(); + LPRDDNODE pRddNode; + USHORT uiRddID; pRddNode = hb_rddFindNode( s_szDefDriver, &uiRddID ); - if( !pRddNode ) + if( pRddNode ) { - hb_retc( NULL ); - return; - } - uiSize = sizeof( AREA ); /* Default Size Area */ - pTempArea = ( AREAP ) hb_xgrab( uiSize ); - memset( pTempArea, 0, uiSize ); - pTempArea->lprfsHost = &pRddNode->pTable; - - /* Need more space? */ - SELF_STRUCTSIZE( ( AREAP ) pTempArea, &uiSize ); - if( uiSize > sizeof( AREA ) ) /* Size of Area changed */ - { - pTempArea = ( AREAP ) hb_xrealloc( pTempArea, uiSize ); - memset( pTempArea, 0, uiSize ); - pTempArea->lprfsHost = &pRddNode->pTable; - } - - pRddNode->uiAreaSize = uiSize; /* Update the size of WorkArea */ - pTempArea->rddID = uiRddID; - - if( SELF_NEW( ( AREAP ) pTempArea ) == FAILURE ) - hb_retc( NULL ); - else - { - pInfo.itmResult = hb_itemPutC( NULL, "" ); - SELF_ORDINFO( pTempArea, DBOI_BAGEXT, &pInfo ); - hb_retc( hb_itemGetCPtr( pInfo.itmResult ) ); - hb_itemRelease( pInfo.itmResult ); - SELF_RELEASE( pTempArea ); + pArea = hb_rddNewAreaNode( pRddNode, uiRddID ); + if ( pArea ) + { + SELF_ORDINFO( pArea, DBOI_BAGEXT, &pInfo ); + SELF_RELEASE( pArea ); + } } } else { - pInfo.itmResult = hb_itemPutC( NULL, "" ); - SELF_ORDINFO( ( AREAP ) s_pCurrArea->pArea, DBOI_BAGEXT, &pInfo ); - hb_retc( hb_itemGetCPtr( pInfo.itmResult ) ); - hb_itemRelease( pInfo.itmResult ); + SELF_ORDINFO( pArea, DBOI_BAGEXT, &pInfo ); } + hb_itemReturn( pInfo.itmResult ); + hb_itemRelease( pInfo.itmResult ); } HB_FUNC( ORDBAGNAME ) { + HB_THREAD_STUB DBORDERINFO pOrderInfo; + AREAP pArea = HB_CURRENT_WA; - if( s_pCurrArea ) + if( pArea ) { if ( ISNUM(1) || ISNIL(1) ) { - if ( hb_parnl(1) == 0 || ISNIL(1) ) /* if NIL or ask for 0, use current order */ + if ( hb_parni(1) == 0 || ISNIL(1) ) /* if NIL or ask for 0, use current order */ pOrderInfo.itmOrder = NULL; else pOrderInfo.itmOrder = hb_param( 1, HB_IT_NUMERIC ); - - }else + } + else { pOrderInfo.itmOrder = hb_param( 1, HB_IT_STRING ); if( !pOrderInfo.itmOrder ) @@ -2407,9 +2571,10 @@ HB_FUNC( ORDBAGNAME ) return; } } + pOrderInfo.atomBagName = NULL; pOrderInfo.itmResult = hb_itemPutC( NULL, "" ); - SELF_ORDINFO( ( AREAP ) s_pCurrArea->pArea, DBOI_BAGNAME, &pOrderInfo ); - hb_retc( hb_itemGetCPtr( pOrderInfo.itmResult ) ); + SELF_ORDINFO( pArea, DBOI_BAGNAME, &pOrderInfo ); + hb_itemReturn( pOrderInfo.itmResult ); hb_itemRelease( pOrderInfo.itmResult ); } else @@ -2418,81 +2583,74 @@ HB_FUNC( ORDBAGNAME ) HB_FUNC( ORDCONDSET ) { + HB_THREAD_STUB LPDBORDERCONDINFO lpdbOrdCondInfo; - ULONG ulLen; PHB_ITEM pItem; + AREAP pArea = HB_CURRENT_WA; - if( s_pCurrArea ) + if( pArea ) { lpdbOrdCondInfo = ( LPDBORDERCONDINFO ) hb_xgrab( sizeof( DBORDERCONDINFO ) ); - - ulLen = hb_parclen( 1 ); - if( ulLen > 0 ) - { - lpdbOrdCondInfo->abFor = ( BYTE * ) hb_xgrab( ulLen + 1 ); - strcpy( ( char * ) lpdbOrdCondInfo->abFor, hb_parc( 1 ) ); - } - else - lpdbOrdCondInfo->abFor = NULL; - - if( ISCHAR( 17 ) && ( ulLen = hb_parclen( 17 ) ) > 0 ) - { - lpdbOrdCondInfo->abWhile = ( BYTE * ) hb_xgrab( ulLen + 1 ); - strcpy( ( char * ) lpdbOrdCondInfo->abWhile, hb_parc( 17 ) ); - } - else - lpdbOrdCondInfo->abWhile = NULL; - + lpdbOrdCondInfo->abFor = hb_parclen( 1 ) > 0 ? + ( BYTE * ) hb_strdup( hb_parc( 1 ) ) : NULL; pItem = hb_param( 2, HB_IT_BLOCK ); - if( pItem ) - { - lpdbOrdCondInfo->itmCobFor = hb_itemNew( NULL ); - hb_itemCopy( lpdbOrdCondInfo->itmCobFor, pItem ); - } - else - lpdbOrdCondInfo->itmCobFor = NULL; - if( ISLOG( 3 ) ) - lpdbOrdCondInfo->fAll = hb_parl( 3 ); - else - lpdbOrdCondInfo->fAll = TRUE; + lpdbOrdCondInfo->itmCobFor = pItem ? hb_itemNew( pItem ) : NULL; + lpdbOrdCondInfo->fAll = !ISLOG( 3 ) || hb_parl( 3 ); + + lpdbOrdCondInfo->abWhile = hb_parclen( 17 ) > 0 ? + ( BYTE * ) hb_strdup( hb_parc( 17 ) ) : NULL; pItem = hb_param( 4, HB_IT_BLOCK ); - if( pItem ) - { - lpdbOrdCondInfo->itmCobWhile = hb_itemNew( NULL ); - hb_itemCopy( lpdbOrdCondInfo->itmCobWhile, pItem ); - } - else - lpdbOrdCondInfo->itmCobWhile = NULL; + lpdbOrdCondInfo->itmCobWhile = pItem ? hb_itemNew( pItem ) : NULL; pItem = hb_param( 5, HB_IT_BLOCK ); - if( pItem ) - { - lpdbOrdCondInfo->itmCobEval = hb_itemNew( NULL ); - hb_itemCopy( lpdbOrdCondInfo->itmCobEval, pItem ); - } - else - lpdbOrdCondInfo->itmCobEval = NULL; + lpdbOrdCondInfo->itmCobEval = pItem ? hb_itemNew( pItem ) : NULL; - lpdbOrdCondInfo->lStep = hb_parnl( 6 ); - lpdbOrdCondInfo->lStartRecno = hb_parnl( 7 ); - lpdbOrdCondInfo->lNextCount = hb_parnl( 8 ); - lpdbOrdCondInfo->lRecno = hb_parnl( 9 ); - lpdbOrdCondInfo->fRest = hb_parl( 10 ); - lpdbOrdCondInfo->fDescending = hb_parl( 11 ); - /* 12th parameter is always nil */ - lpdbOrdCondInfo->fAdditive = hb_parl( 13 ); - lpdbOrdCondInfo->fUseCurrent = hb_parl( 14 ); - lpdbOrdCondInfo->fCustom = hb_parl( 15 ); - lpdbOrdCondInfo->fNoOptimize = hb_parl( 16 ); + lpdbOrdCondInfo->lStep = hb_parnl( 6 ); + lpdbOrdCondInfo->itmStartRecID = ISNIL( 7 ) ? NULL : hb_itemNew( hb_param( 7, HB_IT_ANY ) ); + lpdbOrdCondInfo->lNextCount = hb_parnl( 8 ); + lpdbOrdCondInfo->itmRecID = ISNIL( 9 ) ? NULL : hb_itemNew( hb_param( 9, HB_IT_ANY ) ); + lpdbOrdCondInfo->fRest = hb_parl( 10 ); + lpdbOrdCondInfo->fDescending = hb_parl( 11 ); + /* 12th parameter is always nil in CL5.3, in CL5.2 it's compound flag */ + lpdbOrdCondInfo->fCompound = hb_parl( 12 ); + lpdbOrdCondInfo->fAdditive = hb_parl( 13 ); + lpdbOrdCondInfo->fUseCurrent = hb_parl( 14 ); + lpdbOrdCondInfo->fCustom = hb_parl( 15 ); + lpdbOrdCondInfo->fNoOptimize = hb_parl( 16 ); + /* 18th parameter in[x]Harbour is MEMORY flag added by Alexander for + DBFNTX, so far it was served in hacked way inside SELF_ORDSETCOND() + so it was working only if this method was called from ORDCONDSET() + function. I also do not like the idea that it was called MEMORY. + It should be RDD decision how such index will be served on low + level and it should be IMHO called TEMPORARY - if RDD wants then + it can make it fully in memory or in temporary file which will + be removed on index close operation */ + lpdbOrdCondInfo->fTemporary = hb_parl( 18 ); + /* 19th parameter is CL5.2 USEFILTER parameter which means + that RDD should respect SET FILTER and SET DELETE flag */ + lpdbOrdCondInfo->fUseFilter = hb_parl( 19 ); + /* 20th parameter is xHarbour extenstion and informs RDD that + index is not shared between other clients */ + lpdbOrdCondInfo->fExclusive = hb_parl( 20 ); if( lpdbOrdCondInfo->itmCobWhile ) lpdbOrdCondInfo->fRest = TRUE; - if( lpdbOrdCondInfo->lNextCount || lpdbOrdCondInfo->lRecno || - lpdbOrdCondInfo->fRest || lpdbOrdCondInfo->fUseCurrent ) + if( lpdbOrdCondInfo->lNextCount || lpdbOrdCondInfo->itmRecID || + lpdbOrdCondInfo->fRest || lpdbOrdCondInfo->fUseCurrent || + lpdbOrdCondInfo->fUseFilter ) lpdbOrdCondInfo->fAll = FALSE; - hb_retl( SELF_ORDSETCOND( ( AREAP ) s_pCurrArea->pArea, lpdbOrdCondInfo ) == SUCCESS ); + lpdbOrdCondInfo->fActive = !lpdbOrdCondInfo->fAll || + lpdbOrdCondInfo->abFor || lpdbOrdCondInfo->itmCobFor || + lpdbOrdCondInfo->abWhile || lpdbOrdCondInfo->itmCobWhile || + lpdbOrdCondInfo->fNoOptimize || lpdbOrdCondInfo->itmCobEval || + lpdbOrdCondInfo->fTemporary; + + lpdbOrdCondInfo->fScoped = !lpdbOrdCondInfo->fAll; + lpdbOrdCondInfo->lpvCargo = NULL; + + hb_retl( SELF_ORDSETCOND( pArea, lpdbOrdCondInfo ) == SUCCESS ); } else hb_retl( FALSE ); @@ -2500,12 +2658,14 @@ HB_FUNC( ORDCONDSET ) HB_FUNC( ORDCREATE ) { + HB_THREAD_STUB DBORDERCREATEINFO dbOrderInfo; + AREAP pArea = HB_CURRENT_WA; - if( s_pCurrArea ) + if( pArea ) { - dbOrderInfo.abBagName = ( BYTE * ) hb_parc( 1 ); - dbOrderInfo.atomBagName = ( BYTE * ) hb_parc( 2 ); + dbOrderInfo.abBagName = ( BYTE * ) hb_parcx( 1 ); + dbOrderInfo.atomBagName = ( BYTE * ) hb_parcx( 2 ); dbOrderInfo.abExpr = hb_param( 3, HB_IT_STRING ); if( ( ( dbOrderInfo.abBagName == NULL || strlen( ( char * ) dbOrderInfo.abBagName ) == 0 ) && ( dbOrderInfo.atomBagName == NULL || strlen( ( char * ) dbOrderInfo.atomBagName ) == 0 ) ) || @@ -2519,40 +2679,64 @@ HB_FUNC( ORDCREATE ) dbOrderInfo.fUnique = hb_parl( 5 ); else dbOrderInfo.fUnique = hb_set.HB_SET_UNIQUE; - SELF_ORDCREATE( ( AREAP ) s_pCurrArea->pArea, &dbOrderInfo ); + SELF_ORDCREATE( pArea, &dbOrderInfo ); } else hb_errRT_DBCMD( EG_NOTABLE, EDBCMD_NOTABLE, NULL, "ORDCREATE" ); } +HB_FUNC( ORDBAGCLEAR ) +{ + HB_THREAD_STUB + DBORDERINFO pOrderInfo; + AREAP pArea = HB_CURRENT_WA; + + if( pArea ) + { + pOrderInfo.itmOrder = NULL; + pOrderInfo.atomBagName = hb_param( 1, HB_IT_STRING ); + if( !pOrderInfo.atomBagName ) + pOrderInfo.atomBagName = hb_param( 1, HB_IT_NUMERIC ); + hb_retl( SELF_ORDLSTDELETE( pArea, &pOrderInfo ) == SUCCESS ); + } + else + hb_retl( FALSE ); +} + HB_FUNC( ORDDESTROY ) { + HB_THREAD_STUB DBORDERINFO pOrderInfo; + AREAP pArea = HB_CURRENT_WA; - if( s_pCurrArea ) + if( pArea ) { pOrderInfo.itmOrder = hb_param( 1, HB_IT_STRING ); if( !pOrderInfo.itmOrder ) pOrderInfo.itmOrder = hb_param( 1, HB_IT_NUMERIC ); pOrderInfo.atomBagName = hb_param( 2, HB_IT_STRING ); - SELF_ORDDESTROY( ( AREAP ) s_pCurrArea->pArea, &pOrderInfo ); + hb_retl( SELF_ORDDESTROY( pArea, &pOrderInfo ) == SUCCESS ); } + else + hb_retl( FALSE ); } HB_FUNC( ORDFOR ) { + HB_THREAD_STUB DBORDERINFO pOrderInfo; + AREAP pArea = HB_CURRENT_WA; - if( s_pCurrArea ) + if( pArea ) { if ( ISNUM(1) || ISNIL(1) ) { - if ( hb_parnl(1) == 0 || ISNIL(1) ) /* if NIL or ask for 0, use current order */ + if ( hb_parni(1) == 0 || ISNIL(1) ) /* if NIL or ask for 0, use current order */ pOrderInfo.itmOrder = NULL; else pOrderInfo.itmOrder = hb_param( 1, HB_IT_NUMERIC ); - - }else + } + else { pOrderInfo.itmOrder = hb_param( 1, HB_IT_STRING ); if( !pOrderInfo.itmOrder ) @@ -2563,9 +2747,10 @@ HB_FUNC( ORDFOR ) } pOrderInfo.atomBagName = hb_param( 2, HB_IT_STRING ); + pOrderInfo.itmNewVal = hb_param( 3, HB_IT_STRING ); pOrderInfo.itmResult = hb_itemPutC( NULL, "" ); - SELF_ORDINFO( ( AREAP ) s_pCurrArea->pArea, DBOI_CONDITION, &pOrderInfo ); - hb_retc( hb_itemGetCPtr( pOrderInfo.itmResult ) ); + SELF_ORDINFO( pArea, DBOI_CONDITION, &pOrderInfo ); + hb_itemReturn( pOrderInfo.itmResult ); hb_itemRelease( pOrderInfo.itmResult ); } else @@ -2574,18 +2759,20 @@ HB_FUNC( ORDFOR ) HB_FUNC( ORDKEY ) { + HB_THREAD_STUB DBORDERINFO pOrderInfo; + AREAP pArea = HB_CURRENT_WA; - if( s_pCurrArea ) + if( pArea ) { if ( ISNUM(1) || ISNIL(1) ) { - if ( hb_parnl(1) == 0 || ISNIL(1) ) /* if NIL or ask for 0, use current order */ - pOrderInfo.itmOrder = NULL; + if ( hb_parni(1) == 0 || ISNIL(1) ) /* if NIL or ask for 0, use current order */ + pOrderInfo.itmOrder = NULL; else pOrderInfo.itmOrder = hb_param( 1, HB_IT_NUMERIC ); - - }else + } + else { pOrderInfo.itmOrder = hb_param( 1, HB_IT_STRING ); if( !pOrderInfo.itmOrder ) @@ -2597,8 +2784,8 @@ HB_FUNC( ORDKEY ) pOrderInfo.atomBagName = hb_param( 2, HB_IT_STRING ); pOrderInfo.itmResult = hb_itemPutC( NULL, "" ); - SELF_ORDINFO( ( AREAP ) s_pCurrArea->pArea, DBOI_EXPRESSION, &pOrderInfo ); - hb_retc( hb_itemGetCPtr( pOrderInfo.itmResult ) ); + SELF_ORDINFO( pArea, DBOI_EXPRESSION, &pOrderInfo ); + hb_itemReturn( pOrderInfo.itmResult ); hb_itemRelease( pOrderInfo.itmResult ); } else @@ -2608,9 +2795,11 @@ HB_FUNC( ORDKEY ) #ifdef HB_COMPAT_C53 HB_FUNC( ORDKEYCOUNT ) { + HB_THREAD_STUB DBORDERINFO pOrderInfo; + AREAP pArea = HB_CURRENT_WA; - if( s_pCurrArea ) + if( pArea ) { pOrderInfo.itmOrder = hb_param( 1, HB_IT_STRING ); if( !pOrderInfo.itmOrder ) @@ -2619,8 +2808,8 @@ HB_FUNC( ORDKEYCOUNT ) /* Either or both may be NIL */ pOrderInfo.itmResult = hb_itemPutNL( NULL, 0 ); - SELF_ORDINFO( ( AREAP ) s_pCurrArea->pArea, DBOI_KEYCOUNT, &pOrderInfo ); - hb_retnl( hb_itemGetNL( pOrderInfo.itmResult ) ); + SELF_ORDINFO( pArea, DBOI_KEYCOUNT, &pOrderInfo ); + hb_itemReturn( pOrderInfo.itmResult ); hb_itemRelease( pOrderInfo.itmResult ); } else @@ -2630,9 +2819,11 @@ HB_FUNC( ORDKEYCOUNT ) HB_FUNC( ORDKEYNO ) { + HB_THREAD_STUB DBORDERINFO pOrderInfo; + AREAP pArea = HB_CURRENT_WA; - if( s_pCurrArea ) + if( pArea ) { pOrderInfo.itmOrder = hb_param( 1, HB_IT_STRING ); if( !pOrderInfo.itmOrder ) @@ -2641,8 +2832,8 @@ HB_FUNC( ORDKEYNO ) /* Either or both may be NIL */ pOrderInfo.itmNewVal = NULL; pOrderInfo.itmResult = hb_itemPutNL( NULL, 0 ); - SELF_ORDINFO( ( AREAP ) s_pCurrArea->pArea, DBOI_POSITION, &pOrderInfo ); - hb_retnl( hb_itemGetNL( pOrderInfo.itmResult ) ); + SELF_ORDINFO( pArea, DBOI_POSITION, &pOrderInfo ); + hb_itemReturn( pOrderInfo.itmResult ); hb_itemRelease( pOrderInfo.itmResult ); } else @@ -2651,33 +2842,90 @@ HB_FUNC( ORDKEYNO ) HB_FUNC( ORDKEYGOTO ) { + HB_THREAD_STUB DBORDERINFO pOrderInfo; + AREAP pArea = HB_CURRENT_WA; - if( s_pCurrArea ) + if( pArea ) { pOrderInfo.itmOrder = NULL; pOrderInfo.atomBagName = NULL; pOrderInfo.itmNewVal = hb_param( 1 , HB_IT_NUMERIC ); pOrderInfo.itmResult = hb_itemPutL( NULL, FALSE ); - SELF_ORDINFO( ( AREAP ) s_pCurrArea->pArea, DBOI_POSITION, &pOrderInfo ); - hb_retl( hb_itemGetL( pOrderInfo.itmResult ) ); + SELF_ORDINFO( pArea, DBOI_POSITION, &pOrderInfo ); + hb_itemReturn( pOrderInfo.itmResult ); hb_itemRelease( pOrderInfo.itmResult ); } else hb_errRT_DBCMD( EG_NOTABLE, EDBCMD_NOTABLE, NULL, "ORDKEYGOTO" ); } -HB_FUNC( ORDSKIPUNIQUE ) +HB_FUNC( ORDKEYRELPOS ) { + HB_THREAD_STUB DBORDERINFO pOrderInfo; + AREAP pArea = HB_CURRENT_WA; - if( s_pCurrArea ) + if( pArea ) { pOrderInfo.itmOrder = NULL; + pOrderInfo.atomBagName = NULL; + pOrderInfo.itmNewVal = hb_param( 1 , HB_IT_NUMERIC ); + pOrderInfo.itmResult = hb_itemPutNI( NULL, 0 ); + SELF_ORDINFO( pArea, DBOI_RELKEYPOS, &pOrderInfo ); + hb_itemReturn( pOrderInfo.itmResult ); + hb_itemRelease( pOrderInfo.itmResult ); + } + else + hb_errRT_DBCMD( EG_NOTABLE, EDBCMD_NOTABLE, NULL, "ORDKEYRELPOS" ); +} + +HB_FUNC( ORDFINDREC ) +{ + HB_THREAD_STUB + DBORDERINFO pOrderInfo; + AREAP pArea = HB_CURRENT_WA; + + if( pArea ) + { + pOrderInfo.itmOrder = NULL; + pOrderInfo.atomBagName = NULL; + pOrderInfo.itmNewVal = hb_param( 1 , HB_IT_NUMERIC ); + pOrderInfo.itmResult = hb_itemPutL( NULL, FALSE ); + SELF_ORDINFO( pArea, hb_parl( 2 ) ? DBOI_FINDRECCONT : + DBOI_FINDREC, &pOrderInfo ); + hb_itemReturn( pOrderInfo.itmResult ); + hb_itemRelease( pOrderInfo.itmResult ); + } + else + hb_errRT_DBCMD( EG_NOTABLE, EDBCMD_NOTABLE, NULL, "ORDKEYGOTO" ); +} + +HB_FUNC( ORDSKIPRAW ) +{ + HB_THREAD_STUB + AREAP pArea = HB_CURRENT_WA; + if( pArea ) + SELF_SKIPRAW( pArea, ISNUM( 1 ) ? hb_parnl( 1 ) : 1 ); + else + hb_errRT_DBCMD( EG_NOTABLE, EDBCMD_NOTABLE, NULL, "ORDSKIPRAW" ); +} + + +HB_FUNC( ORDSKIPUNIQUE ) +{ + HB_THREAD_STUB + DBORDERINFO pOrderInfo; + AREAP pArea = HB_CURRENT_WA; + + if( pArea ) + { + pOrderInfo.itmOrder = NULL; + pOrderInfo.atomBagName = NULL; pOrderInfo.itmNewVal = hb_param( 1, HB_IT_ANY ); pOrderInfo.itmResult = hb_itemPutL( NULL, FALSE ); - SELF_ORDINFO( ( AREAP ) s_pCurrArea->pArea, DBOI_SKIPUNIQUE, &pOrderInfo ); - hb_retl( hb_itemGetL( pOrderInfo.itmResult ) ); + SELF_ORDINFO( pArea, DBOI_SKIPUNIQUE, &pOrderInfo ); + hb_itemReturn( pOrderInfo.itmResult ); hb_itemRelease( pOrderInfo.itmResult ); } else @@ -2686,13 +2934,16 @@ HB_FUNC( ORDSKIPUNIQUE ) HB_FUNC( ORDKEYVAL ) { + HB_THREAD_STUB DBORDERINFO pOrderInfo; + AREAP pArea = HB_CURRENT_WA; - if( s_pCurrArea ) + if( pArea ) { - pOrderInfo.itmOrder = NULL; + pOrderInfo.itmOrder = NULL; + pOrderInfo.atomBagName = NULL; pOrderInfo.itmResult = hb_itemNew( NULL ); - SELF_ORDINFO( ( AREAP ) s_pCurrArea->pArea, DBOI_KEYVAL, &pOrderInfo ); + SELF_ORDINFO( pArea, DBOI_KEYVAL, &pOrderInfo ); hb_itemReturn( pOrderInfo.itmResult ); hb_itemRelease( pOrderInfo.itmResult ); } @@ -2702,9 +2953,11 @@ HB_FUNC( ORDKEYVAL ) HB_FUNC( ORDKEYADD ) { + HB_THREAD_STUB DBORDERINFO pOrderInfo; + AREAP pArea = HB_CURRENT_WA; - if( s_pCurrArea ) + if( pArea ) { pOrderInfo.itmOrder = hb_param( 1, HB_IT_STRING ); if( !pOrderInfo.itmOrder ) @@ -2713,18 +2966,21 @@ HB_FUNC( ORDKEYADD ) /* Either or both may be NIL */ pOrderInfo.itmNewVal = hb_param( 3 , HB_IT_ANY ); pOrderInfo.itmResult = hb_itemPutNL( NULL, 0 ); - SELF_ORDINFO( ( AREAP ) s_pCurrArea->pArea, DBOI_KEYADD, &pOrderInfo ); - hb_itemReturn( pOrderInfo.itmResult ); + SELF_ORDINFO( pArea, DBOI_KEYADD, &pOrderInfo ); + hb_itemReturn( pOrderInfo.itmResult ); hb_itemRelease( pOrderInfo.itmResult ); } else hb_errRT_DBCMD( EG_NOTABLE, EDBCMD_NOTABLE, NULL, "ORDKEYADD" ); } + HB_FUNC( ORDKEYDEL ) { + HB_THREAD_STUB DBORDERINFO pOrderInfo; + AREAP pArea = HB_CURRENT_WA; - if( s_pCurrArea ) + if( pArea ) { pOrderInfo.itmOrder = hb_param( 1, HB_IT_STRING ); if( !pOrderInfo.itmOrder ) @@ -2733,8 +2989,8 @@ HB_FUNC( ORDKEYDEL ) /* Either or both may be NIL */ pOrderInfo.itmNewVal = hb_param( 3 , HB_IT_ANY ); pOrderInfo.itmResult = hb_itemPutNL( NULL, 0 ); - SELF_ORDINFO( ( AREAP ) s_pCurrArea->pArea, DBOI_KEYDELETE, &pOrderInfo ); - hb_itemReturn( pOrderInfo.itmResult ); + SELF_ORDINFO( pArea, DBOI_KEYDELETE, &pOrderInfo ); + hb_itemReturn( pOrderInfo.itmResult ); hb_itemRelease( pOrderInfo.itmResult ); } else @@ -2743,9 +2999,11 @@ HB_FUNC( ORDKEYDEL ) HB_FUNC( ORDDESCEND ) { + HB_THREAD_STUB DBORDERINFO pOrderInfo; + AREAP pArea = HB_CURRENT_WA; - if( s_pCurrArea ) + if( pArea ) { pOrderInfo.itmOrder = hb_param( 1, HB_IT_STRING ); if( !pOrderInfo.itmOrder ) @@ -2754,8 +3012,8 @@ HB_FUNC( ORDDESCEND ) /* Either or both may be NIL */ pOrderInfo.itmNewVal = hb_param( 3 , HB_IT_LOGICAL ); pOrderInfo.itmResult = hb_itemPutL( NULL, FALSE ); - SELF_ORDINFO( ( AREAP ) s_pCurrArea->pArea, DBOI_ISDESC, &pOrderInfo ); - hb_retl( hb_itemGetL( pOrderInfo.itmResult ) ); + SELF_ORDINFO( pArea, DBOI_ISDESC, &pOrderInfo ); + hb_itemReturn( pOrderInfo.itmResult ); hb_itemRelease( pOrderInfo.itmResult ); } else @@ -2764,9 +3022,11 @@ HB_FUNC( ORDDESCEND ) HB_FUNC( ORDISUNIQUE ) { + HB_THREAD_STUB DBORDERINFO pOrderInfo; + AREAP pArea = HB_CURRENT_WA; - if( s_pCurrArea ) + if( pArea ) { pOrderInfo.itmOrder = hb_param( 1, HB_IT_STRING ); if( !pOrderInfo.itmOrder ) @@ -2775,33 +3035,75 @@ HB_FUNC( ORDISUNIQUE ) /* HARBOUR extension: NewVal to set/reset unique flag */ pOrderInfo.itmNewVal = hb_param( 3 , HB_IT_LOGICAL ); pOrderInfo.itmResult = hb_itemPutL( NULL, FALSE ); - SELF_ORDINFO( ( AREAP ) s_pCurrArea->pArea, DBOI_UNIQUE, &pOrderInfo ); - hb_retl( hb_itemGetL( pOrderInfo.itmResult ) ); + SELF_ORDINFO( pArea, DBOI_UNIQUE, &pOrderInfo ); + hb_itemReturn( pOrderInfo.itmResult ); hb_itemRelease( pOrderInfo.itmResult ); } else hb_errRT_DBCMD( EG_NOTABLE, EDBCMD_NOTABLE, NULL, "ORDISUNIQUE" ); } +HB_FUNC( ORDCUSTOM ) +{ + HB_THREAD_STUB + DBORDERINFO pOrderInfo; + AREAP pArea = HB_CURRENT_WA; + + if( pArea ) + { + pOrderInfo.itmOrder = hb_param( 1, HB_IT_STRING ); + if( !pOrderInfo.itmOrder ) + pOrderInfo.itmOrder = hb_param( 1, HB_IT_NUMERIC ); + pOrderInfo.atomBagName = hb_param( 2, HB_IT_STRING ); + /* Either or both may be NIL */ + pOrderInfo.itmNewVal = hb_param( 3 , HB_IT_LOGICAL ); + pOrderInfo.itmResult = hb_itemPutL( NULL, FALSE ); + SELF_ORDINFO( pArea, DBOI_CUSTOM, &pOrderInfo ); + hb_itemReturn( pOrderInfo.itmResult ); + hb_itemRelease( pOrderInfo.itmResult ); + } + else + hb_errRT_DBCMD( EG_NOTABLE, EDBCMD_NOTABLE, NULL, "ORDCUSTOM" ); +} + +HB_FUNC( ORDCOUNT ) +{ + HB_THREAD_STUB + DBORDERINFO pOrderInfo; + AREAP pArea = HB_CURRENT_WA; + + if( pArea ) + { + pOrderInfo.itmOrder = NULL; + pOrderInfo.atomBagName = hb_param( 1, HB_IT_STRING ); + pOrderInfo.itmResult = hb_itemPutNI( NULL, 0 ); + SELF_ORDINFO( pArea, DBOI_ORDERCOUNT, &pOrderInfo ); + hb_itemReturn( pOrderInfo.itmResult ); + hb_itemRelease( pOrderInfo.itmResult ); + } + else + hb_errRT_DBCMD( EG_NOTABLE, EDBCMD_NOTABLE, NULL, "ORDCOUNT" ); +} + #endif HB_FUNC( ORDLISTADD ) { - + HB_THREAD_STUB DBORDERINFO pOrderInfo; - BOOL bFirst; + AREAP pArea = HB_CURRENT_WA; - if( s_pCurrArea ) + if( pArea ) { + BOOL bFirst; /* determine if there are existing orders; if not, this becomes the controlling order */ + pOrderInfo.itmOrder = NULL; pOrderInfo.atomBagName = NULL; pOrderInfo.itmResult = hb_itemPutNI( NULL, 0 ); - pOrderInfo.itmOrder = NULL; - SELF_ORDINFO( ( AREAP ) s_pCurrArea->pArea, DBOI_ORDERCOUNT, &pOrderInfo ); - bFirst = ( pOrderInfo.itmResult->type & HB_IT_NUMERIC ) && - hb_itemGetNI( pOrderInfo.itmResult ) == 0; - + SELF_ORDINFO( pArea, DBOI_ORDERCOUNT, &pOrderInfo ); + bFirst = HB_IS_NUMERIC( pOrderInfo.itmResult ) && + hb_itemGetNI( pOrderInfo.itmResult ) == 0; pOrderInfo.atomBagName = hb_param( 1, HB_IT_STRING ); pOrderInfo.itmOrder = hb_param( 2, HB_IT_STRING ); @@ -2814,15 +3116,15 @@ HB_FUNC( ORDLISTADD ) return; } - if( SELF_ORDLSTADD( ( AREAP ) s_pCurrArea->pArea, &pOrderInfo ) == SUCCESS ) + if( SELF_ORDLSTADD( pArea, &pOrderInfo ) == SUCCESS ) { - if ( bFirst ) /* set as controlling order and go top */ + if( bFirst ) /* set as controlling order and go top */ { - pOrderInfo.itmOrder = hb_itemPutNI( NULL, 1 ); - SELF_ORDLSTFOCUS( ( AREAP ) s_pCurrArea->pArea, &pOrderInfo ); + pOrderInfo.itmOrder = hb_itemPutNI( NULL, 1 ); + SELF_ORDLSTFOCUS( pArea, &pOrderInfo ); hb_itemRelease( pOrderInfo.itmOrder ); - SELF_GOTOP( ( AREAP ) s_pCurrArea->pArea ); - } + SELF_GOTOP( pArea ); + } } hb_itemRelease( pOrderInfo.itmResult ); } @@ -2833,34 +3135,42 @@ HB_FUNC( ORDLISTADD ) HB_FUNC( ORDLISTCLEAR ) { - if( s_pCurrArea ) - SELF_ORDLSTCLEAR( ( AREAP ) s_pCurrArea->pArea ); + HB_THREAD_STUB + AREAP pArea = HB_CURRENT_WA; + + if( pArea ) + SELF_ORDLSTCLEAR( pArea ); else hb_errRT_DBCMD( EG_NOTABLE, EDBCMD_NOTABLE, NULL, "ORDLISTCLEAR" ); } HB_FUNC( ORDLISTREBUILD ) { - if( s_pCurrArea ) - SELF_ORDLSTREBUILD( ( AREAP ) s_pCurrArea->pArea ); + HB_THREAD_STUB + AREAP pArea = HB_CURRENT_WA; + + if( pArea ) + SELF_ORDLSTREBUILD( pArea ); else hb_errRT_DBCMD( EG_NOTABLE, EDBCMD_NOTABLE, NULL, "ORDLISTREBUILD" ); } HB_FUNC( ORDNAME ) { + HB_THREAD_STUB DBORDERINFO pOrderInfo; + AREAP pArea = HB_CURRENT_WA; - if( s_pCurrArea ) + if( pArea ) { if ( ISNUM(1) || ISNIL(1) ) { - if ( hb_parnl(1) == 0 || ISNIL(1) ) /* if NIL or ask for 0, use current order */ + if ( hb_parni(1) == 0 || ISNIL(1) ) /* if NIL or ask for 0, use current order */ pOrderInfo.itmOrder = NULL; else pOrderInfo.itmOrder = hb_param( 1, HB_IT_NUMERIC ); - - }else + } + else { hb_errRT_DBCMD( EG_ARG, EDBCMD_REL_BADPARAMETER, NULL, "ORDNAME" ); return; @@ -2868,8 +3178,8 @@ HB_FUNC( ORDNAME ) pOrderInfo.atomBagName = hb_param( 2, HB_IT_STRING ); pOrderInfo.itmResult = hb_itemPutC( NULL, "" ); - SELF_ORDINFO( ( AREAP ) s_pCurrArea->pArea, DBOI_NAME, &pOrderInfo ); - hb_retc( hb_itemGetCPtr( pOrderInfo.itmResult ) ); + SELF_ORDINFO( pArea, DBOI_NAME, &pOrderInfo ); + hb_itemReturn( pOrderInfo.itmResult ); hb_itemRelease( pOrderInfo.itmResult ); } else @@ -2878,20 +3188,22 @@ HB_FUNC( ORDNAME ) HB_FUNC( ORDNUMBER ) { + HB_THREAD_STUB DBORDERINFO pOrderInfo; + AREAP pArea = HB_CURRENT_WA; - if( s_pCurrArea ) + if( pArea ) { pOrderInfo.itmOrder = hb_param( 1, HB_IT_STRING ); pOrderInfo.atomBagName = hb_param( 2, HB_IT_STRING ); - if( !pOrderInfo.itmOrder && ! ISNIL(1)) + if( !pOrderInfo.itmOrder && ! ISNIL(1) ) { hb_errRT_DBCMD( EG_ARG, EDBCMD_REL_BADPARAMETER, NULL, "ORDNUMBER" ); return; } pOrderInfo.itmResult = hb_itemPutNI( NULL, 0 ); - SELF_ORDINFO( ( AREAP ) s_pCurrArea->pArea, DBOI_NUMBER, &pOrderInfo ); - hb_retni( hb_itemGetNI( pOrderInfo.itmResult ) ); + SELF_ORDINFO( pArea, DBOI_NUMBER, &pOrderInfo ); + hb_itemReturn( pOrderInfo.itmResult ); hb_itemRelease( pOrderInfo.itmResult ); } else @@ -2900,55 +3212,54 @@ HB_FUNC( ORDNUMBER ) HB_FUNC( ORDSETFOCUS ) { + HB_THREAD_STUB DBORDERINFO pInfo; + AREAP pArea = HB_CURRENT_WA; - if( s_pCurrArea ) + if( pArea ) { pInfo.itmOrder = hb_param( 1, HB_IT_STRING ); if( !pInfo.itmOrder ) pInfo.itmOrder = hb_param( 1, HB_IT_NUMERIC ); pInfo.atomBagName = hb_param( 2, HB_IT_STRING ); pInfo.itmResult = hb_itemPutC( NULL, "" ); - SELF_ORDLSTFOCUS( ( AREAP ) s_pCurrArea->pArea, &pInfo ); - hb_retc( hb_itemGetCPtr( pInfo.itmResult ) ); + SELF_ORDLSTFOCUS( pArea, &pInfo ); + hb_itemReturn( pInfo.itmResult ); hb_itemRelease( pInfo.itmResult ); } else hb_errRT_DBCMD( EG_NOTABLE, EDBCMD_NOTABLE, NULL, "ORDSETFOCUS" ); } - HB_FUNC( RDDLIST ) { - USHORT uiType; - PHB_ITEM pName; - LPRDDNODE pRddNode; + HB_THREAD_STUB + USHORT uiType, uiCount; + HB_ITEM_NEW( Name ); - hb_rddCheck(); - hb_arrayNew( &hb_stack.Return, 0 ); - pName = hb_itemNew( NULL ); - pRddNode = s_pRddList; + hb_arrayNew( hb_stackReturnItem(), 0 ); uiType = hb_parni( 1 ); /* 0 all types of RDD's */ - while( pRddNode ) + for( uiCount = 0; uiCount < s_uiRddMax; ++uiCount ) { - if( ( uiType == 0 ) || ( pRddNode->uiType == uiType ) ) - hb_arrayAdd( &hb_stack.Return, hb_itemPutC( pName, pRddNode->szName ) ); - pRddNode = pRddNode->pNext; + if( ( uiType == 0 ) || ( s_RddList[ uiCount ]->uiType == uiType ) ) + { + hb_arrayAddForward( hb_stackReturnItem(), hb_itemPutC( &Name, s_RddList[ uiCount ]->szName ) ); + } } - hb_itemRelease( pName ); } HB_FUNC( RDDNAME ) { + HB_THREAD_STUB char * pBuffer; + AREAP pArea = HB_CURRENT_WA; - if( s_pCurrArea ) + if( pArea ) { pBuffer = ( char * ) hb_xgrab( HARBOUR_MAX_RDD_DRIVERNAME_LENGTH + 1 ); pBuffer[ 0 ] = '\0'; - SELF_SYSNAME( ( AREAP ) s_pCurrArea->pArea, ( BYTE * ) pBuffer ); - hb_retc( pBuffer ); - hb_xfree( pBuffer ); + SELF_SYSNAME( pArea, ( BYTE * ) pBuffer ); + hb_retcAdopt( pBuffer ); } else { @@ -2962,8 +3273,6 @@ HB_FUNC( RDDREGISTER ) USHORT uiLen; char szDriver[ HARBOUR_MAX_RDD_DRIVERNAME_LENGTH + 1 ]; - hb_rddCheck(); - uiLen = ( USHORT ) hb_parclen( 1 ); if( uiLen > 0 ) { @@ -2979,39 +3288,40 @@ HB_FUNC( RDDREGISTER ) * > 1: error */ if( hb_rddRegister( szDriver, hb_parni( 2 ) ) > 1 ) + { hb_errInternal( HB_EI_RDDINVALID, NULL, NULL, NULL ); + } } } /* Same as LASTREC() */ HB_FUNC( RECCOUNT ) { - ULONG ulRecCount = 0; - - if( s_pCurrArea ) - SELF_RECCOUNT( ( AREAP ) s_pCurrArea->pArea, &ulRecCount ); - hb_retnl( ulRecCount ); + HB_FUNCNAME( LASTREC )(); } HB_FUNC( RECNO ) { - PHB_ITEM pRecNo; + HB_THREAD_STUB + HB_ITEM_NEW( RecNo ); + AREAP pArea = HB_CURRENT_WA; - pRecNo = hb_itemPutNL( NULL, 0 ); - if( s_pCurrArea ) - SELF_RECNO( ( AREAP ) s_pCurrArea->pArea, pRecNo ); - hb_itemRelease( hb_itemReturn( pRecNo ) ); + hb_itemPutNL( &RecNo, 0 ); + if( pArea ) + SELF_RECID( pArea, &RecNo ); + hb_itemReturnForward( &RecNo ); } HB_FUNC( RECSIZE ) { - PHB_ITEM pRecSize; + HB_THREAD_STUB + AREAP pArea = HB_CURRENT_WA; - if( s_pCurrArea ) + if( pArea ) { - pRecSize = hb_itemNew( NULL ); - SELF_INFO( ( AREAP ) s_pCurrArea->pArea, DBI_GETRECSIZE, pRecSize ); - hb_itemRelease( hb_itemReturn( pRecSize ) ); + HB_ITEM_NEW( RecSize ); + SELF_INFO( pArea, DBI_GETRECSIZE, &RecSize ); + hb_itemForwardValue( hb_stackReturnItem(), &RecSize ); } else hb_retni( 0 ); @@ -3019,14 +3329,16 @@ HB_FUNC( RECSIZE ) HB_FUNC( RLOCK ) { + HB_THREAD_STUB DBLOCKINFO dbLockInfo; + AREAP pArea = HB_CURRENT_WA; dbLockInfo.fResult = FALSE; - if( s_pCurrArea ) + if( pArea ) { dbLockInfo.itmRecID = NULL; dbLockInfo.uiMethod = DBLM_EXCLUSIVE; - SELF_LOCK( ( AREAP ) s_pCurrArea->pArea, &dbLockInfo ); + SELF_LOCK( pArea, &dbLockInfo ); } else hb_errRT_DBCMD( EG_NOTABLE, EDBCMD_NOTABLE, NULL, "RLOCK" ); @@ -3036,27 +3348,35 @@ HB_FUNC( RLOCK ) HB_FUNC( SELECT ) { - int nRet = s_uiCurrArea; - - if( ISCHAR(1) ) + HB_THREAD_STUB + if( hb_parinfo( 0 ) == 0 ) + { + hb_retni( hb_rddGetCurrentWorkAreaNumber() ); + } + else { char * szAlias = hb_parc( 1 ); - ULONG ulLen = hb_parclen( 1 ); + int iArea = 0; - if( ulLen == 1 && toupper( szAlias[ 0 ] ) >= 'A' && toupper( szAlias[ 0 ] ) <= 'K' ) - nRet = toupper( szAlias[ 0 ] ) - 'A' + 1; - else if( ulLen > 0 ) - nRet = hb_rddSelect( szAlias ); - else - nRet = 0; + if( szAlias ) + { +#ifdef HB_C52_STRICT + /* + * I do not like this Clipper behavior, in some constructions + * programmer may use "" in some others not. [Druzus] + */ + if( hb_rddVerifyAliasName( szAlias ) == SUCCESS ) +#endif + hb_rddGetAliasNumber( szAlias, &iArea ); + } + hb_retni( iArea ); } - - hb_retni( nRet ); } HB_FUNC( USED ) { - hb_retl( s_pCurrArea != NULL ); + HB_THREAD_STUB + hb_retl( HB_CURRENT_WA != NULL ); } /* NOTE: Same as dbSetDriver() and rddSetDefault(), but doesn't @@ -3066,9 +3386,9 @@ HB_FUNC( USED ) HB_FUNC( __RDDSETDEFAULT ) { + HB_THREAD_STUB USHORT uiLen; - hb_rddCheck(); hb_retc( s_szDefDriver ); uiLen = ( USHORT ) hb_parclen( 1 ); @@ -3079,26 +3399,17 @@ HB_FUNC( __RDDSETDEFAULT ) { uiLen = HARBOUR_MAX_RDD_DRIVERNAME_LENGTH; } - - if( s_szDefDriver ) - { - s_szDefDriver = ( char * ) hb_xrealloc( s_szDefDriver, uiLen + 1 ); - } - else - { - s_szDefDriver = ( char * ) hb_xgrab( uiLen + 1 ); - } - hb_strncpyUpper( s_szDefDriver, hb_parc( 1 ), uiLen ); } } HB_FUNC( RDDSETDEFAULT ) { + HB_THREAD_STUB + USHORT uiLen; char szNewDriver[ HARBOUR_MAX_RDD_DRIVERNAME_LENGTH + 1 ]; - hb_rddCheck(); hb_retc( s_szDefDriver ); uiLen = ( USHORT ) hb_parclen( 1 ); @@ -3109,36 +3420,23 @@ HB_FUNC( RDDSETDEFAULT ) { uiLen = HARBOUR_MAX_RDD_DRIVERNAME_LENGTH; } - hb_strncpyUpper( szNewDriver, hb_parc( 1 ), uiLen ); - if( ! hb_rddFindNode( szNewDriver, NULL ) ) { hb_errRT_DBCMD( EG_ARG, EDBCMD_BADPARAMETER, NULL, "RDDSETDEFAULT" ); return; } - - if( s_szDefDriver ) - { - s_szDefDriver = ( char * ) hb_xrealloc( s_szDefDriver, uiLen + 1 ); - } - else - { - s_szDefDriver = ( char * ) hb_xgrab( uiLen + 1 ); - } - - strncpy( s_szDefDriver, szNewDriver, uiLen ); - s_szDefDriver[ uiLen ] = '\0'; + strcpy( s_szDefDriver, szNewDriver ); } } HB_FUNC( DBSETDRIVER ) { + HB_THREAD_STUB USHORT uiLen; char szNewDriver[ HARBOUR_MAX_RDD_DRIVERNAME_LENGTH + 1 ]; - hb_rddCheck(); hb_retc( s_szDefDriver ); uiLen = ( USHORT ) hb_parclen( 1 ); @@ -3149,59 +3447,55 @@ HB_FUNC( DBSETDRIVER ) { uiLen = HARBOUR_MAX_RDD_DRIVERNAME_LENGTH; } - hb_strncpyUpper( szNewDriver, hb_parc( 1 ), uiLen ); - if( !hb_rddFindNode( szNewDriver, NULL ) ) { hb_errRT_DBCMD( EG_ARG, EDBCMD_BADPARAMETER, NULL, "DBSETDRIVER" ); return; } - - if( s_szDefDriver ) - { - s_szDefDriver = ( char * ) hb_xrealloc( s_szDefDriver, uiLen + 1 ); - } - else - { - s_szDefDriver = ( char * ) hb_xgrab( uiLen + 1 ); - } - - strncpy( s_szDefDriver, szNewDriver, uiLen ); - s_szDefDriver[ uiLen ] = '\0'; + strcpy( s_szDefDriver, szNewDriver ); } } HB_FUNC( ORDSCOPE ) { - PHB_ITEM pScopeValue = hb_itemNew( NULL ); - DBORDSCOPEINFO sInfo; + HB_THREAD_STUB + AREAP pArea = HB_CURRENT_WA; - if( s_pCurrArea ) + if ( pArea ) { - if( (!ISNIL(2) && !( ISCHAR(2) || ISNUM(2) || ISDATE(2) || ISLOG(2) ))) - { - hb_errRT_DBCMD( EG_ARG, EDBCMD_REL_BADPARAMETER, NULL, "ORDSCOPE" ); - return; - } - sInfo.nScope = (ISNUM(1))? hb_parni( 1 ) : 0; + DBORDERINFO pInfo; + USHORT uiAction; + int iScope = hb_parni( 1 ); - SELF_SCOPEINFO( ( AREAP ) s_pCurrArea->pArea, sInfo.nScope, pScopeValue ); - - if( hb_pcount() > 1 ) + pInfo.itmOrder = NULL; + pInfo.atomBagName = NULL; + pInfo.itmResult = hb_itemNew( NULL ); + pInfo.itmNewVal = NULL; + if ( iScope == 2 ) { - if ( ISNIL( 2 ) ) /* explicitly passed NIL, clear it */ - sInfo.scopeValue = NULL; + if ( hb_pcount() > 1 && !ISNIL( 2 ) ) + { + uiAction = DBOI_SCOPESET; + pInfo.itmNewVal = hb_param( 2, HB_IT_ANY); + } else - sInfo.scopeValue = hb_param( 2, HB_IT_ANY) ; - - /* rdd must not alter the scopeValue item -- it's not a copy */ - SELF_SETSCOPE( ( AREAP ) s_pCurrArea->pArea, (LPDBORDSCOPEINFO) &sInfo ); - - }else - sInfo.scopeValue = NULL; - - hb_itemRelease( hb_itemReturn( pScopeValue ) ); + uiAction = DBOI_SCOPECLEAR; + } + else + { + uiAction = ( iScope == 0 ) ? DBOI_SCOPETOP : DBOI_SCOPEBOTTOM; + if( hb_pcount() > 1 ) + { + if( ISNIL( 2 ) ) + uiAction = ( iScope == 0 ) ? DBOI_SCOPETOPCLEAR : DBOI_SCOPEBOTTOMCLEAR; + else + pInfo.itmNewVal = hb_param( 2, HB_IT_ANY); + } + } + SELF_ORDINFO( pArea, uiAction, &pInfo ); + hb_itemReturn( pInfo.itmResult ); + hb_itemRelease( pInfo.itmResult ); } else hb_errRT_DBCMD( EG_NOTABLE, EDBCMD_NOTABLE, NULL, "ORDSCOPE" ); @@ -3209,102 +3503,109 @@ HB_FUNC( ORDSCOPE ) HB_FUNC( DBRELATION ) /* () --> cLinkExp */ { - char cExprBuff[ 256 ]; /*TODO: Correct buffer size initialization ??*/ + HB_THREAD_STUB + char szExprBuff[ HARBOUR_MAX_RDD_RELTEXT_LENGTH + 1 ]; + AREAP pArea = HB_CURRENT_WA; - cExprBuff[ 0 ] = 0; - if( s_pCurrArea ) - SELF_RELTEXT( ( AREAP ) s_pCurrArea->pArea, hb_parni(1), &cExprBuff ) ; + szExprBuff[ 0 ] = 0; + if( pArea ) + SELF_RELTEXT( pArea, hb_parni(1), szExprBuff ) ; - hb_retc(cExprBuff); + hb_retc( szExprBuff ); } HB_FUNC( DBRSELECT ) /* () --> nWorkArea */ { + HB_THREAD_STUB USHORT uiWorkArea = 0; - if( s_pCurrArea ) - SELF_RELAREA( ( AREAP ) s_pCurrArea->pArea, hb_parni(1), &uiWorkArea ); + AREAP pArea = HB_CURRENT_WA; + + if( pArea ) + SELF_RELAREA( pArea, hb_parni(1), &uiWorkArea ); hb_retni( uiWorkArea ); } HB_FUNC( DBCLEARRELATION ) { - if( s_pCurrArea ) - SELF_CLEARREL( ( AREAP ) s_pCurrArea->pArea ); + HB_THREAD_STUB + AREAP pArea = HB_CURRENT_WA; + + if( pArea ) + SELF_CLEARREL( pArea ); } HB_FUNC( DBSETRELATION ) { - char * szAlias; - DBRELINFO dbRelations; - LPAREANODE s_pArea, pAreaNode; - USHORT uiChildArea; + HB_THREAD_STUB + AREAP pArea = HB_CURRENT_WA; - if( s_pCurrArea ) + if( pArea ) { - szAlias = NULL; - s_pArea = NULL; + DBRELINFO dbRelations; + AREAP pChildArea; + USHORT uiChildArea; + char * szAlias = NULL; - if( hb_pcount() < 2 || ( !( hb_parinfo( 1 ) & HB_IT_NUMERIC ) && - ( hb_parinfo( 1 ) != HB_IT_STRING ) ) || - !( ISNIL( 4 ) || ISLOG( 4 ) ) ) + if( hb_pcount() < 2 || ( !( hb_parinfo( 1 ) & HB_IT_NUMERIC ) && ( hb_parinfo( 1 ) != HB_IT_STRING ) ) || !( ISNIL( 4 ) || ISLOG( 4 ) ) ) { hb_errRT_DBCMD( EG_ARG, EDBCMD_REL_BADPARAMETER, NULL, "DBSETRELATION" ); return; } if( hb_parinfo( 1 ) & HB_IT_NUMERIC ) + { uiChildArea = hb_parni( 1 ); + } else { - szAlias = hb_parc( 1 ); - if( szAlias == NULL || ( uiChildArea = hb_rddSelect( szAlias ) ) == 0 ) + USHORT uiArea = hb_rddGetCurrentWorkAreaNumber(); + + hb_rddSelectWorkAreaAlias( hb_parcx( 1 ) ); + if( hb_vmRequestQuery() ) { - hb_errRT_BASE( EG_NOALIAS, EDBCMD_NOALIAS, NULL, szAlias, 0 ); return; } + uiChildArea = hb_rddGetCurrentWorkAreaNumber(); + hb_rddSelectWorkAreaNumber( uiArea ); } - pAreaNode = s_pWorkAreas; - while( pAreaNode ) - { - if( ( ( AREAP ) pAreaNode->pArea )->uiArea == uiChildArea ) - { - s_pArea = pAreaNode; /* Select a valid WorkArea */ - break; - } - pAreaNode = pAreaNode->pNext; - } - if( !s_pArea ) + pChildArea = HB_GET_WA( uiChildArea ); + + if( !pChildArea ) { hb_errRT_BASE( EG_NOALIAS, EDBCMD_NOALIAS, NULL, szAlias, 0 ); return; } - dbRelations.lpaChild = ( AREAP ) s_pArea->pArea; + dbRelations.lpaChild = pChildArea; dbRelations.itmCobExpr = hb_itemNew( hb_param( 2, HB_IT_BLOCK ) ); dbRelations.abKey = hb_itemNew( hb_param( 3, HB_IT_STRING ) ); - dbRelations.isScoped = ( hb_pcount() > 3 )? hb_parl( 4 ):0; + dbRelations.isScoped = hb_parl( 4 ); + dbRelations.isOptimized = FALSE; dbRelations.lpdbriNext = NULL; - SELF_SETREL( ( AREAP ) s_pCurrArea->pArea, &dbRelations ); + SELF_SETREL( pArea, &dbRelations ); } else + { hb_errRT_DBCMD( EG_NOTABLE, EDBCMD_NOTABLE, NULL, "DBSETRELATION" ); + } } - HB_FUNC( __DBARRANGE ) { - USHORT uiNewArea, uiCount; - ULONG ulSize; - char * szFieldLine, * szFieldName, * szPos; - PHB_ITEM pStruct, pFields; - DBSORTINFO dbSortInfo; - LPAREANODE pAreaNode; + HB_THREAD_STUB + AREAP pArea = HB_CURRENT_WA; - if( s_pCurrArea ) + if( pArea ) { + USHORT uiNewArea, uiCount; + ULONG ulSize; + char * szFieldLine, * szPos; + PHB_ITEM pStruct, pFields; + DBSORTINFO dbSortInfo; + memset( &dbSortInfo, 0, sizeof( DBSORTINFO ) ); dbSortInfo.dbtri.uiFlags = DBTF_PUTREC; uiNewArea = hb_parni( 1 ); @@ -3316,20 +3617,17 @@ HB_FUNC( __DBARRANGE ) dbSortInfo.dbtri.uiItemCount = ( USHORT ) hb_arrayLen( pStruct ); if( dbSortInfo.dbtri.uiItemCount > 0 ) { - pFields = hb_itemNew( NULL ); dbSortInfo.dbtri.lpTransItems = ( LPDBTRANSITEM ) hb_xgrab( dbSortInfo.dbtri.uiItemCount * sizeof( DBTRANSITEM ) ); - for( uiCount = 0; uiCount < dbSortInfo.dbtri.uiItemCount; uiCount++ ) + for( uiCount = 0; uiCount < dbSortInfo.dbtri.uiItemCount; ++uiCount ) { - if( hb_arrayGet( pStruct, uiCount + 1, pFields ) && HB_IS_ARRAY( pFields ) && - ( USHORT ) hb_arrayLen( pFields ) > 0 ) + pFields = hb_arrayGetItemPtr( pStruct, uiCount + 1 ); + if( HB_IS_ARRAY( pFields ) && hb_arrayLen( pFields ) > 0 ) { dbSortInfo.dbtri.lpTransItems[ uiCount ].uiSource = - hb_rddFieldIndex( ( AREAP ) s_pCurrArea->pArea, - hb_arrayGetCPtr( pFields, 1 ) ); dbSortInfo.dbtri.lpTransItems[ uiCount ].uiDest = - dbSortInfo.dbtri.lpTransItems[ uiCount ].uiSource; + hb_rddFieldIndex( pArea, hb_arrayGetCPtr( pFields, 1 ) ); } else { @@ -3338,7 +3636,6 @@ HB_FUNC( __DBARRANGE ) break; } } - hb_itemRelease( pFields ); } } else @@ -3353,10 +3650,12 @@ HB_FUNC( __DBARRANGE ) dbSortInfo.dbtri.dbsci.itmCobWhile = hb_param( 4, HB_IT_BLOCK ); dbSortInfo.dbtri.dbsci.lpstrWhile = NULL; dbSortInfo.dbtri.dbsci.lNext = hb_param( 5, HB_IT_NUMERIC ); - dbSortInfo.dbtri.dbsci.itmRecID = hb_param( 6, HB_IT_NUMERIC ); + dbSortInfo.dbtri.dbsci.itmRecID = ISNIL( 6 ) ? NULL : hb_param( 6, HB_IT_ANY ); dbSortInfo.dbtri.dbsci.fRest = hb_param( 7, HB_IT_LOGICAL ); - dbSortInfo.dbtri.dbsci.fIgnoreFilter = dbSortInfo.dbtri.dbsci.fLast = - dbSortInfo.dbtri.dbsci.fIgnoreDuplicates = FALSE; + dbSortInfo.dbtri.dbsci.fIgnoreFilter = + dbSortInfo.dbtri.dbsci.fLast = + dbSortInfo.dbtri.dbsci.fIgnoreDuplicates = + dbSortInfo.dbtri.dbsci.fBackword = FALSE; dbSortInfo.dbtri.dbsci.fIncludeDeleted = TRUE; pFields = hb_param( 8, HB_IT_ARRAY ); @@ -3368,13 +3667,14 @@ HB_FUNC( __DBARRANGE ) { dbSortInfo.lpdbsItem = ( LPDBSORTITEM ) hb_xgrab( dbSortInfo.uiItemCount * sizeof( DBSORTITEM ) ); ulSize = 0; - for( uiCount = 1; uiCount <= dbSortInfo.uiItemCount; uiCount++ ) + for( uiCount = 1; uiCount <= dbSortInfo.uiItemCount; ++uiCount ) { - if( hb_arrayGetCLen( pFields, uiCount ) > ulSize ) - ulSize = hb_arrayGetCLen( pFields, uiCount ); + ULONG ulLine = hb_arrayGetCLen( pFields, uiCount ); + if( ulLine > ulSize ) + ulSize = ulLine; } szFieldLine = ( char * ) hb_xgrab( ulSize + 1 ); - for( uiCount = 0; uiCount < dbSortInfo.uiItemCount; uiCount++ ) + for( uiCount = 0; uiCount < dbSortInfo.uiItemCount; ++uiCount ) { dbSortInfo.lpdbsItem[ uiCount ].uiFlags = 0; hb_strncpyUpper( szFieldLine, hb_arrayGetCPtr( pFields, uiCount + 1 ), @@ -3397,18 +3697,11 @@ HB_FUNC( __DBARRANGE ) * szPos = 0; } else - dbSortInfo.lpdbsItem[ uiCount ].uiFlags |= SF_ASCEND; - szFieldName = szFieldLine; - while( szFieldName[ 0 ] == ' ' ) - szFieldName++; - ulSize = strlen( szFieldName ); - while( ulSize > 1 && szFieldName[ ulSize - 1 ] == ' ' ) { - ulSize --; - szFieldName[ ulSize ] = 0; + dbSortInfo.lpdbsItem[ uiCount ].uiFlags |= SF_ASCEND; } - dbSortInfo.lpdbsItem[ uiCount ].uiField = - hb_rddFieldIndex( ( AREAP ) s_pCurrArea->pArea, szFieldName ); + + dbSortInfo.lpdbsItem[ uiCount ].uiField = hb_rddFieldIndex( pArea, szFieldLine ); /* Field not found */ if( dbSortInfo.lpdbsItem[ uiCount ].uiField == 0 ) @@ -3427,20 +3720,11 @@ HB_FUNC( __DBARRANGE ) if( dbSortInfo.lpdbsItem == NULL ) return; - dbSortInfo.dbtri.lpaSource = ( AREAP ) s_pCurrArea->pArea; + dbSortInfo.dbtri.lpaSource = pArea; dbSortInfo.dbtri.lpaDest = NULL; - pAreaNode = s_pWorkAreas; - while( pAreaNode ) - { - if( ( ( AREAP ) pAreaNode->pArea )->uiArea == uiNewArea ) - { - dbSortInfo.dbtri.lpaDest = ( AREAP ) pAreaNode->pArea; - break; - } - pAreaNode = pAreaNode->pNext; - } + dbSortInfo.dbtri.lpaDest = HB_GET_WA( uiNewArea ); - SELF_SORT( ( AREAP ) s_pCurrArea->pArea, &dbSortInfo ); + SELF_SORT( pArea, &dbSortInfo ); /* Free items */ if( dbSortInfo.lpdbsItem ) @@ -3451,31 +3735,27 @@ HB_FUNC( __DBARRANGE ) } #ifdef HB_COMPAT_C53 + HB_FUNC( DBINFO ) { - PHB_ITEM pType, pInfo; - BOOL bDeleteItem; + HB_THREAD_STUB + AREAP pArea = HB_CURRENT_WA; - if( s_pCurrArea ) + if( pArea ) { - pType = hb_param( 1 , HB_IT_NUMERIC ); - if( pType ) + PHB_ITEM pIndex; + + pIndex = hb_param( 1, HB_IT_NUMERIC ); + if( pIndex ) { - pInfo = hb_param( 2 , HB_IT_ANY ); - if( !pInfo ) - { - pInfo = hb_itemNew( NULL ); - bDeleteItem = TRUE; - } - else - bDeleteItem = FALSE; - SELF_INFO( ( AREAP ) s_pCurrArea->pArea, hb_itemGetNI( pType ), pInfo ); + PHB_ITEM pInfo = hb_itemNew( hb_param( 2, HB_IT_ANY ) ); + + SELF_INFO( pArea, hb_itemGetNI( pIndex ), pInfo ); hb_itemReturn( pInfo ); - if( bDeleteItem ) - hb_itemRelease( pInfo ); - return; + hb_itemRelease( pInfo ); } - hb_errRT_DBCMD( EG_ARG, EDBCMD_DBINFOBADPARAMETER, NULL, "DBINFO" ); + else + hb_errRT_DBCMD( EG_ARG, EDBCMD_DBINFOBADPARAMETER, NULL, "DBINFO" ); } else hb_errRT_DBCMD( EG_NOTABLE, EDBCMD_NOTABLE, NULL, "DBINFO" ); @@ -3483,40 +3763,34 @@ HB_FUNC( DBINFO ) HB_FUNC( DBORDERINFO ) { - PHB_ITEM pType; - BOOL bDeleteItem; - DBORDERINFO pOrderInfo; + HB_THREAD_STUB + AREAP pArea = HB_CURRENT_WA; - if( s_pCurrArea ) + if( pArea ) { + PHB_ITEM pType; + DBORDERINFO pOrderInfo; + pType = hb_param( 1 , HB_IT_NUMERIC ); if( pType ) { - - pOrderInfo.atomBagName = hb_param( 2, HB_IT_STRING ); /* atomBagName may be NIL */ + pOrderInfo.atomBagName = hb_param( 2, HB_IT_STRING ); + if( !pOrderInfo.atomBagName ) + pOrderInfo.atomBagName = hb_param( 2, HB_IT_NUMERIC ); + pOrderInfo.itmOrder = hb_param( 3, HB_IT_STRING ); if( !pOrderInfo.itmOrder ) pOrderInfo.itmOrder = hb_param( 3, HB_IT_NUMERIC ); pOrderInfo.itmNewVal = hb_param( 4 , HB_IT_ANY ); - if( !pOrderInfo.itmNewVal ) - { - pOrderInfo.itmNewVal = hb_itemNew( NULL ); - bDeleteItem = TRUE; - } - else - bDeleteItem = FALSE; pOrderInfo.itmResult = hb_itemNew( NULL ); - SELF_ORDINFO( ( AREAP ) s_pCurrArea->pArea, hb_itemGetNI( pType ), &pOrderInfo ); - hb_itemReturn( pOrderInfo.itmResult ); + SELF_ORDINFO( pArea, hb_itemGetNI( pType ), &pOrderInfo ); + hb_itemReturn( pOrderInfo.itmResult ); hb_itemRelease( pOrderInfo.itmResult ); - - if( bDeleteItem ) - hb_itemRelease( pOrderInfo.itmNewVal ); - return; } - hb_errRT_DBCMD( EG_ARG, EDBCMD_DBCMDBADPARAMETER, NULL, "DBORDERINFO" ); + else + hb_errRT_DBCMD( EG_ARG, EDBCMD_DBCMDBADPARAMETER, NULL, "DBORDERINFO" ); } else hb_errRT_DBCMD( EG_NOTABLE, EDBCMD_NOTABLE, NULL, "DBORDERINFO" ); @@ -3524,33 +3798,27 @@ HB_FUNC( DBORDERINFO ) HB_FUNC( DBFIELDINFO ) { - PHB_ITEM pType, pInfo; - USHORT uiFields, uiIndex; - BOOL bDeleteItem; + HB_THREAD_STUB + AREAP pArea = HB_CURRENT_WA; - if( s_pCurrArea ) + if( pArea ) { + USHORT uiFields, uiIndex; + PHB_ITEM pType; + pType = hb_param( 1 , HB_IT_NUMERIC ); uiIndex = hb_parni( 2 ); - if( pType && - SELF_FIELDCOUNT( ( AREAP ) s_pCurrArea->pArea, &uiFields ) == SUCCESS && + if( pType && SELF_FIELDCOUNT( pArea, &uiFields ) == SUCCESS && uiIndex > 0 && uiIndex <= uiFields ) { - pInfo = hb_param( 3 , HB_IT_ANY ); - if( !pInfo ) - { - pInfo = hb_itemNew( NULL ); - bDeleteItem = TRUE; - } - else - bDeleteItem = FALSE; - SELF_FIELDINFO( ( AREAP ) s_pCurrArea->pArea, uiIndex, hb_itemGetNI( pType ), pInfo ); + PHB_ITEM pInfo = hb_itemNew( hb_param( 3, HB_IT_ANY ) ); + + SELF_FIELDINFO( pArea, uiIndex, hb_itemGetNI( pType ), pInfo ); hb_itemReturn( pInfo ); - if( bDeleteItem ) - hb_itemRelease( pInfo ); - return; + hb_itemRelease( pInfo ); } - hb_errRT_DBCMD( EG_ARG, EDBCMD_DBCMDBADPARAMETER, NULL, "DBFIELDINFO" ); + else + hb_errRT_DBCMD( EG_ARG, EDBCMD_DBCMDBADPARAMETER, NULL, "DBFIELDINFO" ); } else hb_errRT_DBCMD( EG_NOTABLE, EDBCMD_NOTABLE, NULL, "DBFIELDINFO" ); @@ -3558,30 +3826,25 @@ HB_FUNC( DBFIELDINFO ) HB_FUNC( DBRECORDINFO ) { - PHB_ITEM pType, pRecNo, pInfo; - BOOL bDeleteItem; + HB_THREAD_STUB + AREAP pArea = HB_CURRENT_WA; - if( s_pCurrArea ) + if( pArea ) { - pType = hb_param( 1 , HB_IT_NUMERIC ); - pRecNo = hb_param( 2 , HB_IT_NUMERIC ); + PHB_ITEM pType, pRecNo; + + pType = hb_param( 1, HB_IT_NUMERIC ); + pRecNo = hb_param( 2, HB_IT_ANY ); if( pType ) { - pInfo = hb_param( 3 , HB_IT_ANY ); - if( !pInfo ) - { - pInfo = hb_itemNew( NULL ); - bDeleteItem = TRUE; - } - else - bDeleteItem = FALSE; - SELF_RECINFO( ( AREAP ) s_pCurrArea->pArea, pRecNo, hb_itemGetNI( pType ), pInfo ); + PHB_ITEM pInfo = hb_itemNew( hb_param( 3, HB_IT_ANY ) ); + + SELF_RECINFO( pArea, pRecNo, hb_itemGetNI( pType ), pInfo ); hb_itemReturn( pInfo ); - if( bDeleteItem ) - hb_itemRelease( pInfo ); - return; + hb_itemRelease( pInfo ); } - hb_errRT_DBCMD( EG_ARG, EDBCMD_INFOBADPARAMETER, NULL, "DBRECORDINFO" ); + else + hb_errRT_DBCMD( EG_ARG, EDBCMD_INFOBADPARAMETER, NULL, "DBRECORDINFO" ); } else hb_errRT_DBCMD( EG_NOTABLE, EDBCMD_NOTABLE, NULL, "DBRECORDINFO" ); @@ -3589,24 +3852,27 @@ HB_FUNC( DBRECORDINFO ) HB_FUNC( DBFILEGET ) { - PHB_ITEM pFileName, pMode; - char szFileName[ _POSIX_PATH_MAX + 1 ]; - USHORT uiFields, uiIndex; + HB_THREAD_STUB + AREAP pArea = HB_CURRENT_WA; - szFileName[0] = '\0'; - - if( s_pCurrArea ) + if( pArea ) { - uiIndex = hb_parni( 1 ); - pFileName = hb_param( 2 , HB_IT_STRING ); - pMode = hb_param( 3 , HB_IT_NUMERIC ); - if( pFileName && pMode && - SELF_FIELDCOUNT( ( AREAP ) s_pCurrArea->pArea, &uiFields ) == SUCCESS && - uiIndex > 0 && uiIndex <= uiFields ) + USHORT uiFields, uiIndex; + PHB_ITEM pMode; + char * szField = hb_parc( 1 ); + + if( szField ) + uiIndex = hb_rddFieldIndex( pArea, szField ); + else + uiIndex = hb_parni( 1 ); + + pMode = hb_param( 3, HB_IT_NUMERIC ); + if( uiIndex > 0 && pMode && hb_parclen( 2 ) > 0 && + SELF_FIELDCOUNT( pArea, &uiFields ) == SUCCESS && + uiIndex <= uiFields ) { - strncat( szFileName, hb_itemGetCPtr( pFileName ), _POSIX_PATH_MAX ); - hb_retl( SELF_GETVALUEFILE( ( AREAP ) s_pCurrArea->pArea, uiIndex, szFileName, - hb_itemGetNI( pMode ) ) ); + hb_retl( SELF_GETVALUEFILE( pArea, uiIndex, hb_parc( 2 ), + hb_itemGetNI( pMode ) ) == SUCCESS ); return; } hb_errRT_DBCMD( EG_ARG, EDBCMD_DBFILEGETBADPARAMETER, NULL, "DBFILEGET" ); @@ -3619,22 +3885,24 @@ HB_FUNC( DBFILEGET ) HB_FUNC( DBFILEPUT ) { - PHB_ITEM pFileName; - char szFileName[ _POSIX_PATH_MAX + 1 ]; - USHORT uiFields, uiIndex; + HB_THREAD_STUB + AREAP pArea = HB_CURRENT_WA; - szFileName[0] = '\0'; - - if( s_pCurrArea ) + if( pArea ) { - uiIndex = hb_parni( 1 ); - pFileName = hb_param( 2 , HB_IT_STRING ); - if( pFileName && - SELF_FIELDCOUNT( ( AREAP ) s_pCurrArea->pArea, &uiFields ) == SUCCESS && - uiIndex > 0 && uiIndex <= uiFields ) + USHORT uiFields, uiIndex; + char * szField = hb_parc( 1 ); + + if( szField ) + uiIndex = hb_rddFieldIndex( pArea, szField ); + else + uiIndex = hb_parni( 1 ); + if( uiIndex > 0 && hb_parclen( 2 ) > 0 && + SELF_FIELDCOUNT( pArea, &uiFields ) == SUCCESS && + uiIndex <= uiFields ) { - strncat( szFileName, hb_itemGetCPtr( pFileName ), _POSIX_PATH_MAX ); - hb_retl( SELF_PUTVALUEFILE( ( AREAP ) s_pCurrArea->pArea, uiIndex, szFileName ) ); + hb_retl( SELF_PUTVALUEFILE( pArea, uiIndex, hb_parc( 2 ), + hb_parni( 3 ) ) == SUCCESS ); return; } hb_errRT_DBCMD( EG_ARG, EDBCMD_DBFILEPUTBADPARAMETER, NULL, "DBFILEPUT" ); @@ -3647,470 +3915,691 @@ HB_FUNC( DBFILEPUT ) #endif /*******************************************/ -/* here we have the NEW Database level functions DBDROP & DBEXISTS */ +/* here we have the NEW RDD level functions DBDROP, DBEXISTS, RDDINFO */ HB_FUNC( DBDROP ) { - LPRDDNODE pRDDNode; - USHORT uiRddID; - char *szDriver; + HB_THREAD_STUB + LPRDDNODE pRDDNode; + USHORT uiRddID; + char *szDriver; - if ( ISCHAR( 2 ) ) /* we have a VIA RDD parameter */ - szDriver = hb_parc( 2 ); - else - szDriver = s_szDefDriver; + szDriver = hb_parc( 3 ); + if( !szDriver ) /* no VIA RDD parameter, use default */ + { + szDriver = s_szDefDriver; + } - pRDDNode = hb_rddFindNode( szDriver, &uiRddID ); /* find the RDD */ + pRDDNode = hb_rddFindNode( szDriver, &uiRddID ); /* find the RDDNODE */ - if ( !pRDDNode ) - { - hb_errRT_DBCMD( EG_ARG, EDBCMD_EVAL_BADPARAMETER, NULL, "DBDROP" ); - return; - } - if ( SELF_DROP( pRDDNode, hb_param( 1, HB_IT_STRING )) == 0 ) - hb_retl( TRUE ); - else - hb_retl( FALSE ); + if ( !pRDDNode ) + { + hb_errRT_DBCMD( EG_ARG, EDBCMD_EVAL_BADPARAMETER, NULL, "DBDROP" ); + return; + } + + hb_retl( SELF_DROP( pRDDNode, hb_param( 1, HB_IT_STRING ), + hb_param( 2, HB_IT_STRING ) ) == SUCCESS ); } HB_FUNC( DBEXISTS ) { - LPRDDNODE pRDDNode; - USHORT uiRddID; - char * szDriver; + HB_THREAD_STUB + LPRDDNODE pRDDNode; + USHORT uiRddID; + char * szDriver; - if ( ISCHAR( 3 ) ) /* we have a VIA RDD parameter */ - szDriver = hb_parc( 3 ); - else - szDriver = s_szDefDriver; + szDriver = hb_parc( 3 ); + if( !szDriver ) /* no VIA RDD parameter, use default */ + { + szDriver = s_szDefDriver; + } - pRDDNode = hb_rddFindNode( szDriver, &uiRddID ); /* find the RDD */ + pRDDNode = hb_rddFindNode( szDriver, &uiRddID ); // find the RDD - if ( !pRDDNode ) - { - hb_errRT_DBCMD( EG_ARG, EDBCMD_EVAL_BADPARAMETER, NULL, "DBEXISTS" ); - return; - } + if ( !pRDDNode ) + { + hb_errRT_DBCMD( EG_ARG, EDBCMD_EVAL_BADPARAMETER, NULL, "DBEXISTS" ); + return; + } - if ( SELF_EXISTS( pRDDNode, - ISCHAR( 1 ) ? hb_param( 1, HB_IT_STRING ) : NULL, - ISCHAR( 2 ) ? hb_param( 2, HB_IT_STRING ) : NULL )) - hb_retl( TRUE ); - else - hb_retl( FALSE ); + hb_retl( SELF_EXISTS( pRDDNode, hb_param( 1, HB_IT_STRING ), + hb_param( 2, HB_IT_STRING ) ) == SUCCESS ); } -/*******************************************/ -/* as we are in C, the code is upside down, - find __SBAPP & __DBCOPY at the bottom -*/ - -/* check if the field is on the Fields Array -*/ -static BOOL IsFieldIn( char * fieldName, PHB_ITEM pFields ) +HB_FUNC( RDDINFO ) { - USHORT i, j, uiFields = ( USHORT ) hb_arrayLen( pFields ); - char *ptr; - BOOL lresult; + LPRDDNODE pRDDNode; + USHORT uiRddID; + ULONG ulConnection; + PHB_ITEM pIndex, pParam; + char *szDriver; - for ( i=0; iitem.asArray.value->pItems + i; - ptr = strrchr( (char *)pField->item.asString.value,'>' ); - if( ptr && ptr > (char *)pField->item.asString.value && *(ptr-1)=='-' ) - ptr ++; - else - ptr = (char *)pField->item.asString.value; - lresult = TRUE; - for( j=0;*ptr;j++,ptr++ ) - if( *(fieldName+j) != toupper(*ptr) ) - { - lresult = FALSE; - break; - } - if ( lresult ) - return TRUE; - } - return FALSE; + szDriver = hb_parc( 3 ); + if( !szDriver ) /* no VIA RDD parameter, use default */ + { + szDriver = s_szDefDriver; + } + ulConnection = hb_parnl( 4 ); + + pRDDNode = hb_rddFindNode( szDriver, &uiRddID ); /* find the RDDNODE */ + pIndex = hb_param( 1, HB_IT_NUMERIC ); + pParam = hb_param( 2, HB_IT_ANY ); + + if( pRDDNode && pIndex ) + { + PHB_ITEM pInfo = hb_itemNew( pParam ); + SELF_RDDINFO( pRDDNode, hb_itemGetNI( pIndex ), ulConnection, pInfo ); + hb_itemReturn( pInfo ); + hb_itemRelease( pInfo ); + } + else + { + hb_errRT_DBCMD( EG_ARG, EDBCMD_EVAL_BADPARAMETER, NULL, "RDDINFO" ); + } } -static void AddField( PHB_ITEM pFieldArray, PHB_ITEM pItem, PHB_ITEM pData, USHORT uiCount ) + +static ERRCODE hb_dbTransStruct( AREAP lpaSource, AREAP lpaDest, + LPDBTRANSINFO lpdbTransInfo, + PHB_ITEM *pStruct, PHB_ITEM pFields ) { - hb_arrayNew( pItem, 4 ); - SELF_FIELDINFO( ( AREAP ) s_pCurrArea->pArea, uiCount, DBS_NAME, pData ); - hb_arraySet( pItem, 1, pData ); - SELF_FIELDINFO( ( AREAP ) s_pCurrArea->pArea, uiCount, DBS_TYPE, pData ); - hb_arraySet( pItem, 2, pData ); - SELF_FIELDINFO( ( AREAP ) s_pCurrArea->pArea, uiCount, DBS_LEN, pData ); - hb_arraySet( pItem, 3, pData ); - SELF_FIELDINFO( ( AREAP ) s_pCurrArea->pArea, uiCount, DBS_DEC, pData ); - hb_arraySet( pItem, 4, pData ); - hb_arrayAdd( pFieldArray, pItem ); -} -/* create a new AREANODE and open its Area - If the file exists it will be deleted & a new one created -*/ -static LPAREANODE GetTheOtherArea( char *szDriver, char * szFileName, BOOL createIt, PHB_ITEM pFields ) -{ - LPAREANODE pAreaNode; - LPRDDNODE pRDDNode; - PHB_ITEM tableItem, pFileExt; - USHORT uiRddID; - PHB_FNAME pFileName; - DBOPENINFO pInfo; - char * szDbfName; + USHORT uiFields, uiSize, uiCount, uiPosSrc, uiPosDst, uiSizeSrc, uiSizeDst; + ERRCODE errCode; + char * szField; + BOOL fAll; - pRDDNode = hb_rddFindNode( szDriver, &uiRddID ); /* find the RDD */ + errCode = SELF_FIELDCOUNT( lpaSource, &uiSizeSrc ); + if( errCode != SUCCESS ) + return errCode; - if ( !pRDDNode ) - { - hb_errRT_DBCMD( EG_ARG, EDBCMD_EVAL_BADPARAMETER, NULL, "DBAPP" ); - return NULL; - } + if( lpaDest ) + { + errCode = SELF_FIELDCOUNT( lpaDest, &uiSizeDst ); + if( errCode != SUCCESS ) + return errCode; + uiSize = HB_MIN( uiSizeDst, uiSizeSrc ); + } + else + { + uiSize = uiSizeDst = uiSizeSrc; + } -/* Fill pInfo structure */ - memset( &pInfo, 0, sizeof(DBOPENINFO) ); - pInfo.uiArea = uiRddID; - szDbfName = ( char * ) hb_xgrab( _POSIX_PATH_MAX + 1 ); - pInfo.abName = (BYTE *) szDbfName; - strcpy( ( char * ) pInfo.abName, szFileName ); - pInfo.atomAlias = ( BYTE * ) "__TMPAREA"; - pInfo.fShared = (createIt)? FALSE : !hb_set.HB_SET_EXCLUSIVE; - pInfo.fReadonly = (createIt)? FALSE : TRUE; + if( !uiSize ) + return FAILURE; + if( hb_itemType( pFields ) & HB_IT_ARRAY ) + { + uiFields = ( USHORT ) hb_arrayLen( pFields ); + if( uiFields ) + uiSize = uiFields; + } + else + uiFields = 0; -/* get the new area node */ - pAreaNode = hb_rddNewAreaNode( pRDDNode, uiRddID ); + fAll = ( uiSizeDst == uiSizeSrc ); -/* check the extension */ - pFileName = hb_fsFNameSplit( szFileName ); - if( !pFileName->szExtension ) - { - pFileExt = hb_itemPutC( NULL, "" ); - SELF_INFO( ( AREAP ) pAreaNode->pArea, DBI_TABLEEXT, pFileExt ); - strncat( (char *) pInfo.abName, hb_itemGetCPtr( pFileExt ), _POSIX_PATH_MAX - - strlen( (char *) pInfo.abName ) ); - hb_itemRelease( pFileExt ); - } - hb_xfree( pFileName ); + lpdbTransInfo->lpaSource = lpaSource; + lpdbTransInfo->lpaDest = lpaDest; + lpdbTransInfo->lpTransItems = ( LPDBTRANSITEM ) + hb_xgrab( uiSize * sizeof( DBTRANSITEM ) ); - if ( createIt ) - { - PHB_ITEM pFieldArray, pItem, pData; - USHORT uiFields, uiCount; + if( !lpaDest ) + { + *pStruct = hb_itemNew( NULL ); + hb_arrayNew( *pStruct, 0 ); + } -/* get the table structure */ - pFieldArray = hb_itemNew( NULL ); - SELF_FIELDCOUNT( ( AREAP ) s_pCurrArea->pArea, &uiFields ); - hb_arrayNew( pFieldArray, 0 ); - pData = hb_itemNew( NULL ); - pItem = hb_itemNew( NULL ); - if( pFields ) - { - USHORT i; - int iLen; - char *ptr; - char *szFieldName = ( char * ) hb_xgrab( ((AREAP) s_pCurrArea->pArea)->uiMaxFieldNameLength+1 ); - - uiFields = ( USHORT ) hb_arrayLen( pFields ); - for ( i=0; iitem.asArray.value->pItems + i; - ptr = strrchr( (char *)pField->item.asString.value,'>' ); - if( ptr && ptr > (char *)pField->item.asString.value && *(ptr-1)=='-' ) - ptr ++; - else - ptr = (char *)pField->item.asString.value; - iLen = strlen( ptr ); - hb_strncpyUpper( szFieldName, ptr, iLen ); - if( ( uiCount = hb_rddFieldIndex( (AREAP) s_pCurrArea->pArea, - szFieldName ) ) != 0 ) - AddField( pFieldArray, pItem, pData, uiCount ); - } - hb_xfree( szFieldName ); - } - else - for( uiCount = 1; uiCount <= uiFields; uiCount++ ) - AddField( pFieldArray, pItem, pData, uiCount ); - hb_itemRelease( pItem ); - hb_itemRelease( pData ); - if( !hb_arrayLen( pFieldArray ) ) - { - hb_itemRelease( pFieldArray ); - SELF_RELEASE( ( AREAP ) pAreaNode->pArea ); - hb_xfree( pInfo.abName ); - hb_xfree( pAreaNode ); - hb_errRT_DBCMD( EG_ARG, EDBCMD_BADPARAMETER, NULL, "DBCREATE" ); - return NULL; - } - -/* check for table existence and if true, drop it */ - tableItem = hb_itemNew( NULL ); - hb_itemPutCL( tableItem, szFileName, strlen(szFileName) ); - if( SELF_EXISTS( pRDDNode, tableItem, NULL )) - SELF_DROP( pRDDNode, tableItem ); - hb_itemRelease( tableItem ); - -/* now create a new table based on the current Area's record layout */ - ( ( AREAP ) pAreaNode->pArea )->atomAlias = hb_dynsymGet( ( char * ) pInfo.atomAlias ); - if( SELF_CREATEFIELDS( ( AREAP ) pAreaNode->pArea, pFieldArray ) == FAILURE ) - { - SELF_RELEASE( ( AREAP ) pAreaNode->pArea ); - hb_xfree( pInfo.abName ); - hb_xfree( pAreaNode ); - hb_errRT_DBCMD( EG_ARG, EDBCMD_BADPARAMETER, NULL, "DBAPP" ); - return NULL; - } - - if( SELF_CREATE( ( AREAP ) pAreaNode->pArea, &pInfo ) == FAILURE ) - { - SELF_RELEASE( ( AREAP ) pAreaNode->pArea ); - hb_xfree( pInfo.abName ); - hb_xfree( pAreaNode ); - hb_errRT_DBCMD( EG_ARG, EDBCMD_BADPARAMETER, NULL, "DBAPP" ); - return NULL; - } - hb_itemRelease( pFieldArray ); - SELF_CLOSE( ( AREAP ) pAreaNode->pArea ); - SELF_RELEASE( ( AREAP ) pAreaNode->pArea ); - hb_xfree( pAreaNode ); - -/* get a new area node for this AREA */ - pAreaNode = hb_rddNewAreaNode( pRDDNode, uiRddID ); - } - -/* open it */ - if( SELF_OPEN( ( AREAP ) pAreaNode->pArea, &pInfo ) == FAILURE ) - { - SELF_RELEASE( ( AREAP ) pAreaNode->pArea ); - hb_xfree( pInfo.abName ); - hb_xfree( pAreaNode ); - if( createIt ) - hb_errRT_DBCMD( EG_OPEN, 0, NULL, "DBAPP" ); /* Could not open it */ - else - s_bNetError = TRUE; /* Temp fix! What about other types of errors? */ - return NULL; - } - hb_xfree( szDbfName ); - return pAreaNode; -} - -/* move the Field Data between areas by name */ -static void rddMoveFields( AREAP pAreaFrom, AREAP pAreaTo, PHB_ITEM pFields, LPAREANODE s ) -{ - USHORT i, f; - PHB_ITEM fieldValue; - - fieldValue = hb_itemNew( NULL ); - for ( i=0 ; iuiFieldCount; i++ ) - { - /* list or field in the list?*/ - if ( !pFields || IsFieldIn( (( PHB_DYNS )(pAreaFrom->lpFields + i)->sym )->pSymbol->szName, pFields )) - { - f = hb_rddFieldIndex( pAreaTo, (( PHB_DYNS )(pAreaFrom->lpFields + i)->sym )->pSymbol->szName ); - if ( f ) + if( uiFields == 0 ) + { + if( lpaDest ) { - LPAREANODE s_curr = s_pCurrArea; - SELF_GETVALUE( pAreaFrom, i+1, fieldValue ); - if( s ) - s_pCurrArea = s; - SELF_PUTVALUE( pAreaTo, f, fieldValue ); - s_pCurrArea = s_curr; - } - } - } - hb_itemRelease( fieldValue ); -} - -/*move the records, filtering if apropiate*/ -static ERRCODE rddMoveRecords( char *cAreaFrom, char *cAreaTo, PHB_ITEM pFields, - PHB_ITEM pFor, PHB_ITEM pWhile, LONG lNext, - ULONG lRec, BOOL bRest, char *cDriver ) -{ - char * szDriver; - LONG toGo=lNext; - BOOL bFor, bWhile; - BOOL keepGoing=TRUE; - BOOL bDeleted; - AREAP pAreaFrom; - AREAP pAreaTo; - LPAREANODE pAreaRelease=NULL; - LPAREANODE s_pCurrAreaSaved=s_pCurrArea; - - HB_TRACE(HB_TR_DEBUG, ("rddMoveRecords(%s, %s, %p, %p, %p, %d, %lu, %d, %s )", - cAreaFrom, cAreaTo, pFields, pFor, pWhile, lNext, lRec, bRest, cDriver)); - - if ( !s_pCurrArea ) /*We need a current Area to APPEND TO or FROM*/ - { - hb_errRT_DBCMD( EG_NOTABLE, EDBCMD_NOTABLE, NULL, "DBAPP" ); - return EG_NOTABLE; - } - - /*get the RDD Driver to use for the "other" Area*/ - if( cDriver ) - szDriver = cDriver; - else - szDriver = s_szDefDriver; - - if( !cAreaFrom && ! cAreaTo ) /*File is needed*/ - { - hb_errRT_DBCMD( EG_ARG, EDBCMD_EVAL_BADPARAMETER, NULL, "DBAPP" ); - return EG_ARG; - } - - if ( pFields && hb_arrayLen( pFields ) == 0 ) /*no field clause?*/ - pFields = NULL; - - if ( cAreaTo ) /*it's a COPY TO*/ - { - pAreaRelease = GetTheOtherArea( szDriver, cAreaTo, TRUE, pFields ); - pAreaTo = (AREAP) pAreaRelease->pArea; - } - else - pAreaTo = (AREAP) s_pCurrArea->pArea; - - - if ( cAreaFrom ) /*it's an APPEND FROM*/ - { /*make it current*/ - pAreaRelease = GetTheOtherArea( szDriver, cAreaFrom, FALSE, NULL ); - if( pAreaRelease ) - s_pCurrArea = pAreaRelease; - else - return FAILURE; - pAreaFrom = (AREAP) pAreaRelease->pArea; - } - else - pAreaFrom = (AREAP) s_pCurrArea->pArea; - - /* one or the other but never none*/ - if ( !pAreaRelease ) /*We need another Area to APPEND TO*/ - { - hb_errRT_DBCMD( EG_NOTABLE, EDBCMD_NOTABLE, NULL, "DBAPP" ); - return EG_NOTABLE; - } - - if ( lRec > 0 ) /* only one record */ - SELF_GOTO( pAreaFrom, lRec ); /* go there */ - else - { - if( !pWhile && !bRest && !lNext ) /* these two stay current */ - SELF_GOTOP( pAreaFrom ); /* else start from the top */ - } - - /*move those records assuming we are positioned on one.*/ - while( keepGoing ) - { - keepGoing = FALSE; - if( !pAreaFrom->fEof ) /*until eof or an evaluation failed*/ - { - if( pWhile ) - bWhile = hb_itemGetL( hb_vmEvalBlock( pWhile ) ); - else - bWhile = TRUE; - - if( pFor ) - bFor = hb_itemGetL( hb_vmEvalBlock( pFor ) ); - else - bFor = TRUE; - - if( bWhile && (!lNext || toGo > 0 )) /*candidate?*/ - { - if ( bFor ) + PHB_ITEM pItem = hb_itemNew( NULL ); + uiSize = 0; + for( uiCount = 1; uiCount <= uiSizeSrc; ++uiCount ) { - if ( cAreaFrom ) - s_pCurrArea = s_pCurrAreaSaved; - SELF_APPEND( ( AREAP ) pAreaTo, FALSE ); /*put a new one on TO Area*/ - if ( cAreaFrom ) - s_pCurrArea = pAreaRelease; - rddMoveFields( pAreaFrom, pAreaTo, pFields, (cAreaFrom)?s_pCurrAreaSaved:NULL ); /*move the data*/ - bDeleted = FALSE; - SELF_DELETED( ( AREAP ) pAreaFrom, &bDeleted ); - if ( bDeleted ) - SELF_DELETE( ( AREAP ) pAreaTo ); + SELF_FIELDINFO( lpaSource, uiCount, DBS_NAME, pItem ); + szField = hb_itemGetCPtr( pItem ); + uiPosDst = hb_rddFieldExpIndex( lpaDest, szField ); + if( uiPosDst != uiCount ) + fAll = FALSE; + if( uiPosDst ) + { + lpdbTransInfo->lpTransItems[ uiSize ].uiSource = uiCount; + lpdbTransInfo->lpTransItems[ uiSize++ ].uiDest = uiPosDst; + } } - if ( lRec == 0 || pFor ) /*not only one record? Or there's a For clause?*/ - keepGoing = TRUE; - else - continue; + hb_itemRelease( pItem ); } + else + { + hb_tblStructure( lpaSource, *pStruct ); + uiSize = ( USHORT ) hb_arrayLen( *pStruct ); + for( uiCount = 0; uiCount < uiSize; ++uiCount ) + { + lpdbTransInfo->lpTransItems[ uiCount ].uiSource = + lpdbTransInfo->lpTransItems[ uiCount ].uiDest = uiCount + 1; + } + } + } + else + { + uiSize = 0; + for( uiCount = 1; uiCount <= uiFields; ++uiCount ) + { + szField = hb_arrayGetCPtr( pFields, uiCount ); + if( szField ) + { + uiPosSrc = hb_rddFieldExpIndex( lpaSource, szField ); + if( !uiPosSrc ) + continue; + if( lpaDest ) + uiPosDst = hb_rddFieldExpIndex( lpaDest, szField ); + else + uiPosDst = uiSize + 1; + if( uiPosDst ) + { + if( uiPosSrc != uiPosDst ) + fAll = FALSE; + lpdbTransInfo->lpTransItems[ uiSize ].uiSource = uiPosSrc; + lpdbTransInfo->lpTransItems[ uiSize++ ].uiDest = uiPosDst; + if( !lpaDest ) + { + hb_arraySize( *pStruct, uiSize ); + hb_fldStructure( lpaSource, uiPosSrc, + hb_arrayGetItemPtr( *pStruct, uiSize ) ); + } + } + } + } + } - toGo--; /*one less to go*/ - SELF_SKIP( pAreaFrom, 1L ); /*get the next one*/ - } - } + if( uiSize != uiSizeSrc ) + fAll = FALSE; - s_pCurrArea = s_pCurrAreaSaved; /*set current WorkArea to initial state*/ + if( fAll && lpaDest ) + { + PHB_ITEM pSrcItm = hb_itemNew( NULL ), + pDstItm = hb_itemNew( NULL ); + /* + * if fAll is TRUE here then it means that all fields are included + * and they are on the same positions in both tables, so now check + * if their types and sizes are also equal + */ + for( uiCount = 1; uiCount <= uiSize; ++uiCount ) + { + SELF_FIELDINFO( lpaSource, uiCount, DBS_TYPE, pSrcItm ); + SELF_FIELDINFO( lpaDest, uiCount, DBS_TYPE, pDstItm ); + if( hb_stricmp( hb_itemGetCPtr( pSrcItm ), + hb_itemGetCPtr( pDstItm ) ) != 0 ) + { + fAll = FALSE; + break; + } + SELF_FIELDINFO( lpaSource, uiCount, DBS_LEN, pSrcItm ); + SELF_FIELDINFO( lpaDest, uiCount, DBS_LEN, pDstItm ); + if( hb_itemGetNL( pSrcItm ) != hb_itemGetNL( pDstItm ) ) + { + fAll = FALSE; + break; + } + SELF_FIELDINFO( lpaSource, uiCount, DBS_DEC, pSrcItm ); + SELF_FIELDINFO( lpaDest, uiCount, DBS_DEC, pDstItm ); + if( hb_itemGetNL( pSrcItm ) != hb_itemGetNL( pDstItm ) ) + { + fAll = FALSE; + break; + } + } + hb_itemRelease( pSrcItm ); + hb_itemRelease( pDstItm ); + } - /*Close the File*/ - SELF_CLOSE( ( AREAP ) pAreaRelease->pArea ); - SELF_RELEASE( ( AREAP ) pAreaRelease->pArea ); - hb_xfree( pAreaRelease ); + lpdbTransInfo->uiFlags = fAll ? DBTF_MATCH : 0; + lpdbTransInfo->uiItemCount = uiSize; - return SUCCESS; + return uiSize ? SUCCESS : FAILURE; +} + +static ERRCODE hb_rddTransRecords( AREAP pArea, + char *szFileName, char *szDriver, + ULONG ulConnection, + PHB_ITEM pFields, BOOL fExport, + PHB_ITEM pCobFor, PHB_ITEM pStrFor, + PHB_ITEM pCobWhile, PHB_ITEM pStrWhile, + PHB_ITEM pNext, PHB_ITEM pRecID, + PHB_ITEM pRest ) +{ + AREAP lpaSource, lpaDest, lpaClose = NULL; + DBTRANSINFO dbTransInfo; + USHORT uiPrevArea; + ERRCODE errCode; + + memset( &dbTransInfo, 0, sizeof( DBTRANSINFO ) ); + uiPrevArea = hb_rddGetCurrentWorkAreaNumber(); + + if( fExport ) + { + PHB_ITEM pStruct = NULL; + + lpaSource = pArea; + errCode = hb_dbTransStruct( lpaSource, NULL, &dbTransInfo, + &pStruct, pFields ); + if( errCode == SUCCESS ) + { + errCode = hb_rddCreateTable( szFileName, pStruct, szDriver, + TRUE, 0, "", NULL, ulConnection ); + if( errCode == SUCCESS ) + { + dbTransInfo.lpaDest = lpaClose = lpaDest = + ( AREAP ) hb_rddGetCurrentWorkAreaPointer(); + } + } + if( pStruct ) + hb_itemRelease( pStruct ); + } + else + { + lpaDest = pArea; + errCode = hb_rddOpenTable( szFileName, szDriver, 0, "", TRUE, TRUE, + NULL, ulConnection ); + if( errCode == SUCCESS ) + { + lpaClose = lpaSource = ( AREAP ) hb_rddGetCurrentWorkAreaPointer(); + errCode = hb_dbTransStruct( lpaSource, lpaDest, &dbTransInfo, + NULL, pFields ); + } + } + + if( errCode == SUCCESS ) + { + hb_rddSelectWorkAreaNumber( lpaSource->uiArea ); + + dbTransInfo.dbsci.itmCobFor = pCobFor; + dbTransInfo.dbsci.lpstrFor = pStrFor; + dbTransInfo.dbsci.itmCobWhile = pCobWhile; + dbTransInfo.dbsci.lpstrWhile = pStrWhile; + dbTransInfo.dbsci.lNext = pNext; + dbTransInfo.dbsci.itmRecID = pRecID; + dbTransInfo.dbsci.fRest = pRest; + + dbTransInfo.dbsci.fIgnoreFilter = TRUE; + dbTransInfo.dbsci.fIncludeDeleted = TRUE; + dbTransInfo.dbsci.fLast = FALSE; + dbTransInfo.dbsci.fIgnoreDuplicates = FALSE; + dbTransInfo.dbsci.fBackword = FALSE; + + errCode = SELF_TRANS( lpaSource, &dbTransInfo ); + } + + if( dbTransInfo.lpTransItems ) + hb_xfree( dbTransInfo.lpTransItems ); + if( lpaClose ) + { + hb_rddSelectWorkAreaNumber( lpaClose->uiArea ); + hb_rddReleaseCurrentArea(); + } + hb_rddSelectWorkAreaNumber( uiPrevArea ); + + return errCode; } HB_FUNC( __DBAPP ) { - if( ISCHAR( 1 ) ) - { - rddMoveRecords( hb_parc( 1 ), /* File From */ - NULL, /* TO current area */ - hb_param( 2, HB_IT_ARRAY ), /* Fields */ - hb_param( 3, HB_IT_BLOCK ), /* For */ - hb_param( 4, HB_IT_BLOCK ), /* While */ - hb_parnl( 5 ), /* Next */ /* Defaults to zero on bad type */ - hb_parnl( 6 ), /* Record */ /* Defaults to zero on bad type */ - hb_parl( 7 ), /* Rest */ /* Defaults to zero on bad type */ - ISCHAR( 8 ) ? hb_parc( 8 ) : NULL ); /* RDD */ - } + if( ISCHAR( 1 ) ) + { + AREAP pArea = ( AREAP ) hb_rddGetCurrentWorkAreaPointer(); + if( pArea ) + { + hb_rddTransRecords( pArea, + hb_parc( 1 ), /* file name */ + hb_parc( 8 ), /* RDD */ + hb_parnl( 9 ), /* connection */ + hb_param( 2, HB_IT_ARRAY ), /* Fields */ + FALSE, /* Export? */ + hb_param( 3, HB_IT_BLOCK ), /* cobFor */ + NULL, /* lpStrFor */ + hb_param( 4, HB_IT_BLOCK ), /* cobWhile */ + NULL, /* lpStrWhile */ + hb_param( 5, HB_IT_NUMERIC ), /* Next */ + ISNIL( 6 ) ? NULL : hb_param( 6, HB_IT_ANY ), /* RecID */ + hb_param( 7, HB_IT_LOGICAL ) );/* Rest */ + } + else + { + hb_errRT_DBCMD( EG_NOTABLE, EDBCMD_NOTABLE, NULL, "APPEND FROM" ); + } + } } HB_FUNC( __DBCOPY ) { - if( ISCHAR( 1 ) ) - { - rddMoveRecords( NULL, /* fro CURRENT Area */ - hb_parc( 1 ), /* To File */ - hb_param( 2, HB_IT_ARRAY ), /* Fields */ - hb_param( 3, HB_IT_BLOCK ), /* For */ - hb_param( 4, HB_IT_BLOCK ), /* While */ - hb_parnl( 5 ), /* Next */ /* Defaults to zero on bad type */ - hb_parnl( 6 ), /* Record */ /* Defaults to zero on bad type */ - hb_parl( 7 ), /* Rest */ /* Defaults to zero on bad type */ - ISCHAR( 8 ) ? hb_parc( 8 ) : NULL ); /* RDD */ - } + if( ISCHAR( 1 ) ) + { + AREAP pArea = ( AREAP ) hb_rddGetCurrentWorkAreaPointer(); + if( pArea ) + { + hb_rddTransRecords( pArea, + hb_parc( 1 ), /* file name */ + hb_parc( 8 ), /* RDD */ + hb_parnl( 9 ), /* connection */ + hb_param( 2, HB_IT_ARRAY ), /* Fields */ + TRUE, /* Export? */ + hb_param( 3, HB_IT_BLOCK ), /* cobFor */ + NULL, /* lpStrFor */ + hb_param( 4, HB_IT_BLOCK ), /* cobWhile */ + NULL, /* lpStrWhile */ + hb_param( 5, HB_IT_NUMERIC ), /* Next */ + ISNIL( 6 ) ? NULL : hb_param( 6, HB_IT_ANY ), /* RecID */ + hb_param( 7, HB_IT_LOGICAL ) );/* Rest */ + } + else + { + hb_errRT_DBCMD( EG_NOTABLE, EDBCMD_NOTABLE, NULL, "COPY TO" ); + } + } } -ERRCODE hb_rddGetTempAlias( char * szAliasTmp ) +ERRCODE HB_EXPORT hb_rddGetTempAlias( char * szAliasTmp ) { - int i; + int i, iArea; - /* szAliasTmp[0] = '\0'; */ - for ( i = 1 ; i < 1000 ; i++ ) + for( i = 1 ; i < 1000 ; i++ ) { - sprintf( szAliasTmp, "HBTMP%3.3i", i); + sprintf( szAliasTmp, "__HBTMP%03i", i); - if ( !hb_rddSelect( szAliasTmp ) ) + if( hb_rddGetAliasNumber( szAliasTmp, &iArea ) != SUCCESS ) { - break; + return SUCCESS; } } - if ( i >= 1000 ) - { - szAliasTmp[0] = '\0'; - return FAILURE; - } - else - { - return SUCCESS; - } + szAliasTmp[0] = '\0'; + return FAILURE; } HB_FUNC( __RDDGETTEMPALIAS ) { + HB_THREAD_STUB char szAliasTmp[ HARBOUR_MAX_RDD_ALIAS_LENGTH + 1 ]; - if ( hb_rddGetTempAlias( szAliasTmp ) == FAILURE ) - hb_ret(); - else + if ( hb_rddGetTempAlias( szAliasTmp ) == SUCCESS ) hb_retc( szAliasTmp ); + else + hb_ret(); +} + +HB_FUNC( DBSKIPPER ) +{ + HB_THREAD_STUB + AREAP pArea = HB_CURRENT_WA; + + if( pArea ) + { + LONG nSkipped = 0; + LONG nRecs = 1; + BOOL bBEof = TRUE; + if( hb_pcount() > 0 ) + { + nRecs = hb_parnl( 1 ) ; + } + + SELF_EOF( pArea, &bBEof ); + if( nRecs == 0 ) + { + SELF_SKIP( pArea, 0 ); + } + else if( nRecs > 0 && !bBEof ) + { + while( nSkipped < nRecs ) + { + SELF_SKIP( pArea, 1 ); + SELF_EOF( pArea, &bBEof ); + if( bBEof ) + { + SELF_SKIP( pArea, -1 ); + nRecs = nSkipped ; + } + else + { + nSkipped++ ; + } + } + } + else if( nRecs < 0 ) + { + while( nSkipped > nRecs ) + { + SELF_SKIP( pArea, -1 ); + SELF_BOF( pArea, &bBEof ); + if( bBEof ) + { + nRecs = nSkipped ; + } + else + { + nSkipped-- ; + } + } + } + hb_retnl( nSkipped ); + } + else + hb_errRT_DBCMD( EG_NOTABLE, EDBCMD_NOTABLE, NULL, "DBSKIPPER" ); +} + +// Escaping delimited strings. Need to be cleaned/optimized/improved +static char *hb_strescape( char *szInput, int lLen, char *cDelim ) +{ + int lCnt = 0; + char * szChr; + char * szEscape = NULL; + char * szReturn = NULL; + + szReturn = szEscape = ( char * ) hb_xgrab( lLen * 2 + 4 ); + + while( lLen && HB_ISSPACE( szInput[ lLen - 1 ] ) ) + { + lLen--; + } + + szChr = szInput; + + while ( *szChr && lCnt++ < lLen ) + { + if( *szChr == *cDelim ) + { + *szEscape++ = '\\'; + } + *szEscape++ = *szChr++; + } + *szEscape = '\0'; + + return szReturn; +} + +// Export field values to text file +static BOOL hb_ExportVar( int handle, PHB_ITEM pValue, char *cDelim ) +{ + switch( pValue->type ) + { + // a "C" field + case HB_IT_STRING: + { + char *szStrEsc; + char *szString; + + szStrEsc = hb_strescape( pValue->item.asString.value, pValue->item.asString.length, cDelim ); + szString = hb_xstrcpy( NULL,cDelim,szStrEsc,cDelim,NULL); + + // FWrite( handle, szString ) + hb_fsWriteLarge( handle, (BYTE*) szString, strlen( szString ) ); + + // Orphaned, get rif off it + hb_xfree( szStrEsc ); + hb_xfree( szString ); + break; + } + // a "D" field + case HB_IT_DATE: + { + char *szDate = (char*) hb_xgrab( 9 ); + + hb_itemGetDS( pValue, szDate ); + hb_fsWriteLarge( handle, (BYTE*) szDate, strlen( szDate ) ); + hb_xfree( szDate ); + break; + } + // an "L" field + case HB_IT_LOGICAL: + { + hb_fsWriteLarge( handle, (BYTE*) ( pValue->item.asLogical.value ? "T" : "F" ), 1 ); + break; + } + // an "N" field + case HB_IT_INTEGER: + case HB_IT_LONG: + case HB_IT_DOUBLE: + { + char *szResult = hb_itemStr( pValue, NULL, NULL ); + + if ( szResult ) + { + ULONG ulLen = strlen( szResult ); + char * szTrimmed = hb_strLTrim( szResult, &ulLen ); + + hb_fsWriteLarge( handle, (BYTE*) szTrimmed, strlen( szTrimmed ) ); + hb_xfree( szResult ); + } + break; + } + // an "M" field or the other, might be a "V" in SixDriver + default: + // We do not want MEMO contents + return FALSE; + } + return TRUE; +} + +HB_FUNC( DBF2TEXT ) +{ + HB_THREAD_STUB + + PHB_ITEM pWhile = hb_param( 1, HB_IT_BLOCK ); + PHB_ITEM pFor = hb_param( 2, HB_IT_BLOCK ); + PHB_ITEM pFields = hb_param( 3, HB_IT_ARRAY ); + + char *cDelim = hb_parc( 4 ); + FHANDLE handle = (FHANDLE) hb_parnl(5); + BYTE *cSep = (BYTE *) hb_parc( 6 ); + int nCount = (int) hb_parnl( 7 ); + + AREAP pArea = HB_CURRENT_WA; + + // Export DBF content to text file + + int iSepLen; + USHORT uiFields = 0; + USHORT ui; + HB_ITEM_NEW( Tmp ); + BOOL bWriteSep = FALSE; + + BOOL bEof = TRUE; + BOOL bBof = TRUE; + + BOOL bNoFieldPassed = ( pFields == NULL || pFields->item.asArray.value->ulLen == 0 ) ; + + if( ! handle ) + { + hb_errRT_DBCMD( EG_ARG, EDBCMD_EVAL_BADPARAMETER, NULL, "DBF2TEXT" ); + return; + } + + if ( !cDelim ) + { + cDelim = "\""; + } + + if ( cSep ) + { + iSepLen = strlen( (char*) cSep ); + } + else + { + cSep = (BYTE*) ','; + iSepLen = 1; + } + + SELF_FIELDCOUNT( pArea, &uiFields ); + + while( ( nCount == -1 || nCount > 0 ) && + ( !pWhile || hb_itemGetL( hb_vmEvalBlock( pWhile ) ) ) ) + { + // While !BOF() .AND. !EOF() + SELF_EOF( pArea, &bEof ); + SELF_BOF( pArea, &bBof ); + + if( bEof || bBof ) + { + break; + } + + // For condition is met + // if For is NULL, hb__Eval returns TRUE + if( !pFor || hb_itemGetL( hb_vmEvalBlock( pFor ) ) ) + { + // User does not request fields, copy all fields + if( bNoFieldPassed ) + { + for ( ui = 1; ui <= uiFields; ui ++ ) + { + if ( bWriteSep ) + { + hb_fsWriteLarge( handle, cSep, iSepLen ); + } + + SELF_GETVALUE( pArea, ui, &Tmp ); + bWriteSep = hb_ExportVar( handle, &Tmp, cDelim ); + hb_itemClear( &Tmp ); + } + } + // Only requested fields are exorted here + else + { + USHORT uiFieldCopy = ( USHORT ) pFields->item.asArray.value->ulLen; + USHORT uiItter; + + for ( uiItter = 1; uiItter <= uiFieldCopy; uiItter++ ) + { + char * szFieldName = hb_arrayGetCPtr( pFields, uiItter ); + if( szFieldName ) + { + int iPos = hb_rddFieldIndex( pArea, szFieldName ); + + if( iPos ) + { + if ( bWriteSep ) + { + hb_fsWriteLarge( handle, cSep, iSepLen ); + } + SELF_GETVALUE( pArea, iPos, &Tmp ); + bWriteSep = hb_ExportVar( handle, &Tmp, cDelim ); + hb_itemClear( &Tmp ); + } + } + } + } + hb_fsWriteLarge( handle, (BYTE*) "\r\n", 2 ); + bWriteSep = FALSE; + } + + if ( nCount != -1 ) + { + nCount-- ; + } + + // DBSKIP() + SELF_SKIP( pArea, 1 ); + } + + // Writing EOF + hb_fsWriteLarge( handle, (BYTE*) "\x1A", 1 ); } diff --git a/harbour/source/rdd/dbf1.c b/harbour/source/rdd/dbf1.c index 3f46232aa6..aae45f0539 100644 --- a/harbour/source/rdd/dbf1.c +++ b/harbour/source/rdd/dbf1.c @@ -63,8 +63,8 @@ #include "hbdate.h" #include "hbmath.h" #include "hbdbsort.h" +#include "hbsxfunc.h" #include "error.ch" -#include #ifndef HB_CDP_SUPPORT_OFF # include "hbapicdp.h" @@ -90,7 +90,7 @@ HB_INIT_SYMBOLS_END( dbf1__InitSymbols ) #if defined(HB_PRAGMA_STARTUP) #pragma startup dbf1__InitSymbols -#elif defined(_MSC_VER) +#elif defined(HB_MSC_STARTUP) #if _MSC_VER >= 1010 #pragma data_seg( ".CRT$XIY" ) #pragma comment( linker, "/Merge:.CRT=.data" ) @@ -101,6 +101,7 @@ HB_INIT_SYMBOLS_END( dbf1__InitSymbols ) #pragma data_seg() #endif +static USHORT s_uiRddId = ( USHORT ) -1; static RDDFUNCS dbfSuper; static RDDFUNCS dbfTable = { ( DBENTRYP_BP ) hb_dbfBof, ( DBENTRYP_BP ) hb_dbfEof, @@ -133,7 +134,8 @@ static RDDFUNCS dbfTable = { ( DBENTRYP_BP ) hb_dbfBof, ( DBENTRYP_V ) hb_dbfRecall, ( DBENTRYP_ULP ) hb_dbfRecCount, ( DBENTRYP_ISI ) hb_dbfRecInfo, - ( DBENTRYP_I ) hb_dbfRecNo, + ( DBENTRYP_ULP ) hb_dbfRecNo, + ( DBENTRYP_I ) hb_dbfRecId, ( DBENTRYP_S ) hb_dbfSetFieldExtent, ( DBENTRYP_P ) hb_dbfAlias, ( DBENTRYP_V ) hb_dbfClose, @@ -163,7 +165,7 @@ static RDDFUNCS dbfTable = { ( DBENTRYP_BP ) hb_dbfBof, ( DBENTRYP_VR ) hb_dbfSetRel, ( DBENTRYP_OI ) hb_dbfOrderListAdd, ( DBENTRYP_V ) hb_dbfOrderListClear, - ( DBENTRYP_VP ) hb_dbfOrderListDelete, + ( DBENTRYP_OI ) hb_dbfOrderListDelete, ( DBENTRYP_OI ) hb_dbfOrderListFocus, ( DBENTRYP_V ) hb_dbfOrderListRebuild, ( DBENTRYP_VOI ) hb_dbfOrderCondition, @@ -180,27 +182,28 @@ static RDDFUNCS dbfTable = { ( DBENTRYP_BP ) hb_dbfBof, ( DBENTRYP_VLO ) hb_dbfSetLocate, ( DBENTRYP_VOS ) hb_dbfSetScope, ( DBENTRYP_VPL ) hb_dbfSkipScope, + ( DBENTRYP_B ) hb_dbfLocate, ( DBENTRYP_P ) hb_dbfCompile, ( DBENTRYP_I ) hb_dbfError, ( DBENTRYP_I ) hb_dbfEvalBlock, ( DBENTRYP_VSP ) hb_dbfRawLock, ( DBENTRYP_VL ) hb_dbfLock, - ( DBENTRYP_UL ) hb_dbfUnLock, + ( DBENTRYP_I ) hb_dbfUnLock, ( DBENTRYP_V ) hb_dbfCloseMemFile, ( DBENTRYP_VP ) hb_dbfCreateMemFile, ( DBENTRYP_SVPB ) hb_dbfGetValueFile, ( DBENTRYP_VP ) hb_dbfOpenMemFile, - ( DBENTRYP_SVP ) hb_dbfPutValueFile, + ( DBENTRYP_SVPB ) hb_dbfPutValueFile, ( DBENTRYP_V ) hb_dbfReadDBHeader, ( DBENTRYP_V ) hb_dbfWriteDBHeader, - ( DBENTRYP_I0 ) hb_dbfExit, - ( DBENTRYP_I1 ) hb_dbfDrop, - ( DBENTRYP_I2 ) hb_dbfExists, + ( DBENTRYP_R ) hb_dbfInit, + ( DBENTRYP_R ) hb_dbfExit, + ( DBENTRYP_RVV ) hb_dbfDrop, + ( DBENTRYP_RVV ) hb_dbfExists, + ( DBENTRYP_RSLV ) hb_dbfRddInfo, ( DBENTRYP_SVP ) hb_dbfWhoCares }; -static BYTE s_dbfVersion = 0x03; /* Stores the current default DBF type for DBCREATE() */ - /* * Common functions. */ @@ -216,10 +219,11 @@ static void hb_dbfSetBlankRecord( DBFAREAP pArea ) { USHORT uiLen = pField->uiLen; - if ( ( pField->uiType == HB_IT_MEMO && uiLen == 4 ) || - ( pField->uiType == HB_IT_DATE && uiLen == 3 ) || - pField->uiType == HB_IT_INTEGER || - pField->uiType == HB_IT_DOUBLE ) + if( ( pField->uiType == HB_IT_MEMO && uiLen == 4 ) || + ( pField->uiType == HB_IT_DATE && uiLen <= 4 ) || + pField->uiType == HB_IT_ANY || + pField->uiType == HB_IT_INTEGER || + pField->uiType == HB_IT_DOUBLE ) { bNext = '\0'; } @@ -228,7 +232,7 @@ static void hb_dbfSetBlankRecord( DBFAREAP pArea ) bNext = ' '; } - if ( bNext == bFill ) + if( bNext == bFill ) { ulSize += uiLen; } @@ -250,8 +254,8 @@ static ULONG hb_dbfCalcRecCount( DBFAREAP pArea ) { HB_TRACE(HB_TR_DEBUG, ("hb_dbfCalcRecCount(%p)", pArea)); - return ( hb_fsSeekLarge( pArea->hDataFile, 0, FS_END ) - pArea->uiHeaderLen ) / - pArea->uiRecordLen; + return ( ULONG ) ( ( hb_fsSeekLarge( pArea->hDataFile, 0, FS_END ) - + pArea->uiHeaderLen ) / pArea->uiRecordLen ); } /* @@ -280,12 +284,15 @@ static BOOL hb_dbfReadRecord( DBFAREAP pArea ) } } - if ( SELF_GETREC( ( AREAP ) pArea, NULL ) == FAILURE ) + /* Set record encryption flag */ + pArea->fEncrypted = FALSE; + + if( SELF_GETREC( ( AREAP ) pArea, NULL ) == FAILURE ) return FALSE; /* Set flags */ pArea->fValidBuffer = pArea->fPositioned = TRUE; - pArea->fDeleted = ( pArea->pRecord[ 0 ] == '*' ); + pArea->fDeleted = pArea->pRecord[ 0 ] == '*'; return TRUE; } @@ -296,7 +303,7 @@ static BOOL hb_dbfWriteRecord( DBFAREAP pArea ) { HB_TRACE(HB_TR_DEBUG, ("hb_dbfWriteRecord(%p)", pArea)); - if ( SELF_PUTREC( ( AREAP ) pArea, NULL ) == FAILURE ) + if( SELF_PUTREC( ( AREAP ) pArea, NULL ) == FAILURE ) return FALSE; pArea->fRecordChanged = FALSE; @@ -339,7 +346,7 @@ static ERRCODE hb_dbfUnlockRecord( DBFAREAP pArea, ULONG ulRecNo ) /* Search the locked record */ for( ulCount = 0; ulCount < pArea->ulNumLocksPos && - pArea->pLocksPos[ ulCount ] != ulRecNo; ulCount++ ); + pArea->pLocksPos[ ulCount ] != ulRecNo; ulCount++ ) {} if( ulCount < pArea->ulNumLocksPos ) { @@ -387,17 +394,20 @@ static ERRCODE hb_dbfLockRecord( DBFAREAP pArea, ULONG ulRecNo, BOOL * pResult, ulRecNo = pArea->ulRecNo; if( bExclusive ) + { hb_dbfUnlockAllRecords( pArea ); - - if( pArea->ulNumLocksPos > 0 ) + } + else if( pArea->ulNumLocksPos > 0 ) { ULONG ul; for( ul = 0; ul < pArea->ulNumLocksPos; ul++ ) + { if( pArea->pLocksPos[ ul ] == ulRecNo ) { * pResult = TRUE; return SUCCESS; } + } } if( SELF_RAWLOCK( ( AREAP ) pArea, REC_LOCK, ulRecNo ) == SUCCESS ) @@ -405,21 +415,27 @@ static ERRCODE hb_dbfLockRecord( DBFAREAP pArea, ULONG ulRecNo, BOOL * pResult, if( pArea->ulNumLocksPos == 0 ) /* Create the list */ { pArea->pLocksPos = ( ULONG * ) hb_xgrab( sizeof( ULONG ) ); - pArea->pLocksPos[ 0 ] = ulRecNo; } else /* Resize the list */ { pArea->pLocksPos = ( ULONG * ) hb_xrealloc( pArea->pLocksPos, ( pArea->ulNumLocksPos + 1 ) * sizeof( ULONG ) ); - pArea->pLocksPos[ pArea->ulNumLocksPos ] = ulRecNo; } - pArea->ulNumLocksPos ++; + pArea->pLocksPos[ pArea->ulNumLocksPos++ ] = ulRecNo; * pResult = TRUE; - if( !pArea->fPositioned ) - SELF_GOTO( ( AREAP ) pArea, pArea->ulRecNo ); - else if ( !pArea->fRecordChanged ) - pArea->fValidBuffer = FALSE; + if( ulRecNo == pArea->ulRecNo ) + { + if( !pArea->fPositioned ) + { + SELF_GOTO( ( AREAP ) pArea, pArea->ulRecNo ); + } + else if( !pArea->fRecordChanged ) + { + SELF_GOCOLD( ( AREAP ) pArea ); + pArea->fValidBuffer = FALSE; + } + } } else * pResult = FALSE; @@ -444,9 +460,14 @@ static ERRCODE hb_dbfLockFile( DBFAREAP pArea, BOOL * pResult ) * pResult = pArea->fFLocked; if( !pArea->fPositioned ) + { SELF_GOTO( ( AREAP ) pArea, pArea->ulRecNo ); - else if ( !pArea->fRecordChanged ) + } + else if( !pArea->fRecordChanged ) + { + SELF_GOCOLD( ( AREAP ) pArea ); pArea->fValidBuffer = FALSE; + } } else * pResult = TRUE; @@ -507,6 +528,7 @@ static void hb_dbfGetLockArray( DBFAREAP pArea, PHB_ITEM pItem ) } } + /* * Converts EDBF_* error code into EG_* one. * This function is common for different DBF based RDD implementation @@ -572,12 +594,11 @@ ERRCODE HB_EXPORT hb_dbfGetEGcode( ERRCODE errCode ) */ ULONG HB_EXPORT hb_dbfGetMemoBlock( DBFAREAP pArea, USHORT uiIndex ) { - ULONG ulBlock= 0 ; + ULONG ulBlock= 0; HB_TRACE(HB_TR_DEBUG, ("hb_dbfGetMemoBlock(%p, %hu)", pArea, uiIndex)); - /* 3/05/2004 Support 0x30 format DBF memo */ - if ( pArea->lpFields[ uiIndex ].uiLen == 4 ) + if( pArea->lpFields[ uiIndex ].uiLen == 4 ) { ulBlock = HB_GET_LE_UINT32( &pArea->pRecord[ pArea->pFieldOffset[ uiIndex ] ] ); } @@ -608,10 +629,9 @@ void HB_EXPORT hb_dbfPutMemoBlock( DBFAREAP pArea, USHORT uiIndex, ULONG ulBlock { HB_TRACE(HB_TR_DEBUG, ("hb_dbfPutMemoBlock(%p, %hu, %lu)", pArea, uiIndex, ulBlock)); - /* 3/05/2004 Support 0x30 format DBF memo */ - if ( pArea->lpFields[ uiIndex ].uiLen == 4 ) + if( pArea->lpFields[ uiIndex ].uiLen == 4 ) { - HB_PUT_LE_UINT32( &pArea->pRecord[ pArea->pFieldOffset[ uiIndex ] ], ulBlock ); + HB_PUT_LE_UINT32( &pArea->pRecord[ pArea->pFieldOffset[ uiIndex ] ], ulBlock ); } else { @@ -632,30 +652,152 @@ void HB_EXPORT hb_dbfPutMemoBlock( DBFAREAP pArea, USHORT uiIndex, ULONG ulBlock } } +/* + * Retrive memo field information stored in DBF file + * This function is common for different MEMO implementation + * so I left it in DBF. + */ +ERRCODE HB_EXPORT hb_dbfGetMemoData( DBFAREAP pArea, USHORT uiIndex, + ULONG * pulBlock, ULONG * pulSize, + ULONG * pulType ) +{ + HB_TRACE(HB_TR_DEBUG, ("hb_dbfGetMemoData(%p, %hu, %p, %p, %p)", pArea, uiIndex, pulBlock, pulSize, pulType)); + + *pulBlock = *pulSize = *pulType = 0; + + if( uiIndex >= pArea->uiFieldCount || pArea->lpFields[ uiIndex ].uiType != HB_IT_MEMO ) + return FAILURE; + + if( pArea->lpFields[ uiIndex ].uiLen == 4 ) + { + *pulBlock = HB_GET_LE_UINT32( &pArea->pRecord[ pArea->pFieldOffset[ uiIndex ] ] ); + return SUCCESS; + } + else if( pArea->lpFields[ uiIndex ].uiLen == 10 ) + { + ULONG ulValue; + + if( pArea->bMemoType == DB_MEMO_SMT ) + { + LPSMTFIELD pSMTFiled = ( LPSMTFIELD ) &pArea->pRecord[ pArea->pFieldOffset[ uiIndex ] ]; + + ulValue = HB_GET_LE_UINT16( pSMTFiled->type ); + if( ulValue != 0x2020 ) + { + *pulType = ulValue; + *pulSize = HB_GET_LE_UINT32( pSMTFiled->length ); + *pulBlock = HB_GET_LE_UINT32( pSMTFiled->block ); + } + } + else + { + USHORT uiCount; + BYTE bByte; + + ulValue = 0; + for( uiCount = 0; uiCount < 10; uiCount++ ) + { + bByte = pArea->pRecord[ pArea->pFieldOffset[ uiIndex ] + uiCount ]; + if( bByte >= '0' && bByte <= '9' ) + ulValue = ulValue * 10 + ( bByte - '0' ); + else if( bByte != ' ' ) + return FAILURE; + } + *pulBlock = ulValue; + } + return SUCCESS; + } + + return FAILURE; +} + +/* + * Write memo data information into memo field in DBF file + * This function is common for different MEMO implementation + * so I left it in DBF. + */ +ERRCODE HB_EXPORT hb_dbfSetMemoData( DBFAREAP pArea, USHORT uiIndex, + ULONG ulBlock, ULONG ulSize, ULONG ulType ) +{ + HB_TRACE(HB_TR_DEBUG, ("hb_dbfSetMemoData(%p, %hu, %lu, %lu, %lu)", pArea, uiIndex, ulBlock, ulSize, ulType)); + + if( uiIndex >= pArea->uiFieldCount || pArea->lpFields[ uiIndex ].uiType != HB_IT_MEMO ) + return FAILURE; + + if( pArea->lpFields[ uiIndex ].uiLen == 4 ) + { + HB_PUT_LE_UINT32( &pArea->pRecord[ pArea->pFieldOffset[ uiIndex ] ], ulBlock ); + return SUCCESS; + } + else if( pArea->lpFields[ uiIndex ].uiLen == 10 ) + { + if( pArea->bMemoType == DB_MEMO_SMT ) + { + LPSMTFIELD pSMTFiled = ( LPSMTFIELD ) &pArea->pRecord[ pArea->pFieldOffset[ uiIndex ] ]; + + HB_PUT_LE_UINT16( pSMTFiled->type, ulType ); + HB_PUT_LE_UINT32( pSMTFiled->length, ulSize ); + HB_PUT_LE_UINT32( pSMTFiled->block, ulBlock ); + } + else + { + SHORT iCount; + + for( iCount = 9; iCount >= 0; iCount-- ) + { + if( ulBlock > 0 ) + { + pArea->pRecord[ pArea->pFieldOffset[ uiIndex ] + iCount ] = ( BYTE )( ulBlock % 10 ) + '0'; + ulBlock /= 10; + } + else + { + pArea->pRecord[ pArea->pFieldOffset[ uiIndex ] + iCount ] = ' '; + } + } + } + return SUCCESS; + } + + return FAILURE; +} + /* * Get information about locking schemes for additional files (MEMO, INDEX) * This function is common for different MEMO implementation * so I left it in DBF. */ -BOOL HB_EXPORT hb_dbfLockIdxGetData( BYTE bScheme, ULONG *ulPos, ULONG *ulPool ) +BOOL HB_EXPORT hb_dbfLockIdxGetData( BYTE bScheme, HB_FOFFSET *ulPos, HB_FOFFSET *ulPool ) { switch ( bScheme ) { - case HB_SET_DBFLOCK_CLIP: + case DB_DBFLOCK_CLIP: *ulPos = IDX_LOCKPOS_CLIP; *ulPool = IDX_LOCKPOOL_CLIP; break; - case HB_SET_DBFLOCK_CL53: + case DB_DBFLOCK_CL53: *ulPos = IDX_LOCKPOS_CL53; *ulPool = IDX_LOCKPOOL_CL53; break; - case HB_SET_DBFLOCK_VFP: + case DB_DBFLOCK_CL53EXT: + *ulPos = IDX_LOCKPOS_CL53EXT; + *ulPool = IDX_LOCKPOOL_CL53EXT; + break; + + case DB_DBFLOCK_VFP: *ulPos = IDX_LOCKPOS_VFP; *ulPool = IDX_LOCKPOOL_VFP; break; +#ifndef HB_LONG_LONG_OFF + case DB_DBFLOCK_XHB64: + *ulPos = IDX_LOCKPOS_XHB64; + *ulPool = IDX_LOCKPOOL_XHB64; + break; +#endif + default: return FALSE; } @@ -667,12 +809,12 @@ BOOL HB_EXPORT hb_dbfLockIdxGetData( BYTE bScheme, ULONG *ulPos, ULONG *ulPool ) * This function is common for different MEMO implementation * so I left it in DBF. */ -BOOL HB_EXPORT hb_dbfLockIdxFile( FHANDLE hFile, BYTE bScheme, USHORT usMode, ULONG *pPoolPos ) +BOOL HB_EXPORT hb_dbfLockIdxFile( FHANDLE hFile, BYTE bScheme, USHORT usMode, HB_FOFFSET *pPoolPos ) { - ULONG ulPos, ulPool, ulSize = 1; + HB_FOFFSET ulPos, ulPool, ulSize = 1; BOOL fRet = FALSE, fWait; - if ( !hb_dbfLockIdxGetData( bScheme, &ulPos, &ulPool ) ) + if( !hb_dbfLockIdxGetData( bScheme, &ulPos, &ulPool ) ) { return fRet ; } @@ -682,10 +824,10 @@ BOOL HB_EXPORT hb_dbfLockIdxFile( FHANDLE hFile, BYTE bScheme, USHORT usMode, UL switch ( usMode & FL_MASK ) { case FL_LOCK: - if ( ulPool ) + if( ulPool ) { - if ( ( usMode & FLX_SHARED ) != 0 ) - *pPoolPos = (ULONG) ( hb_random_num() * ulPool ) + 1; + if( ( usMode & FLX_SHARED ) != 0 ) + *pPoolPos = ( HB_FOFFSET ) ( hb_random_num() * ulPool ) + 1; else { *pPoolPos = 0; @@ -699,9 +841,9 @@ BOOL HB_EXPORT hb_dbfLockIdxFile( FHANDLE hFile, BYTE bScheme, USHORT usMode, UL break; case FL_UNLOCK: - if ( ulPool ) + if( ulPool ) { - if ( ! *pPoolPos ) + if( ! *pPoolPos ) ulSize = ulPool + 1; } else @@ -713,11 +855,11 @@ BOOL HB_EXPORT hb_dbfLockIdxFile( FHANDLE hFile, BYTE bScheme, USHORT usMode, UL default: return FALSE; } - fRet = hb_fsLock( hFile, ulPos + *pPoolPos, ulSize, usMode ); + fRet = hb_fsLockLarge( hFile, ulPos + *pPoolPos, ulSize, usMode ); fWait = ( !fRet && ( usMode & FLX_WAIT ) != 0 && ( usMode & FL_MASK ) == FL_LOCK ); /* TODO: call special error handler (LOCKHANDLER) here if fWait */ - } while ( fWait ); + } while( fWait ); return fRet; } @@ -801,7 +943,7 @@ static ERRCODE hb_dbfGoTo( DBFAREAP pArea, ULONG ulRecNo ) if( pArea->lpdbPendingRel ) { - if ( pArea->lpdbPendingRel->isScoped ) + if( pArea->lpdbPendingRel->isScoped ) SELF_FORCEREL( ( AREAP ) pArea ); else /* Reset parent rel struct */ pArea->lpdbPendingRel = NULL; @@ -821,10 +963,10 @@ static ERRCODE hb_dbfGoTo( DBFAREAP pArea, ULONG ulRecNo ) { pArea->ulRecNo = pArea->ulRecCount + 1; pArea->fBof = pArea->fEof = pArea->fValidBuffer = TRUE; - pArea->fPositioned = pArea->fDeleted = FALSE; + pArea->fPositioned = pArea->fDeleted = pArea->fEncrypted = FALSE; /* Clear record buffer */ - hb_dbfSetBlankRecord( pArea ) ; + hb_dbfSetBlankRecord( pArea ); } pArea->fFound = FALSE; @@ -894,6 +1036,9 @@ static ERRCODE hb_dbfSkip( DBFAREAP pArea, LONG lToSkip ) uiError = SELF_SKIPRAW( ( AREAP ) pArea, lToSkip ); + /* TODO: remove this hack - it's not necessary if SKIPRAW works + as it should, Druzus */ + /* Move first record and set Bof flag */ if( uiError == SUCCESS && pArea->fBof && lToSkip < 0 ) { @@ -915,26 +1060,45 @@ static ERRCODE hb_dbfSkip( DBFAREAP pArea, LONG lToSkip ) */ static ERRCODE hb_dbfSkipRaw( DBFAREAP pArea, LONG lToSkip ) { - BOOL bBof, bEof; + ERRCODE uiError; HB_TRACE(HB_TR_DEBUG, ("hb_dbfSkipRaw(%p, %ld)", pArea, lToSkip)); + if( pArea->lpdbPendingRel ) + SELF_FORCEREL( ( AREAP ) pArea ); + if( lToSkip == 0 ) { - /* Save flags */ - bBof = pArea->fBof; - bEof = pArea->fEof; + if( pArea->fPositioned ) + { + BOOL bBof, bEof; - SELF_GOTO( ( AREAP ) pArea, pArea->ulRecNo ); + /* Save flags */ + bBof = pArea->fBof; + bEof = pArea->fEof; - /* Restore flags */ - pArea->fBof = bBof; - pArea->fEof = bEof; - return SUCCESS; + uiError = SELF_GOTO( ( AREAP ) pArea, pArea->ulRecNo ); + + /* Restore flags */ + pArea->fBof = bBof; + pArea->fEof = bEof; + } + else + { + uiError = SUCCESS; + } + } + else if( lToSkip < 0 && ( ULONG ) ( -lToSkip ) >= pArea->ulRecNo ) + { + uiError = SELF_GOTO( ( AREAP ) pArea, 1 ); + pArea->fBof = TRUE; } else - return SELF_GOTO( ( AREAP ) pArea, pArea->ulRecNo + lToSkip ); - /* return SELF_GOTO( ( AREAP ) pArea, ((LONG)pArea->ulRecNo + lToSkip) <= 0 ? 0 : (pArea->ulRecNo + lToSkip)); */ + { + uiError = SELF_GOTO( ( AREAP ) pArea, pArea->ulRecNo + lToSkip ); + } + + return uiError; } /* @@ -962,6 +1126,11 @@ static ERRCODE hb_dbfAppend( DBFAREAP pArea, BOOL bUnLockAll ) HB_TRACE(HB_TR_DEBUG, ("hb_dbfAppend(%p, %d)", pArea, (int) bUnLockAll)); + if( SELF_GOCOLD( ( AREAP ) pArea ) == FAILURE ) + return FAILURE; + + /* TODO: EVENT_APPEND call (stopped) */ + if( pArea->fReadonly ) { pError = hb_errNew(); @@ -973,12 +1142,9 @@ static ERRCODE hb_dbfAppend( DBFAREAP pArea, BOOL bUnLockAll ) return FAILURE; } - if( SELF_GOCOLD( ( AREAP ) pArea ) == FAILURE ) - return FAILURE; - if( pArea->lpdbPendingRel ) { - if ( pArea->lpdbPendingRel->isScoped ) + if( pArea->lpdbPendingRel->isScoped ) SELF_FORCEREL( ( AREAP ) pArea ); else /* Reset parent rel struct */ pArea->lpdbPendingRel = NULL; @@ -1019,6 +1185,7 @@ static ERRCODE hb_dbfAppend( DBFAREAP pArea, BOOL bUnLockAll ) pArea->ulRecCount ++; pArea->ulRecNo = pArea->ulRecCount; pArea->fDeleted = pArea->fBof = pArea->fEof = pArea->fFound = FALSE; + pArea->fEncrypted = pArea->pCryptKey != NULL && !pArea->fHasMemo; if( pArea->fShared ) { @@ -1036,6 +1203,8 @@ static ERRCODE hb_dbfDeleteRec( DBFAREAP pArea ) { HB_TRACE(HB_TR_DEBUG, ("hb_dbfDeleteRec(%p)", pArea)); + /* TODO: EVENT_DELETE call (stopped) */ + if( pArea->lpdbPendingRel ) SELF_FORCEREL( ( AREAP ) pArea ); @@ -1088,9 +1257,9 @@ static ERRCODE hb_dbfFlush( DBFAREAP pArea ) SELF_WRITEDBHEADER( ( AREAP ) pArea ); } - if ( hb_set.HB_SET_HARDCOMMIT ) + if( hb_set.HB_SET_HARDCOMMIT ) { - if ( pArea->fDataFlush ) + if( pArea->fDataFlush ) { hb_fsCommit( pArea->hDataFile ); pArea->fDataFlush = FALSE; @@ -1112,15 +1281,19 @@ static ERRCODE hb_dbfGetRec( DBFAREAP pArea, BYTE ** pBuffer ) { HB_TRACE(HB_TR_DEBUG, ("hb_dbfGetRec(%p, %p)", pArea, pBuffer)); - if ( pBuffer != NULL ) + if( pBuffer != NULL ) { + /* Read record */ + if( !pArea->fValidBuffer && !hb_dbfReadRecord( pArea ) ) + return FAILURE; + *pBuffer = pArea->pRecord; } else { /* Read data from file */ - hb_fsSeekLarge( pArea->hDataFile, ( HB_FOFFSET ) pArea->uiHeaderLen + - ( HB_FOFFSET ) ( pArea->ulRecNo - 1 ) * + hb_fsSeekLarge( pArea->hDataFile, ( HB_FOFFSET ) pArea->uiHeaderLen + + ( HB_FOFFSET ) ( pArea->ulRecNo - 1 ) * ( HB_FOFFSET ) pArea->uiRecordLen, FS_SET ); if( hb_fsRead( pArea->hDataFile, pArea->pRecord, pArea->uiRecordLen ) != pArea->uiRecordLen ) @@ -1130,10 +1303,27 @@ static ERRCODE hb_dbfGetRec( DBFAREAP pArea, BYTE ** pBuffer ) hb_errPutGenCode( pError, EG_READ ); hb_errPutDescription( pError, hb_langDGetErrorDesc( EG_READ ) ); hb_errPutSubCode( pError, EDBF_READ ); + hb_errPutOsCode( pError, hb_fsError() ); + hb_errPutFileName( pError, pArea->szDataFileName ); SELF_ERROR( ( AREAP ) pArea, pError ); hb_itemRelease( pError ); return FAILURE; } + + if( pArea->pRecord[ 0 ] == 'D' || pArea->pRecord[ 0 ] == 'E' ) + { + pArea->fEncrypted = TRUE; + pArea->pRecord[ 0 ] = pArea->pRecord[ 0 ] == 'D' ? '*' : ' '; + if( pArea->pCryptKey && pArea->bCryptType == DB_CRYPT_SIX ) + { + hb_sxDeCrypt( pArea->pRecord + 1, pArea->pRecord + 1, + pArea->pCryptKey, pArea->uiRecordLen - 1 ); + } + } + else + { + pArea->fEncrypted = FALSE; + } } return SUCCESS; } @@ -1144,8 +1334,7 @@ static ERRCODE hb_dbfGetRec( DBFAREAP pArea, BYTE ** pBuffer ) static ERRCODE hb_dbfGetValue( DBFAREAP pArea, USHORT uiIndex, PHB_ITEM pItem ) { LPFIELD pField; - char szBuffer[ 256 ]; - BOOL bError; + BOOL fError; PHB_ITEM pError; HB_TRACE(HB_TR_DEBUG, ("hb_dbfGetValue(%p, %hu, %p)", pArea, uiIndex, pItem)); @@ -1157,17 +1346,27 @@ static ERRCODE hb_dbfGetValue( DBFAREAP pArea, USHORT uiIndex, PHB_ITEM pItem ) if( !pArea->fValidBuffer && !hb_dbfReadRecord( pArea ) ) return FAILURE; - bError = FALSE; + fError = FALSE; uiIndex--; pField = pArea->lpFields + uiIndex; switch( pField->uiType ) { case HB_IT_STRING: - hb_itemPutCL( pItem, ( char * ) pArea->pRecord + pArea->pFieldOffset[ uiIndex ], - pField->uiLen ); #ifndef HB_CDP_SUPPORT_OFF - hb_cdpnTranslate( pItem->item.asString.value, pArea->cdPage, hb_cdp_page, pField->uiLen ); + if( pArea->cdPage != hb_cdp_page ) + { + char * pVal = ( char * ) hb_xgrab( pField->uiLen + 1 ); + memcpy( pVal, pArea->pRecord + pArea->pFieldOffset[ uiIndex ], pField->uiLen ); + pVal[ pField->uiLen ] = '\0'; + hb_cdpnTranslate( pVal, pArea->cdPage, hb_cdp_page, pField->uiLen ); + hb_itemPutCPtr( pItem, pVal, pField->uiLen ); + } + else #endif + { + hb_itemPutCL( pItem, ( char * ) pArea->pRecord + pArea->pFieldOffset[ uiIndex ], + pField->uiLen ); + } break; case HB_IT_LOGICAL: @@ -1178,12 +1377,17 @@ static ERRCODE hb_dbfGetValue( DBFAREAP pArea, USHORT uiIndex, PHB_ITEM pItem ) break; case HB_IT_DATE: - if ( pField->uiLen == 3 ) + if( pField->uiLen == 3 ) { hb_itemPutDL( pItem, HB_GET_LE_UINT24( pArea->pRecord + pArea->pFieldOffset[ uiIndex ] ) ); } + else if( pField->uiLen == 4 ) + { + hb_itemPutDL( pItem, HB_GET_LE_UINT32( pArea->pRecord + pArea->pFieldOffset[ uiIndex ] ) ); + } else { + char szBuffer[ 9 ]; memcpy( szBuffer, pArea->pRecord + pArea->pFieldOffset[ uiIndex ], 8 ); szBuffer[ 8 ] = 0; hb_itemPutDS( pItem, szBuffer ); @@ -1213,7 +1417,7 @@ static ERRCODE hb_dbfGetValue( DBFAREAP pArea, USHORT uiIndex, PHB_ITEM pItem ) #endif break; default: - bError = TRUE; + fError = TRUE; break; } break; @@ -1226,12 +1430,12 @@ static ERRCODE hb_dbfGetValue( DBFAREAP pArea, USHORT uiIndex, PHB_ITEM pItem ) case HB_IT_LONG: /* DBASE documentation defines maximum numeric field size as 20 - * but Clipper alows to create longer fileds so I remove this + * but Clipper allows to create longer fields so I remove this * limit, Druzus */ /* if( pField->uiLen > 20 ) - bError = TRUE; + fError = TRUE; else */ { @@ -1261,14 +1465,30 @@ static ERRCODE hb_dbfGetValue( DBFAREAP pArea, USHORT uiIndex, PHB_ITEM pItem ) } break; + case HB_IT_ANY: + if( pField->uiLen == 3 ) + { + hb_itemPutDL( pItem, hb_sxPtoD( ( char * ) pArea->pRecord + pArea->pFieldOffset[ uiIndex ] ) ); + } + else if( pField->uiLen == 4 ) + { + hb_itemPutNIntLen( pItem, ( HB_LONG ) HB_GET_LE_INT32( pArea->pRecord + pArea->pFieldOffset[ uiIndex ] ), 10 ); + } + else + { + /* TODO: write into MEMO file */ + fError = TRUE; + } + break; + case HB_IT_MEMO: default: - bError = TRUE; + fError = TRUE; break; } /* Any error? */ - if( bError ) + if( fError ) { pError = hb_errNew(); hb_errPutGenCode( pError, EG_DATATYPE ); @@ -1288,13 +1508,6 @@ static ERRCODE hb_dbfGetVarLen( DBFAREAP pArea, USHORT uiIndex, ULONG * pLength { HB_TRACE(HB_TR_DEBUG, ("hb_dbfGetVarLen(%p, %hu, %p)", pArea, uiIndex, pLength)); - if( pArea->lpdbPendingRel ) - SELF_FORCEREL( ( AREAP ) pArea ); - - /* Read record */ - if( !pArea->fValidBuffer && !hb_dbfReadRecord( pArea ) ) - return FAILURE; - * pLength = pArea->lpFields[ uiIndex - 1 ].uiLen; return SUCCESS; @@ -1310,7 +1523,7 @@ static ERRCODE hb_dbfGoCold( DBFAREAP pArea ) if( pArea->fRecordChanged ) { /* Write current record */ - if ( ! hb_dbfWriteRecord( pArea ) ) + if( ! hb_dbfWriteRecord( pArea ) ) return FAILURE; if( pArea->fAppend ) @@ -1321,7 +1534,7 @@ static ERRCODE hb_dbfGoCold( DBFAREAP pArea ) /* Update header */ if( pArea->fShared && pArea->fUpdateHeader ) - SELF_WRITEDBHEADER( ( AREAP ) pArea ); + return SELF_WRITEDBHEADER( ( AREAP ) pArea ); } return SUCCESS; } @@ -1367,28 +1580,67 @@ static ERRCODE hb_dbfPutRec( DBFAREAP pArea, BYTE * pBuffer ) { HB_TRACE(HB_TR_DEBUG, ("hb_dbfPutRec(%p, %p)", pArea, pBuffer)); - if ( pBuffer != NULL ) + if( pBuffer != NULL ) { + if( pArea->lpdbPendingRel ) + SELF_FORCEREL( ( AREAP ) pArea ); + + if( !pArea->fPositioned ) + return SUCCESS; + if( !pArea->fRecordChanged && SELF_GOHOT( ( AREAP ) pArea ) == FAILURE ) return FAILURE; /* Copy data to buffer */ memcpy( pArea->pRecord, pBuffer, pArea->uiRecordLen ); + + /* + * TODO: such operation should be forbidden + * maybe it will be good to return FAILURE when + * pArea->pRecord[ 0 ] != '*' && pArea->pRecord[ 0 ] != ' ' + */ + if( pArea->pRecord[ 0 ] == 'D' || pArea->pRecord[ 0 ] == 'E' ) + { + pArea->fEncrypted = TRUE; + pArea->pRecord[ 0 ] = pArea->pRecord[ 0 ] == 'D' ? '*' : ' '; + } + + pArea->fDeleted = pArea->pRecord[ 0 ] == '*'; } else /* if( pArea->fRecordChanged ) */ { + BYTE * pRecord = pArea->pRecord; + USHORT uiWritten; + + if( pArea->pCryptKey ) + { + if( pArea->bCryptType == DB_CRYPT_SIX && pArea->fEncrypted ) + { + pRecord = ( BYTE * ) hb_xgrab( pArea->uiRecordLen ); + pRecord[ 0 ] = pArea->fDeleted ? 'D' : 'E'; + hb_sxEnCrypt( pArea->pRecord + 1, pRecord + 1, pArea->pCryptKey, + pArea->uiRecordLen - 1 ); + } + } + /* Write data to file */ - hb_fsSeekLarge( pArea->hDataFile, ( HB_FOFFSET ) pArea->uiHeaderLen + - ( HB_FOFFSET ) ( pArea->ulRecNo - 1 ) * + hb_fsSeekLarge( pArea->hDataFile, ( HB_FOFFSET ) pArea->uiHeaderLen + + ( HB_FOFFSET ) ( pArea->ulRecNo - 1 ) * ( HB_FOFFSET ) pArea->uiRecordLen, FS_SET ); - if( hb_fsWrite( pArea->hDataFile, pArea->pRecord, pArea->uiRecordLen ) != - pArea->uiRecordLen ) + uiWritten = hb_fsWrite( pArea->hDataFile, pRecord, pArea->uiRecordLen ); + + if( pRecord != pArea->pRecord ) + hb_xfree( pRecord ); + + if( uiWritten != pArea->uiRecordLen ) { PHB_ITEM pError = hb_errNew(); hb_errPutGenCode( pError, EG_WRITE ); hb_errPutDescription( pError, hb_langDGetErrorDesc( EG_WRITE ) ); hb_errPutSubCode( pError, EDBF_WRITE ); + hb_errPutOsCode( pError, hb_fsError() ); + hb_errPutFileName( pError, pArea->szDataFileName ); SELF_ERROR( ( AREAP ) pArea, pError ); hb_itemRelease( pError ); return FAILURE; @@ -1406,7 +1658,7 @@ static ERRCODE hb_dbfPutValue( DBFAREAP pArea, USHORT uiIndex, PHB_ITEM pItem ) LPFIELD pField; /* this buffer is for date and number conversion, * DBASE documentation defines maximum numeric field size as 20 - * but Clipper alows to create longer fileds so I remove this limit, Druzus + * but Clipper allows to create longer fields so I remove this limit, Druzus */ char szBuffer[ 256 ]; PHB_ITEM pError; @@ -1459,25 +1711,35 @@ static ERRCODE hb_dbfPutValue( DBFAREAP pArea, USHORT uiIndex, PHB_ITEM pItem ) { if( pField->uiType == HB_IT_DATE ) { - if ( pField->uiLen == 3 ) + if( pField->uiLen == 3 ) { HB_PUT_LE_UINT24( pArea->pRecord + pArea->pFieldOffset[ uiIndex ], hb_itemGetDL( pItem ) ); } + else if( pField->uiLen == 4 ) + { + HB_PUT_LE_UINT32( pArea->pRecord + pArea->pFieldOffset[ uiIndex ], + hb_itemGetDL( pItem ) ); + } else { hb_itemGetDS( pItem, szBuffer ); memcpy( pArea->pRecord + pArea->pFieldOffset[ uiIndex ], szBuffer, 8 ); } } + else if( pField->uiType == HB_IT_ANY && pField->uiLen == 3 ) + { + hb_sxDtoP( ( char * ) pArea->pRecord + pArea->pFieldOffset[ uiIndex ], + hb_itemGetDL( pItem ) ); + } else uiError = EDBF_DATATYPE; } - else if( HB_IS_NUMERIC( pItem ) ) + else if( HB_IS_NUMBER( pItem ) ) { if( pField->uiType == HB_IT_LONG ) { - if ( hb_itemStrBuf( szBuffer, pItem, pField->uiLen, pField->uiDec ) ) + if( hb_itemStrBuf( szBuffer, pItem, pField->uiLen, pField->uiDec ) ) { memcpy( pArea->pRecord + pArea->pFieldOffset[ uiIndex ], szBuffer, pField->uiLen ); @@ -1489,12 +1751,12 @@ static ERRCODE hb_dbfPutValue( DBFAREAP pArea, USHORT uiIndex, PHB_ITEM pItem ) '*', pField->uiLen ); } } - else if ( pField->uiType == HB_IT_INTEGER ) + else if( pField->uiType == HB_IT_INTEGER ) { HB_LONG lVal; int iSize; - if ( HB_IS_DOUBLE( pItem ) && + if( HB_IS_DOUBLE( pItem ) && ! HB_DBL_LIM_INT64( pItem->item.asDouble.value ) ) { lVal = 0; @@ -1517,7 +1779,7 @@ static ERRCODE hb_dbfPutValue( DBFAREAP pArea, USHORT uiIndex, PHB_ITEM pItem ) lVal = hb_itemGetNL( pItem ); #endif } - if ( iSize > pField->uiLen ) + if( iSize > pField->uiLen ) { uiError = EDBF_DATAWIDTH; } @@ -1554,6 +1816,20 @@ static ERRCODE hb_dbfPutValue( DBFAREAP pArea, USHORT uiIndex, PHB_ITEM pItem ) { HB_PUT_LE_DOUBLE( pArea->pRecord + pArea->pFieldOffset[ uiIndex ], hb_itemGetND( pItem ) ); } + else if( pField->uiType == HB_IT_ANY && pField->uiLen == 4 ) + { + HB_LONG lVal = hb_itemGetNInt( pItem ); + if( HB_IS_DOUBLE( pItem ) ? + HB_DBL_LIM_INT32( pItem->item.asDouble.value ) : + HB_LIM_INT32( lVal ) ) + { + HB_PUT_LE_UINT32( pArea->pRecord + pArea->pFieldOffset[ uiIndex ], ( UINT32 ) lVal ); + } + else + { + uiError = EDBF_DATAWIDTH; + } + } else { uiError = EDBF_DATATYPE; @@ -1584,8 +1860,6 @@ static ERRCODE hb_dbfPutValue( DBFAREAP pArea, USHORT uiIndex, PHB_ITEM pItem ) /* return FAILURE; */ } - /* Update deleted flag */ - pArea->pRecord[ 0 ] = pArea->fDeleted ? '*' : ' '; return SUCCESS; } @@ -1633,16 +1907,46 @@ static ERRCODE hb_dbfRecCount( DBFAREAP pArea, ULONG * pRecCount ) /* * Obtain physical row number at current WorkArea cursor position. */ -static ERRCODE hb_dbfRecNo( DBFAREAP pArea, PHB_ITEM pRecNo ) +static ERRCODE hb_dbfRecNo( DBFAREAP pArea, ULONG * ulRecNo ) { - HB_TRACE(HB_TR_DEBUG, ("hb_dbfRecNo(%p, %p)", pArea, pRecNo)); + HB_TRACE(HB_TR_DEBUG, ("hb_dbfRecNo(%p, %p)", pArea, ulRecNo)); if( pArea->lpdbPendingRel ) SELF_FORCEREL( ( AREAP ) pArea ); - hb_itemPutNLLen( pRecNo, pArea->ulRecNo, 7 ); + + *ulRecNo = pArea->ulRecNo; return SUCCESS; } +/* + * Obtain physical row ID at current WorkArea cursor position. + */ +static ERRCODE hb_dbfRecId( DBFAREAP pArea, PHB_ITEM pRecNo ) +{ + ERRCODE errCode; + ULONG ulRecNo; + + HB_TRACE(HB_TR_DEBUG, ("hb_dbfRecId(%p, %p)", pArea, pRecNo)); + + errCode = SELF_RECNO( ( AREAP ) pArea, &ulRecNo ); + +#ifdef HB_C52_STRICT + /* this is for strict Clipper compatibility but IMHO Clipper should not + do that and always set fixed size independent to the record number */ + if( ulRecNo < 10000000 ) + { + hb_itemPutNLLen( pRecNo, ulRecNo, 7 ); + } + else + { + hb_itemPutNLLen( pRecNo, ulRecNo, 10 ); + } +#else + hb_itemPutNInt( pRecNo, ulRecNo ); +#endif + return errCode; +} + /* * Establish the extent of the array of fields for a WorkArea. */ @@ -1678,7 +1982,7 @@ static ERRCODE hb_dbfClose( DBFAREAP pArea ) SELF_GOCOLD( ( AREAP ) pArea ); /* Unlock all records */ - SELF_UNLOCK( ( AREAP ) pArea, 0 ); + SELF_UNLOCK( ( AREAP ) pArea, NULL ); /* Update header */ if( pArea->fUpdateHeader ) @@ -1688,7 +1992,7 @@ static ERRCODE hb_dbfClose( DBFAREAP pArea ) /* It's not Clipper compatible but it reduces the problem with byggy Windows network setting */ - if ( hb_set.HB_SET_HARDCOMMIT ) + if( hb_set.HB_SET_HARDCOMMIT ) { SELF_FLUSH( ( AREAP ) pArea ); } @@ -1717,6 +2021,14 @@ static ERRCODE hb_dbfClose( DBFAREAP pArea ) pArea->pRecord = NULL; } + /* Free encryption password key */ + if( pArea->pCryptKey ) + { + memset( pArea->pCryptKey, '\0', 8 ); + hb_xfree( pArea->pCryptKey ); + pArea->pCryptKey = NULL; + } + /* Free all filenames */ if( pArea->szDataFileName ) { @@ -1737,19 +2049,40 @@ static ERRCODE hb_dbfClose( DBFAREAP pArea ) */ static ERRCODE hb_dbfCreate( DBFAREAP pArea, LPDBOPENINFO pCreateInfo ) { + ERRCODE errCode; USHORT uiSize, uiCount; - BOOL fHasMemo, bRetry; + BOOL fRetry, fError; DBFFIELD * pBuffer, *pThisField; PHB_FNAME pFileName; - PHB_ITEM pFileExt, pError; + PHB_ITEM pItem = NULL, pError; + BYTE szFileName[ _POSIX_PATH_MAX + 1 ]; HB_TRACE(HB_TR_DEBUG, ("hb_dbfCreate(%p, %p)", pArea, pCreateInfo)); + pFileName = hb_fsFNameSplit( ( char * ) pCreateInfo->abName ); + if( ! pFileName->szExtension ) + { + pItem = hb_itemPutC( pItem, "" ); + SELF_INFO( ( AREAP ) pArea, DBI_TABLEEXT, pItem ); + pFileName->szExtension = hb_itemGetCPtr( pItem ); + hb_fsFNameMerge( ( char * ) szFileName, pFileName ); + hb_itemRelease( pItem ); + pItem = NULL; + } + else + { + hb_strncpy( ( char * ) szFileName, ( char * ) pCreateInfo->abName, _POSIX_PATH_MAX ); + } + hb_xfree( pFileName ); + pError = NULL; /* Try create */ do { - pArea->hDataFile = hb_spCreate( pCreateInfo->abName, FC_NORMAL ); + pArea->hDataFile = hb_fsExtOpen( szFileName, NULL, + FO_READWRITE | FO_EXCLUSIVE | FXO_TRUNCATE | + FXO_DEFAULTS | FXO_SHARELOCK | FXO_COPYNAME, + NULL, pError ); if( pArea->hDataFile == FS_ERROR ) { if( !pError ) @@ -1759,14 +2092,14 @@ static ERRCODE hb_dbfCreate( DBFAREAP pArea, LPDBOPENINFO pCreateInfo ) hb_errPutSubCode( pError, EDBF_CREATE_DBF ); hb_errPutOsCode( pError, hb_fsError() ); hb_errPutDescription( pError, hb_langDGetErrorDesc( EG_CREATE ) ); - hb_errPutFileName( pError, ( char * ) pCreateInfo->abName ); + hb_errPutFileName( pError, ( char * ) szFileName ); hb_errPutFlags( pError, EF_CANRETRY | EF_CANDEFAULT ); } - bRetry = ( SELF_ERROR( ( AREAP ) pArea, pError ) == E_RETRY ); + fRetry = ( SELF_ERROR( ( AREAP ) pArea, pError ) == E_RETRY ); } else - bRetry = FALSE; - } while( bRetry ); + fRetry = FALSE; + } while( fRetry ); if( pError ) { @@ -1778,149 +2111,272 @@ static ERRCODE hb_dbfCreate( DBFAREAP pArea, LPDBOPENINFO pCreateInfo ) return FAILURE; } - pArea->szDataFileName = (char *) hb_xgrab( strlen( (char * ) pCreateInfo->abName)+1 ); - strcpy( pArea->szDataFileName, ( char * ) pCreateInfo->abName ); + pArea->szDataFileName = hb_strdup( ( char * ) szFileName ); uiSize = pArea->uiFieldCount * sizeof( DBFFIELD ); pBuffer = ( DBFFIELD * ) hb_xgrab( uiSize ); memset( pBuffer, 0, uiSize ); pThisField = pBuffer; + /* Size for deleted flag */ pArea->uiRecordLen = 1; - pArea->bVersion = s_dbfVersion; - fHasMemo = FALSE; + if( pArea->bTableType == 0 ) + { + pItem = hb_itemPutNI( pItem, 0 ); + if( SELF_INFO( ( AREAP ) pArea, DBI_TABLETYPE, pItem ) != SUCCESS ) + { + hb_itemRelease( pItem ); + return FAILURE; + } + pArea->bTableType = hb_itemGetNI( pItem ); + } + + if( pArea->bLockType == 0 ) + { + pItem = hb_itemPutNI( pItem, 0 ); + if( SELF_INFO( ( AREAP ) pArea, DBI_LOCKSCHEME, pItem ) != SUCCESS ) + { + hb_itemRelease( pItem ); + return FAILURE; + } + pArea->bLockType = hb_itemGetNI( pItem ); + if( pArea->bLockType == 0 ) + { + pArea->bLockType = DB_DBFLOCK_CLIP; + } + } + + if( pArea->bTableType == DB_DBF_VFP ) + { + pArea->bMemoType = DB_MEMO_FPT; + } + else if( pArea->bMemoType == 0 ) + { + /* get memo type */ + pItem = hb_itemPutNI( pItem, 0 ); + if( SELF_INFO( ( AREAP ) pArea, DBI_MEMOTYPE, pItem ) != SUCCESS ) + { + hb_itemRelease( pItem ); + return FAILURE; + } + pArea->bMemoType = ( BYTE ) hb_itemGetNI( pItem ); + } + + pArea->bCryptType = DB_CRYPT_NONE; + + if( pItem ) + { + hb_itemRelease( pItem ); + } + + pArea->fHasMemo = fError = FALSE; for( uiCount = 0; uiCount < pArea->uiFieldCount; uiCount++ ) { + LPFIELD pField = pArea->lpFields + uiCount; strncpy( ( char * ) pThisField->bName, - ( ( PHB_DYNS ) pArea->lpFields[ uiCount ].sym )->pSymbol->szName, 10 ); - switch( pArea->lpFields[ uiCount ].uiType ) + ( ( PHB_DYNS ) pField->sym )->pSymbol->szName, 10 ); + pArea->pFieldOffset[ uiCount ] = pArea->uiRecordLen; + /* field offset */ + if( pArea->bTableType == DB_DBF_VFP ) + HB_PUT_LE_UINT16( pThisField->bReserved1, pArea->uiRecordLen ); + + switch( pField->uiType ) { case HB_IT_STRING: pThisField->bType = 'C'; - pThisField->bLen = ( BYTE ) pArea->lpFields[ uiCount ].uiLen; - pThisField->bDec = ( BYTE ) ( pArea->lpFields[ uiCount ].uiLen / 256 ); - pArea->uiRecordLen += pArea->lpFields[ uiCount ].uiLen; + pThisField->bLen = ( BYTE ) pField->uiLen; + pThisField->bDec = ( BYTE ) ( pField->uiLen >> 8 ); + pArea->uiRecordLen += pField->uiLen; break; case HB_IT_LOGICAL: pThisField->bType = 'L'; pThisField->bLen = 1; pThisField->bDec = 0; - pArea->uiRecordLen ++; + pArea->uiRecordLen++; break; case HB_IT_MEMO: pThisField->bType = 'M'; - pThisField->bLen = ( BYTE ) pArea->lpFields[ uiCount ].uiLen; - if ( pThisField->bLen != 4 ) - pThisField->bLen = 10; + if( pField->uiLen != 4 || pArea->bMemoType == DB_MEMO_SMT ) + { + pField->uiLen = 10; + } + pThisField->bLen = ( BYTE ) pField->uiLen; pThisField->bDec = 0; pArea->uiRecordLen += pThisField->bLen; - fHasMemo = TRUE; + pArea->fHasMemo = TRUE; + break; + + case HB_IT_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; + */ break; case HB_IT_DATE: pThisField->bType = 'D'; - pThisField->bLen = ( BYTE ) pArea->lpFields[ uiCount ].uiLen; - if ( pThisField->bLen != 3 ) - pThisField->bLen = 8; + if( pField->uiLen != 3 && pField->uiLen != 4 ) + { + pField->uiLen = pThisField->bLen = 8; + } + pThisField->bLen = ( BYTE ) pField->uiLen; pThisField->bDec = 0; pArea->uiRecordLen += pThisField->bLen; break; case HB_IT_LONG: pThisField->bType = 'N'; - pThisField->bLen = ( BYTE ) pArea->lpFields[ uiCount ].uiLen; - pThisField->bDec = ( BYTE ) pArea->lpFields[ uiCount ].uiDec; - pArea->uiRecordLen += pArea->lpFields[ uiCount ].uiLen; + pThisField->bLen = ( BYTE ) pField->uiLen; + pThisField->bDec = ( BYTE ) pField->uiDec; + pArea->uiRecordLen += pThisField->bLen; break; case HB_IT_DOUBLE: pThisField->bType = 'B'; - pThisField->bLen = 8; - pThisField->bDec = ( BYTE ) pArea->lpFields[ uiCount ].uiDec; - pArea->uiRecordLen += pArea->lpFields[ uiCount ].uiLen; + pField->uiLen = 8; + pThisField->bLen = ( BYTE ) pField->uiLen; + pThisField->bDec = ( BYTE ) pField->uiDec; + pArea->uiRecordLen += pThisField->bLen; break; case HB_IT_INTEGER: pThisField->bType = 'I'; - pThisField->bLen = ( BYTE ) pArea->lpFields[ uiCount ].uiLen; - if ( ( pThisField->bLen > 4 && pThisField->bLen != 8 ) || - pThisField->bLen == 0 ) - pThisField->bLen = 4; + if( ( pField->uiLen > 4 && pField->uiLen != 8 ) || + pField->uiLen == 0 ) + { + pField->uiLen = 4; + } + pThisField->bLen = ( BYTE ) pField->uiLen; pThisField->bDec = 0; - pArea->uiRecordLen += pArea->lpFields[ uiCount ].uiLen; + pArea->uiRecordLen += pThisField->bLen; break; default: - hb_xfree( pBuffer ); - return FAILURE; + fError = TRUE; + } + if( fError ) + { + hb_xfree( pBuffer ); + SELF_CLOSE( ( AREAP ) pArea ); + + pError = hb_errNew(); + hb_errPutGenCode( pError, EG_CREATE ); + hb_errPutSubCode( pError, EDBF_DATATYPE ); + hb_errPutDescription( pError, hb_langDGetErrorDesc( EG_CREATE ) ); + hb_errPutFileName( pError, ( char * ) pCreateInfo->abName ); + SELF_ERROR( ( AREAP ) pArea, pError ); + hb_itemRelease( pError ); + + return FAILURE; } pThisField++ ; } - pArea->fShared = pCreateInfo->fShared; + pArea->fShared = FALSE; /* pCreateInfo->fShared; */ + pArea->fReadonly = FALSE; /* pCreateInfo->fReadonly */ pArea->ulRecCount = 0; - pArea->uiHeaderLen = sizeof( DBFHEADER ) + uiSize + ( pArea->bVersion == 0x30 ? 1 : 2 ); - pArea->fHasMemo = fHasMemo; + pArea->uiHeaderLen = sizeof( DBFHEADER ) + uiSize + + ( pArea->bTableType == DB_DBF_VFP ? 1 : 2 ); + if( !pArea->fHasMemo ) + { + pArea->bMemoType = DB_MEMO_NONE; + } pArea->uiMemoBlockSize = 0; - /* Write header */ - if ( SELF_WRITEDBHEADER( ( AREAP ) pArea ) == FAILURE ) +#ifndef HB_CDP_SUPPORT_OFF + if( pCreateInfo->cdpId ) + { + pArea->cdPage = hb_cdpFind( (char *) pCreateInfo->cdpId ); + if( !pArea->cdPage ) + pArea->cdPage = hb_cdp_page; + } + else + pArea->cdPage = hb_cdp_page; +#endif + + /* Write header */ + errCode = SELF_WRITEDBHEADER( ( AREAP ) pArea ); + if( errCode != SUCCESS ) { - hb_fsClose( pArea->hDataFile ); - pArea->hDataFile = FS_ERROR; hb_xfree( pBuffer ); - return FAILURE; + SELF_CLOSE( ( AREAP ) pArea ); + return errCode; } /* Write fields and eof mark */ - if ( hb_fsWrite( pArea->hDataFile, ( BYTE * ) pBuffer, uiSize ) != uiSize || - ( pArea->bVersion == 0x30 ? + if( hb_fsWrite( pArea->hDataFile, ( BYTE * ) pBuffer, uiSize ) != uiSize || + ( pArea->bTableType == DB_DBF_VFP ? hb_fsWrite( pArea->hDataFile, ( BYTE * ) "\r\032", 2 ) != 2 : hb_fsWrite( pArea->hDataFile, ( BYTE * ) "\r\0\032", 3 ) != 3 ) ) { - hb_fsClose( pArea->hDataFile ); - pArea->hDataFile = FS_ERROR; + /* TODO: add RT error */ hb_xfree( pBuffer ); + SELF_CLOSE( ( AREAP ) pArea ); return FAILURE; } + pArea->fDataFlush = TRUE; hb_xfree( pBuffer ); /* Create memo file */ - if ( fHasMemo ) + if( pArea->fHasMemo ) { - BYTE *tmp; - ERRCODE result; - pArea->szMemoFileName = ( char * ) hb_xgrab( _POSIX_PATH_MAX + 1 ); - pFileName = hb_fsFNameSplit( ( char * ) pCreateInfo->abName ); - pArea->szMemoFileName[ 0 ] = 0; - - if ( pFileName->szPath ) + pFileName = hb_fsFNameSplit( ( char * ) szFileName ); + pItem = hb_itemPutC( NULL, "" ); + errCode = SELF_INFO( ( AREAP ) pArea, DBI_MEMOEXT, pItem ); + if( errCode == SUCCESS ) { - strcat( pArea->szMemoFileName, pFileName->szPath ); + pFileName->szExtension = hb_itemGetCPtr( pItem ); + hb_fsFNameMerge( ( char * ) szFileName, pFileName ); + pArea->szMemoFileName = hb_strdup( ( char * ) szFileName ); } - - strcat( pArea->szMemoFileName, pFileName->szName ); + hb_itemRelease( pItem ); hb_xfree( pFileName ); - pFileExt = hb_itemPutC( NULL, "" ); - SELF_INFO( ( AREAP ) pArea, DBI_MEMOEXT, pFileExt ); - strncat( pArea->szMemoFileName, pFileExt->item.asString.value, - _POSIX_PATH_MAX - strlen( pArea->szMemoFileName ) ); - hb_itemRelease( pFileExt ); - tmp = pCreateInfo->abName; - pCreateInfo->abName = ( BYTE * ) pArea->szMemoFileName; - result = SELF_CREATEMEMFILE( ( AREAP ) pArea, pCreateInfo ); - pCreateInfo->abName = tmp; - - return result; + if( errCode == SUCCESS ) + { + BYTE *tmp = pCreateInfo->abName; + pCreateInfo->abName = ( BYTE * ) pArea->szMemoFileName; + errCode = SELF_CREATEMEMFILE( ( AREAP ) pArea, pCreateInfo ); + pCreateInfo->abName = tmp; + } } - else + /* If successful call SUPER_CREATE to finish system jobs */ + if( errCode == SUCCESS ) { - return SUCCESS; + errCode = SUPER_CREATE( ( AREAP ) pArea, pCreateInfo ); } + + if( errCode != SUCCESS ) + { + SELF_CLOSE( ( AREAP ) pArea ); + return errCode; + } + + /* Alloc buffer */ + pArea->pRecord = ( BYTE * ) hb_xgrab( pArea->uiRecordLen ); + pArea->fValidBuffer = FALSE; + + /* Update the number of record for corrupted headers */ + pArea->ulRecCount = hb_dbfCalcRecCount( pArea ); + + /* Position cursor at the first record */ + return SELF_GOTOP( ( AREAP ) pArea ); } /* @@ -1942,7 +2398,9 @@ static ERRCODE hb_dbfInfo( DBFAREAP pArea, USHORT uiIndex, PHB_ITEM pItem ) break; case DBI_LASTUPDATE: - hb_itemPutD( pItem, 1900 + pArea->bYear, pArea->bMonth, pArea->bDay ); + hb_itemPutD( pItem, 1900 + pArea->dbfHeader.bYear, + pArea->dbfHeader.bMonth, + pArea->dbfHeader.bDay ); break; case DBI_GETDELIMITER: @@ -1958,23 +2416,28 @@ static ERRCODE hb_dbfInfo( DBFAREAP pArea, USHORT uiIndex, PHB_ITEM pItem ) break; case DBI_TABLEEXT: - hb_itemPutC( pItem, DBF_TABLEEXT ); - break; + hb_itemClear( pItem ); + return SELF_RDDINFO( SELF_RDDNODE( pArea ), RDDI_TABLEEXT, 0, pItem ); case DBI_FULLPATH: hb_itemPutC( pItem, pArea->szDataFileName); break; - case DBI_MEMOEXT: - hb_itemPutC( pItem, "" ); + case DBI_MEMOTYPE: + hb_itemPutNI( pItem, DB_MEMO_NONE ); break; - case DBI_MEMOBLOCKSIZE: - hb_itemPutNI( pItem, pArea->uiMemoBlockSize ); + case DBI_TABLETYPE: + if( pArea->hDataFile == FS_ERROR ) + { + hb_itemClear( pItem ); + return SELF_RDDINFO( SELF_RDDNODE( pArea ), RDDI_TABLETYPE, 0, pItem ); + } + hb_itemPutNI( pItem, pArea->bTableType ); break; case DBI_FILEHANDLE: - hb_itemPutNL( pItem, (LONG)pArea->hDataFile ); + hb_itemPutNL( pItem, ( LONG ) pArea->hDataFile ); break; case DBI_MEMOHANDLE: @@ -1985,7 +2448,7 @@ static ERRCODE hb_dbfInfo( DBFAREAP pArea, USHORT uiIndex, PHB_ITEM pItem ) { BOOL fShared = pArea->fShared; - if ( HB_IS_LOGICAL( pItem ) ) + if( HB_IS_LOGICAL( pItem ) ) { pArea->fShared = hb_itemGetL( pItem ); } @@ -2011,22 +2474,34 @@ static ERRCODE hb_dbfInfo( DBFAREAP pArea, USHORT uiIndex, PHB_ITEM pItem ) case DBI_LOCKSCHEME: { SHORT bScheme = hb_itemGetNI( pItem ); - hb_itemPutNI( pItem, pArea->bLockType ); - switch ( bScheme ) + if( pArea->bLockType ) { - case HB_SET_DBFLOCK_CLIP: - case HB_SET_DBFLOCK_CL53: - case HB_SET_DBFLOCK_VFP: + hb_itemPutNI( pItem, pArea->bLockType ); + } + else + { + hb_itemClear( pItem ); + SELF_RDDINFO( SELF_RDDNODE( pArea ), RDDI_LOCKSCHEME, 0, pItem ); + } + switch( bScheme ) + { + case DB_DBFLOCK_CLIP: + case DB_DBFLOCK_CL53: + case DB_DBFLOCK_CL53EXT: + case DB_DBFLOCK_VFP: +#ifndef HB_LONG_LONG_OFF + case DB_DBFLOCK_XHB64: +#endif pArea->bLockType = (BYTE) bScheme; } break; } case DBI_ROLLBACK: - if ( pArea->fRecordChanged ) + if( pArea->fRecordChanged ) { - if ( pArea->fAppend ) + if( pArea->fAppend ) { - hb_dbfSetBlankRecord( pArea ) ; + hb_dbfSetBlankRecord( pArea ); pArea->fDeleted = FALSE; } else @@ -2036,8 +2511,85 @@ static ERRCODE hb_dbfInfo( DBFAREAP pArea, USHORT uiIndex, PHB_ITEM pItem ) } break; + case DBI_PASSWORD: + { + BYTE byBuffer[ 8 ]; + ULONG ulLen = 0; + BOOL fSet = !pArea->fHasMemo && HB_IS_STRING( pItem ); + + if( fSet ) + { + ulLen = hb_itemGetCLen( pItem ); + if( ulLen > 0 ) + { + if( ulLen < 8 ) + { + memcpy( byBuffer, hb_itemGetCPtr( pItem ), ulLen ); + memset( byBuffer + ulLen, '\0', 8 - ulLen ); + } + else + { + memcpy( byBuffer, hb_itemGetCPtr( pItem ), 8 ); + } + } + } + + if( pArea->pCryptKey ) + hb_itemPutCL( pItem, ( char * ) pArea->pCryptKey, 8 ); + else + hb_itemClear( pItem ); + + if( fSet ) + { + if( pArea->fPositioned ) + { + SELF_GOCOLD( ( AREAP ) pArea ); + pArea->fValidBuffer = FALSE; + } + if( pArea->pCryptKey ) + { + /* clean the memory with password key - though it's not + * a serious actions in such case ;-) + */ + memset( pArea->pCryptKey, '\0', 8 ); + hb_xfree( pArea->pCryptKey ); + pArea->pCryptKey = NULL; + } + if( ulLen > 0 ) + { + /* at this moment only one encryption method is used, + I'll add other later, [druzus] */ + pArea->bCryptType = DB_CRYPT_SIX; + pArea->pCryptKey = ( BYTE * ) hb_xgrab( 8 ); + /* SIX encode the key with its own value before use */ + hb_sxEnCrypt( byBuffer, pArea->pCryptKey, byBuffer, 8 ); + } + } + } + break; + + case DBI_DB_VERSION: + case DBI_RDD_VERSION: + { + char szBuf[ 64 ]; + int iSub = hb_itemGetNI( pItem ); + + if( iSub == 1 ) + snprintf( szBuf, sizeof( szBuf ), "%d.%d (%s)", 0, 1, "DBF" ); + else if( iSub == 2 ) + snprintf( szBuf, sizeof( szBuf ), "%d.%d (%s:%d)", 0, 1, "DBF", pArea->rddID ); +/* + snprintf( szBuf, sizeof( szBuf ), "%d.%d (%s:%d)", 0, 1, pArea->pRddNode->szName, pArea->rddID ); +*/ + else + snprintf( szBuf, sizeof( szBuf ), "%d.%d", 0, 1 ); + hb_itemPutC( pItem, szBuf ); + break; + } + default: return SUPER_INFO( ( AREAP ) pArea, uiIndex, pItem ); + } return SUCCESS; @@ -2048,44 +2600,47 @@ static ERRCODE hb_dbfInfo( DBFAREAP pArea, USHORT uiIndex, PHB_ITEM pItem ) */ static ERRCODE hb_dbfRecInfo( DBFAREAP pArea, PHB_ITEM pRecID, USHORT uiInfoType, PHB_ITEM pInfo ) { - ULONG ulRecNo = hb_itemGetNL( pRecID ); + ULONG ulRecNo = hb_itemGetNL( pRecID ), ulPrevRec = 0; + ERRCODE errResult = SUCCESS; + BOOL bDeleted; HB_TRACE(HB_TR_DEBUG, ("hb_dbfRecInfo(%p, %p, %hu, %p)", pArea, pRecID, uiInfoType, pInfo)); + if( pArea->lpdbPendingRel ) + SELF_FORCEREL( ( AREAP ) pArea ); if( ulRecNo == 0 ) { - if( pArea->lpdbPendingRel ) - SELF_FORCEREL( ( AREAP ) pArea ); ulRecNo = pArea->ulRecNo; } + else if( ulRecNo != pArea->ulRecNo ) + { + switch( uiInfoType ) + { + case DBRI_DELETED: + case DBRI_ENCRYPTED: + case DBRI_RAWRECORD: + case DBRI_RAWMEMOS: + case DBRI_RAWDATA: + ulPrevRec = pArea->ulRecNo; + SELF_GOTO( ( AREAP ) pArea, ulRecNo ); + break; + } + } switch( uiInfoType ) { case DBRI_DELETED: - { - BOOL bDeleted; - ULONG ulPrevRec = 0; - - if( pArea->lpdbPendingRel ) - SELF_FORCEREL( ( AREAP ) pArea ); - - if( pArea->ulRecNo != ulRecNo ) - { - ulPrevRec = pArea->ulRecNo; - SELF_GOTO( ( AREAP ) pArea, ulRecNo ); - } - SELF_DELETED( ( AREAP ) pArea, &bDeleted ); - if( ulPrevRec != 0 ) - { - SELF_GOTO( ( AREAP ) pArea, ulPrevRec ); - } - hb_itemPutL( pInfo, bDeleted ); + if( SELF_DELETED( ( AREAP ) pArea, &bDeleted ) != SUCCESS ) + errResult = FAILURE; + else + hb_itemPutL( pInfo, bDeleted ); break; - } case DBRI_LOCKED: - hb_itemPutL( pInfo, hb_dbfIsLocked( pArea, ulRecNo ) ); + /* Clipper also checks only fShared and RLOCK and ignore FLOCK */ + hb_itemPutL( pInfo, !pArea->fShared || /* pArea->fFLocked || */ + hb_dbfIsLocked( pArea, ulRecNo ) ); break; case DBRI_RECSIZE: @@ -2100,74 +2655,71 @@ static ERRCODE hb_dbfRecInfo( DBFAREAP pArea, PHB_ITEM pRecID, USHORT uiInfoType hb_itemPutL( pInfo, ulRecNo == pArea->ulRecNo && pArea->fRecordChanged ); break; + case DBRI_ENCRYPTED: + if( !pArea->fValidBuffer && !hb_dbfReadRecord( pArea ) ) + errResult = FAILURE; + else + hb_itemPutL( pInfo, pArea->fEncrypted ); + break; + case DBRI_RAWRECORD: + if( !pArea->fValidBuffer && !hb_dbfReadRecord( pArea ) ) + errResult = FAILURE; + else + hb_itemPutCL( pInfo, ( char * ) pArea->pRecord, pArea->uiRecordLen ); + break; + case DBRI_RAWMEMOS: case DBRI_RAWDATA: + { + USHORT uiFields; + BYTE *pResult ; + ULONG ulLength; + + if( !pArea->fHasMemo ) { - USHORT uiFields; - BYTE *pResult ; - HB_ITEM itItem = HB_ITEM_NIL ; - ULONG ulLength; - ULONG ulPrevRec = 0; - BOOL bDeleted; - if( pArea->ulRecNo != ulRecNo ) - { - ulPrevRec = pArea->ulRecNo; - SELF_GOTO( ( AREAP ) pArea, ulRecNo ); - } - SELF_DELETED( ( AREAP ) pArea, &bDeleted ); /* No need to allow for == FAILURE here */ - - if ( uiInfoType == DBRI_RAWRECORD || uiInfoType == DBRI_RAWDATA ) - { - ulLength = pArea->uiRecordLen; - pResult = (BYTE *) hb_xgrab( ulLength + 1 ) ; /* Allow final '\0' placed by hb_itemPutCPtr */ - /* Assume xgrab ok - no memory checking */ - memcpy( pResult, pArea->pRecord, ulLength ) ; - } - else - { - pResult = NULL; - ulLength = 0; - } - - if ( uiInfoType == DBRI_RAWMEMOS || uiInfoType == DBRI_RAWDATA ) - { - for ( uiFields = 0; uiFields < pArea->uiFieldCount ; uiFields++ ) - { - if ( pArea->lpFields[ uiFields ].uiType == HB_IT_MEMO ) - { - /* uiFields in SELF_GETVALUE() 1 based */ - if ( SELF_GETVALUE( ( AREAP ) pArea, uiFields + 1, &itItem ) == SUCCESS && - HB_IS_STRING( &itItem ) && itItem.item.asString.length > 0 ) - { - if ( pResult ) - { - pResult = (BYTE *) hb_xrealloc( pResult, ulLength + 1 + itItem.item.asString.length ); /* Assume xgrab ok - no memory checking */ - } - else - { - pResult = (BYTE *) hb_xgrab( itItem.item.asString.length + 1 ); /* Assume xgrab ok - no memory checking */ - } - memcpy( pResult + ulLength, itItem.item.asString.value, itItem.item.asString.length ); - ulLength += itItem.item.asString.length; - } - } - } - } - hb_itemClear( &itItem ); - hb_itemPutCPtr( pInfo, (char *) pResult, ulLength ); - - if( ulPrevRec != 0 ) - { - SELF_GOTO( ( AREAP ) pArea, ulPrevRec ); - } + hb_itemPutC( pInfo, "" ); break; } + if( !pArea->fValidBuffer && !hb_dbfReadRecord( pArea ) ) + { + errResult = FAILURE; + break; + } + ulLength = uiInfoType == DBRI_RAWDATA ? pArea->uiRecordLen : 0; + pResult = ( BYTE * ) hb_xgrab( ulLength + 1 ); + if( ulLength ) + { + memcpy( pResult, pArea->pRecord, ulLength ); + } + + for( uiFields = 0; uiFields < pArea->uiFieldCount ; uiFields++ ) + { + if( pArea->lpFields[ uiFields ].uiType == HB_IT_MEMO ) + { + errResult = SELF_GETVALUE( ( AREAP ) pArea, uiFields + 1, pInfo ); + if( errResult != SUCCESS ) + break; + if( HB_IS_STRING( pInfo ) && pInfo->item.asString.length > 0 ) + { + pResult = ( BYTE * ) hb_xrealloc( pResult, ulLength + pInfo->item.asString.length ); + } + memcpy( pResult + ulLength, pInfo->item.asString.value, pInfo->item.asString.length ); + ulLength += pInfo->item.asString.length; + } + } + hb_itemPutCPtr( pInfo, ( char * ) pResult, ulLength ); + break; + } default: - return SUPER_RECINFO( ( AREAP ) pArea, pRecID, uiInfoType, pInfo ); + errResult = SUPER_RECINFO( ( AREAP ) pArea, pRecID, uiInfoType, pInfo ); } - return SUCCESS; + if( ulPrevRec != 0 ) + { + SELF_GOTO( ( AREAP ) pArea, ulPrevRec ); + } + return errResult; } /* @@ -2193,33 +2745,33 @@ static ERRCODE hb_dbfNewArea( DBFAREAP pArea ) */ static ERRCODE hb_dbfOpen( DBFAREAP pArea, LPDBOPENINFO pOpenInfo ) { + ERRCODE errCode; USHORT uiFlags, uiFields, uiSize, uiCount; - BOOL bRetry, bError, bLock; + BOOL fRetry; PHB_ITEM pError, pFileExt; PHB_FNAME pFileName; BYTE * pBuffer; LPDBFFIELD pField; DBFIELDINFO pFieldInfo; - BYTE szPath[ _POSIX_PATH_MAX + 1 ]; + BYTE szFileName[ _POSIX_PATH_MAX + 1 ]; + char szAlias[ HARBOUR_MAX_RDD_ALIAS_LENGTH + 1 ]; HB_TRACE(HB_TR_DEBUG, ("hb_dbfOpen(%p, %p)", pArea, pOpenInfo)); - pArea->atomAlias = hb_dynsymGet( ( char * ) pOpenInfo->atomAlias ); - - if( ( ( PHB_DYNS ) pArea->atomAlias )->hArea ) + if( !pArea->bLockType ) { - hb_errRT_DBCMD( EG_DUPALIAS, EDBCMD_DUPALIAS, NULL, ( char * ) pOpenInfo->atomAlias ); - return FAILURE; - } + PHB_ITEM pItem = hb_itemNew( NULL ); - if ( !pArea->bLockType ) - { - if ( hb_set.HB_SET_DBFLOCKSCHEME ) - pArea->bLockType = hb_set.HB_SET_DBFLOCKSCHEME; - else - pArea->bLockType = HB_SET_DBFLOCK_CLIP; + if( SELF_INFO( ( AREAP ) pArea, DBI_LOCKSCHEME, pItem ) != SUCCESS ) + { + hb_itemRelease( pItem ); + return FAILURE; + } + pArea->bLockType = hb_itemGetNI( pItem ); + if( !pArea->bLockType ) + pArea->bLockType = DB_DBFLOCK_CLIP; + hb_itemRelease( pItem ); } - ( ( PHB_DYNS ) pArea->atomAlias )->hArea = pOpenInfo->uiArea; #ifndef HB_CDP_SUPPORT_OFF if( pOpenInfo->cdpId ) { @@ -2243,28 +2795,35 @@ static ERRCODE hb_dbfOpen( DBFAREAP pArea, LPDBOPENINFO pOpenInfo ) (pArea->fShared ? FO_DENYNONE : FO_EXCLUSIVE); pError = NULL; + pFileName = hb_fsFNameSplit( ( char * ) pOpenInfo->abName ); + /* Add default file name extension if necessary */ + if( ! pFileName->szExtension ) + { + pFileExt = hb_itemPutC( NULL, "" ); + SELF_INFO( ( AREAP ) pArea, DBI_TABLEEXT, pFileExt ); + pFileName->szExtension = hb_itemGetCPtr( pFileExt ); + hb_fsFNameMerge( ( char * ) szFileName, pFileName ); + hb_itemRelease( pFileExt ); + } + else + { + hb_strncpy( ( char * ) szFileName, ( char * ) pOpenInfo->abName, _POSIX_PATH_MAX ); + } + + /* Create default alias if necessary */ + if( !pOpenInfo->atomAlias ) + { + hb_strncpyUpperTrim( szAlias, pFileName->szName, HARBOUR_MAX_RDD_ALIAS_LENGTH ); + pOpenInfo->atomAlias = ( BYTE * ) szAlias; + } + hb_xfree( pFileName ); + /* Try open */ do { - bLock = FALSE; - if ( ! hb_spFile( pOpenInfo->abName, szPath ) ) - { - hb_strncpy( ( char * ) szPath, ( const char * ) pOpenInfo->abName, _POSIX_PATH_MAX ); - } - pArea->hDataFile = hb_spOpen( szPath, uiFlags ); -#ifdef DBF_EXLUSIVE_LOCKPOS - if( pArea->hDataFile != FS_ERROR ) - { - if ( !hb_fsLock( pArea->hDataFile, DBF_EXLUSIVE_LOCKPOS, DBF_EXLUSIVE_LOCKSIZE, - FL_LOCK | ( ( pArea->fShared || pArea->fReadonly ) ? - FLX_SHARED : FLX_EXCLUSIVE ) ) ) - { - hb_fsClose( pArea->hDataFile ); - pArea->hDataFile = FS_ERROR; - bLock = TRUE; - } - } -#endif + pArea->hDataFile = hb_fsExtOpen( szFileName, NULL, uiFlags | + FXO_DEFAULTS | FXO_SHARELOCK | FXO_COPYNAME, + NULL, pError ); if( pArea->hDataFile == FS_ERROR ) { if( !pError ) @@ -2272,32 +2831,16 @@ static ERRCODE hb_dbfOpen( DBFAREAP pArea, LPDBOPENINFO pOpenInfo ) pError = hb_errNew(); hb_errPutGenCode( pError, EG_OPEN ); hb_errPutSubCode( pError, EDBF_OPEN_DBF ); + hb_errPutOsCode( pError, hb_fsError() ); hb_errPutDescription( pError, hb_langDGetErrorDesc( EG_OPEN ) ); - hb_errPutFileName( pError, ( char * ) pOpenInfo->abName ); + hb_errPutFileName( pError, ( char * ) szFileName ); hb_errPutFlags( pError, EF_CANRETRY | EF_CANDEFAULT ); } - /* - * Temporary fix for neterr() support and Clipper compatibility, - * should be revised with a better solution. - */ - if ( hb_fsError() == EACCES || bLock ) - { - hb_errPutOsCode( pError, 32 ); - } - else if ( hb_fsError() == 0 ) - { - break; - } - else - { - hb_errPutOsCode( pError, hb_fsError() ); - } - - bRetry = ( SELF_ERROR( ( AREAP ) pArea, pError ) == E_RETRY ); + fRetry = ( SELF_ERROR( ( AREAP ) pArea, pError ) == E_RETRY ); } else - bRetry = FALSE; - } while( bRetry ); + fRetry = FALSE; + } while( fRetry ); if( pError ) { @@ -2308,18 +2851,19 @@ static ERRCODE hb_dbfOpen( DBFAREAP pArea, LPDBOPENINFO pOpenInfo ) /* Exit if error */ if( pArea->hDataFile == FS_ERROR ) { - pArea->szDataFileName = NULL; + SELF_CLOSE( ( AREAP ) pArea ); return FAILURE; } /* Allocate only after succesfully open file */ - pArea->szDataFileName = hb_strdup( ( char * ) szPath ); + pArea->szDataFileName = hb_strdup( ( char * ) szFileName ); /* Read file header and exit if error */ - if( SELF_READDBHEADER( ( AREAP ) pArea ) == FAILURE ) + errCode = SELF_READDBHEADER( ( AREAP ) pArea ); + if( errCode != SUCCESS ) { SELF_CLOSE( ( AREAP ) pArea ); - return FAILURE; + return errCode; } @@ -2334,7 +2878,7 @@ static ERRCODE hb_dbfOpen( DBFAREAP pArea, LPDBOPENINFO pOpenInfo ) hb_fsSeek( pArea->hDataFile, sizeof( DBFHEADER ), FS_SET ); if( hb_fsRead( pArea->hDataFile, pBuffer, uiSize ) != uiSize ) { - bError = TRUE; + errCode = FAILURE; if( !pError ) { pError = hb_errNew(); @@ -2344,11 +2888,15 @@ static ERRCODE hb_dbfOpen( DBFAREAP pArea, LPDBOPENINFO pOpenInfo ) hb_errPutFileName( pError, pArea->szDataFileName ); hb_errPutFlags( pError, EF_CANRETRY | EF_CANDEFAULT ); } - bRetry = ( SELF_ERROR( ( AREAP ) pArea, pError ) == E_RETRY ); + fRetry = ( SELF_ERROR( ( AREAP ) pArea, pError ) == E_RETRY ); } else - bRetry = bError = FALSE; - } while( bRetry ); + { + errCode = SUCCESS; + break; + } + } while( fRetry ); + if( pError ) { hb_itemRelease( pError ); @@ -2356,11 +2904,11 @@ static ERRCODE hb_dbfOpen( DBFAREAP pArea, LPDBOPENINFO pOpenInfo ) } /* Exit if error */ - if( bError ) + if( errCode != SUCCESS ) { hb_xfree( pBuffer ); SELF_CLOSE( ( AREAP ) pArea ); - return FAILURE; + return errCode; } /* some RDDs use the additional space in the header after field arrray @@ -2368,26 +2916,41 @@ static ERRCODE hb_dbfOpen( DBFAREAP pArea, LPDBOPENINFO pOpenInfo ) data as fields description */ for( uiCount = 0; uiCount < uiFields; uiCount++ ) { - if ( pBuffer[ uiCount * sizeof( DBFFIELD ) ] == 0x0d ) + if( pBuffer[ uiCount * sizeof( DBFFIELD ) ] == 0x0d ) { uiFields = uiCount; break; } + /* Peter added it for FVP DBFs but in wrong place, + anyhow I cannot see why it's necessary, FVP private data + in header should be after 0x0d - I disabled this code, [druzus] */ + /* + if( pArea->bTableType == DB_DBF_VFP && + pBuffer[ uiCount * sizeof( DBFFIELD ) ] == 0x00 ) + { + uiFields = uiCount; + break; + } + */ } - if ( uiFields == 0 ) + if( uiFields == 0 ) { - bError = TRUE; + errCode = FAILURE; } else { - SELF_SETFIELDEXTENT( ( AREAP ) pArea, uiFields ); + errCode = SELF_SETFIELDEXTENT( ( AREAP ) pArea, uiFields ); + if( errCode != SUCCESS ) + { + SELF_CLOSE( ( AREAP ) pArea ); + return errCode; + } } /* Size for deleted flag */ pArea->uiRecordLen = 1; - pFieldInfo.uiTypeExtended = 0; for( uiCount = 0; uiCount < uiFields; uiCount++ ) { pField = ( LPDBFFIELD ) ( pBuffer + uiCount * sizeof( DBFFIELD ) ); @@ -2396,6 +2959,7 @@ static ERRCODE hb_dbfOpen( DBFAREAP pArea, LPDBOPENINFO pOpenInfo ) hb_strUpper( (char *) pFieldInfo.atomName, 11 ); pFieldInfo.uiLen = pField->bLen; pFieldInfo.uiDec = 0; + pFieldInfo.uiTypeExtended = 0; switch( pField->bType ) { case 'C': @@ -2410,19 +2974,28 @@ static ERRCODE hb_dbfOpen( DBFAREAP pArea, LPDBOPENINFO pOpenInfo ) case 'M': pFieldInfo.uiType = HB_IT_MEMO; - pArea->fHasMemo = TRUE ; + pArea->fHasMemo = TRUE; + break; + + case 'V': + pFieldInfo.uiType = HB_IT_ANY; + if( pFieldInfo.uiLen >= 6 ) + { + pArea->uiMemoVersion = DB_MEMOVER_SIX; + pArea->fHasMemo = TRUE; + } break; case 'D': pFieldInfo.uiType = HB_IT_DATE; - if ( pFieldInfo.uiLen != 3 ) + if( pFieldInfo.uiLen != 3 && pFieldInfo.uiLen != 4 ) pFieldInfo.uiLen = 8; break; case 'I': pFieldInfo.uiType = HB_IT_INTEGER; - if ( ( pFieldInfo.uiLen > 4 && pFieldInfo.uiLen != 8 ) || - pFieldInfo.uiLen == 0 ) + if( ( pFieldInfo.uiLen > 4 && pFieldInfo.uiLen != 8 ) || + pFieldInfo.uiLen == 0 ) pFieldInfo.uiLen = 4; break; @@ -2436,12 +3009,12 @@ static ERRCODE hb_dbfOpen( DBFAREAP pArea, LPDBOPENINFO pOpenInfo ) case 'F': pFieldInfo.uiType = HB_IT_LONG; /* DBASE documentation defines maximum numeric field size as 20 - * but Clipper alows to create longer fileds so I remove this + * but Clipper allows to create longer fields so I removed this * limit, Druzus */ /* if( pField->bLen > 20 ) - bError = TRUE; + errCode = FAILURE; else */ pFieldInfo.uiDec = pField->bDec; @@ -2454,76 +3027,80 @@ static ERRCODE hb_dbfOpen( DBFAREAP pArea, LPDBOPENINFO pOpenInfo ) pFieldInfo.uiDec = pField->bDec; break; + /* types which are not supported by VM - mapped to different ones */ + case 'T': + case '@': + pFieldInfo.uiType = HB_IT_INTEGER; + break; + + case 'Y': + pFieldInfo.uiType = HB_IT_DOUBLE; + pFieldInfo.uiDec = pField->bDec; + default: - bError = TRUE; + errCode = FAILURE; break; } - /* Peter, is it necessary? - shouldn't be such filed after 0x0D terminator? - */ - if( pArea->bVersion == 0x30 && pField->bType == 0 ) - { - bError = FALSE; - break; - } - /* Add field */ - if( !bError ) - bError = ( SELF_ADDFIELD( ( AREAP ) pArea, &pFieldInfo ) == FAILURE ); + if( errCode == SUCCESS ) + errCode = SELF_ADDFIELD( ( AREAP ) pArea, &pFieldInfo ); /* Exit if error */ - if( bError ) + if( errCode != SUCCESS ) break; } hb_xfree( pBuffer ); - /* Open memo file if exists */ - /* Exit if error */ - if( bError ) + if( errCode != SUCCESS ) { - if( !pError ) - { - pError = hb_errNew(); - hb_errPutGenCode( pError, EG_CORRUPTION ); - hb_errPutSubCode( pError, EDBF_CORRUPT ); - hb_errPutDescription( pError, hb_langDGetErrorDesc( EG_CORRUPTION ) ); - hb_errPutFileName( pError, pArea->szDataFileName ); - hb_errPutFlags( pError, EF_CANRETRY | EF_CANDEFAULT ); - } + pError = hb_errNew(); + hb_errPutGenCode( pError, EG_CORRUPTION ); + hb_errPutSubCode( pError, EDBF_CORRUPT ); + hb_errPutDescription( pError, hb_langDGetErrorDesc( EG_CORRUPTION ) ); + hb_errPutFileName( pError, pArea->szDataFileName ); + hb_errPutFlags( pError, EF_CANDEFAULT ); SELF_ERROR( ( AREAP ) pArea, pError ); hb_itemRelease( pError ); SELF_CLOSE( ( AREAP ) pArea ); - return FAILURE; + return errCode; } + /* Open memo file if exists */ if( pArea->fHasMemo ) { - BYTE *tmp; - pFileName = hb_fsFNameSplit( ( char * ) szPath ); + pFileName = hb_fsFNameSplit( ( char * ) szFileName ); pFileExt = hb_itemPutC( NULL, "" ); - SELF_INFO( ( AREAP ) pArea, DBI_MEMOEXT, pFileExt ); - - szPath[ 0 ] = 0; - if( pFileName->szPath ) - strcat( ( char * ) szPath, pFileName->szPath ); - strncat( ( char * ) szPath, pFileName->szName, _POSIX_PATH_MAX - strlen( ( char * ) szPath ) ); - strncat( ( char * ) szPath, pFileExt->item.asString.value, _POSIX_PATH_MAX - strlen( ( char * ) szPath ) ); + errCode = SELF_INFO( ( AREAP ) pArea, DBI_MEMOEXT, pFileExt ); + if( errCode == SUCCESS ) + { + pFileName->szExtension = hb_itemGetCPtr( pFileExt ); + hb_fsFNameMerge( ( char * ) szFileName, pFileName ); + } hb_itemRelease( pFileExt ); hb_xfree( pFileName ); - tmp = pOpenInfo->abName; - pOpenInfo->abName = szPath; - pArea->szMemoFileName = hb_strdup( ( char * ) szPath ); - - /* Open memo file and exit if error */ - if( SELF_OPENMEMFILE( ( AREAP ) pArea, pOpenInfo ) == FAILURE ) + if( errCode == SUCCESS ) { + BYTE * tmp = pOpenInfo->abName; + pArea->szMemoFileName = hb_strdup( ( char * ) szFileName ); + pOpenInfo->abName = ( BYTE * ) pArea->szMemoFileName; + /* Open memo file and exit if error */ + errCode = SELF_OPENMEMFILE( ( AREAP ) pArea, pOpenInfo ); pOpenInfo->abName = tmp; - SELF_CLOSE( ( AREAP ) pArea ); - return FAILURE; } - pOpenInfo->abName = tmp; + } + + if( errCode == SUCCESS ) + { + /* If successful call SUPER_OPEN to finish system jobs */ + errCode = SUPER_OPEN( ( AREAP ) pArea, pOpenInfo ); + } + + if( errCode != SUCCESS ) + { + SELF_CLOSE( ( AREAP ) pArea ); + return FAILURE; } /* Alloc buffer */ @@ -2557,10 +3134,37 @@ static ERRCODE hb_dbfSysName( DBFAREAP pArea, BYTE * pBuffer ) HB_TRACE(HB_TR_DEBUG, ("hb_dbfSysName(%p, %p)", pArea, pBuffer)); HB_SYMBOL_UNUSED( pArea ); - strncpy( ( char * ) pBuffer, "DBF", 4 ); + strcpy( ( char * ) pBuffer, "DBF" ); return SUCCESS; } +/* + * Pack helper function called for each packed record + */ +static ERRCODE hb_dbfPackRec( DBFAREAP pArea, ULONG ulRecNo, BOOL *fWritten ) +{ + HB_TRACE(HB_TR_DEBUG, ("hb_dbfPackRec(%p, %lu, %p)", pArea, ulRecNo, fWritten)); + + if( pArea->fDeleted ) + { + *fWritten = FALSE; + } + else + { + *fWritten = TRUE; + if( pArea->ulRecNo != ulRecNo ) + { + pArea->ulRecNo = ulRecNo; + pArea->fRecordChanged = TRUE; + if( ! hb_dbfWriteRecord( pArea ) ) + return FAILURE; + } + } + + return SUCCESS; +} + + /* * Remove records marked for deletion from a database. */ @@ -2568,6 +3172,7 @@ static ERRCODE hb_dbfPack( DBFAREAP pArea ) { ULONG ulRecIn, ulRecOut, ulEvery, ulUserEvery; PHB_ITEM pError, pBlock; + BOOL fWritten; HB_TRACE(HB_TR_DEBUG, ("hb_dbfPack(%p)", pArea)); @@ -2610,7 +3215,7 @@ static ERRCODE hb_dbfPack( DBFAREAP pArea ) ulRecOut = ulEvery = 0; ulRecIn = 1; - while ( ulRecIn <= pArea->ulRecCount ) + while( ulRecIn <= pArea->ulRecCount ) { SELF_GOTO( ( AREAP ) pArea, ulRecIn ); hb_dbfReadRecord( pArea ); @@ -2621,22 +3226,16 @@ static ERRCODE hb_dbfPack( DBFAREAP pArea ) if( ++ulEvery >= ulUserEvery ) { ulEvery = 0; - hb_vmPushSymbol( &hb_symEval ); - hb_vmPush( pBlock ); - hb_vmDo( 0 ); + hb_vmEvalBlock( pBlock ); } } - /* Copy record */ - if( !pArea->fDeleted ) + if( SELF_PACKREC( ( AREAP ) pArea, ulRecOut + 1, &fWritten ) == FAILURE ) + return FAILURE; + + if( fWritten ) { ulRecOut++; - if( ulRecIn != ulRecOut ) - { - pArea->ulRecNo = ulRecOut; - pArea->fRecordChanged = TRUE; - hb_dbfWriteRecord( pArea ); - } } ulRecIn++; } @@ -2644,16 +3243,15 @@ static ERRCODE hb_dbfPack( DBFAREAP pArea ) /* Execute the Code Block for pending record */ if( pBlock && ulEvery > 0 ) { - hb_vmPushSymbol( &hb_symEval ); - hb_vmPush( pBlock ); - hb_vmDo( 0 ); + hb_vmEvalBlock( pBlock ); } - if ( pArea->ulRecCount != ulRecOut ) + if( pArea->ulRecCount != ulRecOut ) { pArea->ulRecCount = ulRecOut; /* Force write new header */ pArea->fUpdateHeader = TRUE; + SELF_WRITEDBHEADER( ( AREAP ) pArea ); } return SELF_GOTO( ( AREAP ) pArea, 1 ); } @@ -2765,55 +3363,28 @@ static ERRCODE hb_dbfSort( DBFAREAP pArea, LPDBSORTINFO pSortInfo ) */ static ERRCODE hb_dbfTrans( DBFAREAP pArea, LPDBTRANSINFO pTransInfo ) { - PHB_ITEM pPutRec; - HB_TRACE(HB_TR_DEBUG, ("hb_dbfTrans(%p, %p)", pArea, pTransInfo)); - if( pTransInfo->uiFlags & DBTF_MATCH && !pArea->fHasMemo ) + if( pTransInfo->uiFlags & DBTF_MATCH ) { - pPutRec = hb_itemPutL( NULL, FALSE ); - SELF_INFO( ( AREAP ) pTransInfo->lpaDest, DBI_CANPUTREC, pPutRec ); - if( hb_itemGetL( pPutRec ) ) + if( pArea->fHasMemo ) + pTransInfo->uiFlags &= ~DBTF_PUTREC; + else if( pArea->rddID == pTransInfo->lpaDest->rddID ) pTransInfo->uiFlags |= DBTF_PUTREC; - hb_itemRelease( pPutRec ); + else + { + PHB_ITEM pPutRec = hb_itemPutL( NULL, FALSE ); + SELF_INFO( ( AREAP ) pTransInfo->lpaDest, DBI_CANPUTREC, pPutRec ); + if( hb_itemGetL( pPutRec ) ) + pTransInfo->uiFlags |= DBTF_PUTREC; + else + pTransInfo->uiFlags &= ~DBTF_PUTREC; + hb_itemRelease( pPutRec ); + } } return SUPER_TRANS( ( AREAP ) pArea, pTransInfo ); } -/* - * Copy a record to another WorkArea. - */ -static ERRCODE hb_dbfTransRec( DBFAREAP pArea, LPDBTRANSINFO pTransInfo ) -{ - BOOL bDeleted; - - HB_TRACE(HB_TR_DEBUG, ("hb_dbfTransRec(%p, %p)", pArea, pTransInfo)); - - if( pTransInfo->uiFlags & DBTF_PUTREC ) - { - /* Append a new record */ - if( SELF_APPEND( ( AREAP ) pTransInfo->lpaDest, TRUE ) == FAILURE ) - return FAILURE; - - /* Read record */ - if( !pArea->fValidBuffer && !hb_dbfReadRecord( pArea ) ) - return FAILURE; - - /* Copy record */ - if( SELF_PUTREC( ( AREAP ) pTransInfo->lpaDest, pArea->pRecord ) == FAILURE ) - return FAILURE; - - /* Record deleted? */ - if( SELF_DELETED( ( AREAP ) pArea, &bDeleted ) == FAILURE ) - return FAILURE; - - /* Delete the new record */ - if( bDeleted ) - return SELF_DELETE( ( AREAP ) pTransInfo->lpaDest ); - } - return SUPER_TRANSREC( ( AREAP ) pArea, pTransInfo ); -} - /* * Physically remove all records from data store. */ @@ -2849,12 +3420,13 @@ static ERRCODE hb_dbfZap( DBFAREAP pArea ) pArea->fUpdateHeader = TRUE; pArea->ulRecCount = 0; + SELF_WRITEDBHEADER( ( AREAP ) pArea ); SELF_GOTO( ( AREAP ) pArea, 0 ); /* Zap memo file */ if( pArea->fHasMemo ) { - if ( SELF_CREATEMEMFILE( ( AREAP ) pArea, NULL ) == FAILURE ) + if( SELF_CREATEMEMFILE( ( AREAP ) pArea, NULL ) == FAILURE ) return FAILURE; } return SUCCESS; @@ -2959,8 +3531,8 @@ static ERRCODE hb_dbfSetFilter( DBFAREAP pArea, LPDBFILTERINFO pFilterInfo ) static ERRCODE hb_dbfRawLock( DBFAREAP pArea, USHORT uiAction, ULONG ulRecNo ) { ERRCODE uiErr = SUCCESS; - ULONG ulPos, ulFlSize, ulRlSize; - SHORT iDir; + HB_FOFFSET ulPos, ulFlSize, ulRlSize; + int iDir; BOOL fLck; HB_TRACE(HB_TR_DEBUG, ("hb_dbfRawLock(%p, %hu, %lu)", pArea, uiAction, ulRecNo)); @@ -2969,22 +3541,29 @@ static ERRCODE hb_dbfRawLock( DBFAREAP pArea, USHORT uiAction, ULONG ulRecNo ) { switch( pArea->bLockType ) { - case HB_SET_DBFLOCK_CLIP: + case DB_DBFLOCK_CLIP: ulPos = DBF_LOCKPOS_CLIP; iDir = DBF_LOCKDIR_CLIP; ulFlSize = DBF_FLCKSIZE_CLIP; ulRlSize = DBF_RLCKSIZE_CLIP; break; - case HB_SET_DBFLOCK_CL53: + case DB_DBFLOCK_CL53: ulPos = DBF_LOCKPOS_CL53; iDir = DBF_LOCKDIR_CL53; ulFlSize = DBF_FLCKSIZE_CL53; ulRlSize = DBF_RLCKSIZE_CL53; break; - case HB_SET_DBFLOCK_VFP: - if ( pArea->fHasTags ) + case DB_DBFLOCK_CL53EXT: + ulPos = DBF_LOCKPOS_CL53EXT; + iDir = DBF_LOCKDIR_CL53EXT; + ulFlSize = DBF_FLCKSIZE_CL53EXT; + ulRlSize = DBF_RLCKSIZE_CL53EXT; + break; + + case DB_DBFLOCK_VFP: + if( pArea->fHasTags ) { ulPos = DBF_LOCKPOS_VFPX; iDir = DBF_LOCKDIR_VFPX; @@ -3000,6 +3579,15 @@ static ERRCODE hb_dbfRawLock( DBFAREAP pArea, USHORT uiAction, ULONG ulRecNo ) } break; +#ifndef HB_LONG_LONG_OFF + case DB_DBFLOCK_XHB64: + ulPos = DBF_LOCKPOS_XHB64; + iDir = DBF_LOCKDIR_XHB64; + ulFlSize = DBF_FLCKSIZE_XHB64; + ulRlSize = DBF_RLCKSIZE_XHB64; + break; +#endif + default: return FAILURE; } @@ -3009,10 +3597,10 @@ static ERRCODE hb_dbfRawLock( DBFAREAP pArea, USHORT uiAction, ULONG ulRecNo ) case FILE_LOCK: if( !pArea->fFLocked ) { - if ( iDir < 0 ) - fLck = hb_fsLock( pArea->hDataFile, ulPos - ulFlSize, ulFlSize, FL_LOCK ); + if( iDir < 0 ) + fLck = hb_fsLockLarge( pArea->hDataFile, ulPos - ulFlSize, ulFlSize, FL_LOCK ); else - fLck = hb_fsLock( pArea->hDataFile, ulPos + 1, ulFlSize, FL_LOCK ); + fLck = hb_fsLockLarge( pArea->hDataFile, ulPos + 1, ulFlSize, FL_LOCK ); if( !fLck ) uiErr = FAILURE; @@ -3024,10 +3612,10 @@ static ERRCODE hb_dbfRawLock( DBFAREAP pArea, USHORT uiAction, ULONG ulRecNo ) case FILE_UNLOCK: if( pArea->fFLocked ) { - if ( iDir < 0 ) - fLck = hb_fsLock( pArea->hDataFile, ulPos - ulFlSize, ulFlSize, FL_UNLOCK ); + if( iDir < 0 ) + fLck = hb_fsLockLarge( pArea->hDataFile, ulPos - ulFlSize, ulFlSize, FL_UNLOCK ); else - fLck = hb_fsLock( pArea->hDataFile, ulPos + 1, ulFlSize, FL_UNLOCK ); + fLck = hb_fsLockLarge( pArea->hDataFile, ulPos + 1, ulFlSize, FL_UNLOCK ); if( !fLck ) uiErr = FAILURE; @@ -3038,12 +3626,12 @@ static ERRCODE hb_dbfRawLock( DBFAREAP pArea, USHORT uiAction, ULONG ulRecNo ) case REC_LOCK: if( !pArea->fFLocked ) { - if ( iDir < 0 ) - fLck = hb_fsLock( pArea->hDataFile, ulPos - ulRecNo, ulRlSize, FL_LOCK ); - else if ( iDir == 2 ) - fLck = hb_fsLock( pArea->hDataFile, ulPos + ( ulRecNo - 1 ) * pArea->uiRecordLen + pArea->uiHeaderLen, ulRlSize, FL_LOCK ); + if( iDir < 0 ) + fLck = hb_fsLockLarge( pArea->hDataFile, ulPos - ulRecNo, ulRlSize, FL_LOCK ); + else if( iDir == 2 ) + fLck = hb_fsLockLarge( pArea->hDataFile, ulPos + ( ulRecNo - 1 ) * pArea->uiRecordLen + pArea->uiHeaderLen, ulRlSize, FL_LOCK ); else - fLck = hb_fsLock( pArea->hDataFile, ulPos + ulRecNo, ulRlSize, FL_LOCK ); + fLck = hb_fsLockLarge( pArea->hDataFile, ulPos + ulRecNo, ulRlSize, FL_LOCK ); if( !fLck ) uiErr = FAILURE; @@ -3053,12 +3641,12 @@ static ERRCODE hb_dbfRawLock( DBFAREAP pArea, USHORT uiAction, ULONG ulRecNo ) case REC_UNLOCK: if( !pArea->fFLocked ) { - if ( iDir < 0 ) - fLck = hb_fsLock( pArea->hDataFile, ulPos - ulRecNo, ulRlSize, FL_UNLOCK ); - else if ( iDir == 2 ) - fLck = hb_fsLock( pArea->hDataFile, ulPos + ( ulRecNo - 1 ) * pArea->uiRecordLen + pArea->uiHeaderLen, ulRlSize, FL_UNLOCK ); + if( iDir < 0 ) + fLck = hb_fsLockLarge( pArea->hDataFile, ulPos - ulRecNo, ulRlSize, FL_UNLOCK ); + else if( iDir == 2 ) + fLck = hb_fsLockLarge( pArea->hDataFile, ulPos + ( ulRecNo - 1 ) * pArea->uiRecordLen + pArea->uiHeaderLen, ulRlSize, FL_UNLOCK ); else - fLck = hb_fsLock( pArea->hDataFile, ulPos + ulRecNo, ulRlSize, FL_UNLOCK ); + fLck = hb_fsLockLarge( pArea->hDataFile, ulPos + ulRecNo, ulRlSize, FL_UNLOCK ); if( !fLck ) uiErr = FAILURE; } @@ -3070,9 +3658,9 @@ static ERRCODE hb_dbfRawLock( DBFAREAP pArea, USHORT uiAction, ULONG ulRecNo ) { do { - fLck = hb_fsLock( pArea->hDataFile, ulPos, 1, FL_LOCK | FLX_WAIT ); + fLck = hb_fsLockLarge( pArea->hDataFile, ulPos, 1, FL_LOCK | FLX_WAIT ); /* TODO: call special error handler (LOCKHANDLER) hiere if !fLck */ - } while ( !fLck ); + } while( !fLck ); if( !fLck ) uiErr = FAILURE; else @@ -3084,7 +3672,7 @@ static ERRCODE hb_dbfRawLock( DBFAREAP pArea, USHORT uiAction, ULONG ulRecNo ) case HEADER_UNLOCK: if( pArea->fHeaderLocked ) { - if( !hb_fsLock( pArea->hDataFile, ulPos, 1, FL_UNLOCK ) ) + if( !hb_fsLockLarge( pArea->hDataFile, ulPos, 1, FL_UNLOCK ) ) uiErr = FAILURE; pArea->fHeaderLocked = FALSE; } @@ -3106,13 +3694,11 @@ static ERRCODE hb_dbfLock( DBFAREAP pArea, LPDBLOCKINFO pLockInfo ) switch( pLockInfo->uiMethod ) { case DBLM_EXCLUSIVE: - return hb_dbfLockRecord( pArea, pArea->ulRecNo, &pLockInfo->fResult, - TRUE ); + return hb_dbfLockRecord( pArea, 0, &pLockInfo->fResult, TRUE ); case DBLM_MULTIPLE: return hb_dbfLockRecord( pArea, hb_itemGetNL( pLockInfo->itmRecID ), - &pLockInfo->fResult, - FALSE ); + &pLockInfo->fResult, FALSE ); case DBLM_FILE: return hb_dbfLockFile( pArea, &pLockInfo->fResult ); @@ -3130,11 +3716,14 @@ static ERRCODE hb_dbfLock( DBFAREAP pArea, LPDBLOCKINFO pLockInfo ) /* * Release network locks in the specified WorkArea. */ -static ERRCODE hb_dbfUnLock( DBFAREAP pArea, ULONG ulRecNo ) +static ERRCODE hb_dbfUnLock( DBFAREAP pArea, PHB_ITEM pRecNo ) { ERRCODE uiError; + ULONG ulRecNo; - HB_TRACE(HB_TR_DEBUG, ("dbfUnLock(%p, %lu)", pArea, ulRecNo)); + HB_TRACE(HB_TR_DEBUG, ("dbfUnLock(%p, %p)", pArea, pRecNo)); + + ulRecNo = hb_itemGetNL( pRecNo ); uiError = SUCCESS; if( pArea->fShared ) @@ -3167,7 +3756,7 @@ static ERRCODE hb_dbfCreateMemFile( DBFAREAP pArea, LPDBOPENINFO pCreateInfo ) if( pCreateInfo ) { pError = hb_errNew(); - hb_errPutGenCode( pError, EG_DATATYPE ); + hb_errPutGenCode( pError, EG_CREATE ); hb_errPutSubCode( pError, EDBF_DATATYPE ); hb_errPutDescription( pError, hb_langDGetErrorDesc( EG_CREATE ) ); hb_errPutFileName( pError, ( char * ) pCreateInfo->abName ); @@ -3178,6 +3767,75 @@ static ERRCODE hb_dbfCreateMemFile( DBFAREAP pArea, LPDBOPENINFO pCreateInfo ) return FAILURE; } +/* + * BLOB2FILE - retrieve memo contents into file + */ +static ERRCODE hb_dbfGetValueFile( DBFAREAP pArea, USHORT uiIndex, BYTE * szFile, USHORT uiMode ) +{ + USHORT uiError = SUCCESS; + LPFIELD pField; + + HB_TRACE(HB_TR_DEBUG, ("hb_dbfGetValueFile(%p, %hu, %s, %hu)", pArea, uiIndex, szFile, uiMode)); + + if( pArea->lpdbPendingRel ) + SELF_FORCEREL( ( AREAP ) pArea ); + + /* Read record */ + if( !pArea->fValidBuffer && !hb_dbfReadRecord( pArea ) ) + return FAILURE; + + if( --uiIndex >= pArea->uiFieldCount ) + return FAILURE; + + pField = pArea->lpFields + uiIndex; + if( pField->uiType == HB_IT_STRING ) + { + FHANDLE hFile; + + hFile = hb_fsExtOpen( szFile, NULL, FO_WRITE | FO_EXCLUSIVE | + FXO_DEFAULTS | FXO_SHARELOCK | + ( uiMode == FILEGET_APPEND ? FXO_APPEND : FXO_TRUNCATE ), + NULL, NULL ); + if( hFile == FS_ERROR ) + { + uiError = uiMode != FILEGET_APPEND ? EDBF_CREATE : EDBF_OPEN_DBF; + } + else + { + hb_fsSeekLarge( hFile, 0, FS_END ); + if( hb_fsWrite( hFile, pArea->pRecord + pArea->pFieldOffset[ uiIndex ], + pField->uiLen ) != pField->uiLen ) + { + uiError = EDBF_WRITE; + } + hb_fsClose( hFile ); + } + } + else + { + uiError = EDBF_DATATYPE; + } + + /* Exit if any error */ + if( uiError != SUCCESS ) + { + PHB_ITEM pError = hb_errNew(); + hb_errPutGenCode( pError, hb_dbfGetEGcode( uiError ) ); + hb_errPutDescription( pError, hb_langDGetErrorDesc( hb_dbfGetEGcode( uiError ) ) ); + hb_errPutSubCode( pError, uiError ); + hb_errPutFlags( pError, EF_CANDEFAULT ); + if( uiError != EDBF_DATATYPE ) + { + hb_errPutOsCode( pError, hb_fsError() ); + hb_errPutFileName( pError, ( char * ) szFile ); + } + SELF_ERROR( ( AREAP ) pArea, pError ); + hb_itemRelease( pError ); + return FAILURE; + } + return SUCCESS; +} + /* * Open a memo file in the specified WorkArea. */ @@ -3197,13 +3855,87 @@ static ERRCODE hb_dbfOpenMemFile( DBFAREAP pArea, LPDBOPENINFO pOpenInfo ) return FAILURE; } +/* + * FILE2BLOB - store file contents in MEMO + */ +static ERRCODE hb_dbfPutValueFile( DBFAREAP pArea, USHORT uiIndex, BYTE * szFile, USHORT uiMode ) +{ + USHORT uiError = SUCCESS, uiRead; + LPFIELD pField; + + HB_TRACE(HB_TR_DEBUG, ("hb_dbfPutValueFile(%p, %hu, %s, %hu)", pArea, uiIndex, szFile, uiMode)); + + HB_SYMBOL_UNUSED( uiMode ); + + if( pArea->lpdbPendingRel ) + SELF_FORCEREL( ( AREAP ) pArea ); + + /* Read record */ + if( !pArea->fValidBuffer && !hb_dbfReadRecord( pArea ) ) + return FAILURE; + + if( --uiIndex >= pArea->uiFieldCount ) + return FAILURE; + + if( !pArea->fPositioned ) + return FAILURE; + + /* Buffer is hot? */ + if( !pArea->fRecordChanged && SELF_GOHOT( ( AREAP ) pArea ) == FAILURE ) + return FAILURE; + + pField = pArea->lpFields + uiIndex; + if( pField->uiType == HB_IT_STRING ) + { + FHANDLE hFile; + + hFile = hb_fsExtOpen( szFile, NULL, FO_READ | FO_DENYNONE | + FXO_DEFAULTS | FXO_SHARELOCK, NULL, NULL ); + if( hFile == FS_ERROR ) + { + uiError = EDBF_OPEN_DBF; + } + else + { + uiRead = hb_fsRead( hFile, pArea->pRecord + + pArea->pFieldOffset[ uiIndex ], pField->uiLen ); + if( uiRead != ( USHORT ) FS_ERROR && uiRead < pField->uiLen ) + memset( pArea->pRecord + pArea->pFieldOffset[ uiIndex ] + uiRead, + ' ', pField->uiLen - uiRead ); + hb_fsClose( hFile ); + } + } + else + { + uiError = EDBF_DATATYPE; + } + + /* Exit if any error */ + if( uiError != SUCCESS ) + { + PHB_ITEM pError = hb_errNew(); + hb_errPutGenCode( pError, hb_dbfGetEGcode( uiError ) ); + hb_errPutDescription( pError, hb_langDGetErrorDesc( hb_dbfGetEGcode( uiError ) ) ); + hb_errPutSubCode( pError, uiError ); + hb_errPutFlags( pError, EF_CANDEFAULT ); + if( uiError != EDBF_DATATYPE ) + { + hb_errPutOsCode( pError, hb_fsError() ); + hb_errPutFileName( pError, ( char * ) szFile ); + } + SELF_ERROR( ( AREAP ) pArea, pError ); + hb_itemRelease( pError ); + return FAILURE; + } + return SUCCESS; +} + /* * Read the database file header record in the WorkArea. */ static ERRCODE hb_dbfReadDBHeader( DBFAREAP pArea ) { - DBFHEADER dbHeader; - BOOL bRetry, bError; + BOOL fRetry, fError; PHB_ITEM pError; HB_TRACE(HB_TR_DEBUG, ("hb_dbfReadDBHeader(%p)", pArea)); @@ -3212,15 +3944,84 @@ static ERRCODE hb_dbfReadDBHeader( DBFAREAP pArea ) /* Try read */ do { + fError = FALSE; + hb_fsSeek( pArea->hDataFile, 0, FS_SET ); - if ( hb_fsRead( pArea->hDataFile, ( BYTE * ) &dbHeader, sizeof( DBFHEADER ) ) != sizeof( DBFHEADER ) || - ( dbHeader.bVersion != 0x03 && /* dBase III */ - dbHeader.bVersion != 0x30 && /* VisualFoxPro 6.0 */ - dbHeader.bVersion != 0x83 && /* dBase III w/memo */ - dbHeader.bVersion != 0xF5 /* FoxPro??? w/memo */ - ) ) + if( hb_fsRead( pArea->hDataFile, ( BYTE * ) &pArea->dbfHeader, + sizeof( DBFHEADER ) ) != sizeof( DBFHEADER ) ) + { + fError = TRUE; + } + else + { + pArea->fAutoInc = pArea->fTableEncrypted = pArea->fHasMemo = FALSE; + pArea->bTableType = DB_DBF_STD; + pArea->bMemoType = DB_MEMO_NONE; + pArea->bCryptType = DB_CRYPT_NONE; + + pArea->fHasTags = pArea->dbfHeader.bHasTags & 0x01; + + switch( pArea->dbfHeader.bVersion ) + { + case 0x31: + pArea->fAutoInc = TRUE; + case 0x30: + pArea->bTableType = DB_DBF_VFP; + pArea->bMemoType = DB_MEMO_FPT; + if( pArea->dbfHeader.bHasTags & 0x02 ) + pArea->fHasMemo = TRUE; + break; + + case 0x03: + break; + + case 0x83: + pArea->fHasMemo = TRUE; + pArea->bMemoType = DB_MEMO_DBT; + break; + + case 0xE5: + pArea->fHasMemo = TRUE; + pArea->bMemoType = DB_MEMO_SMT; + break; + + case 0xF5: + pArea->fHasMemo = TRUE; + pArea->bMemoType = DB_MEMO_FPT; + break; + + case 0x06: + pArea->fTableEncrypted = TRUE; + pArea->bCryptType = DB_CRYPT_SIX; + break; + + case 0x86: + pArea->fTableEncrypted = TRUE; + pArea->fHasMemo = TRUE; + pArea->bCryptType = DB_CRYPT_SIX; + pArea->bMemoType = DB_MEMO_DBT; + break; + + case 0xE6: + pArea->fHasMemo = TRUE; + pArea->fTableEncrypted = TRUE; + pArea->bCryptType = DB_CRYPT_SIX; + pArea->bMemoType = DB_MEMO_SMT; + break; + + case 0xF6: + pArea->fHasMemo = TRUE; + pArea->fTableEncrypted = TRUE; + pArea->bCryptType = DB_CRYPT_SIX; + pArea->bMemoType = DB_MEMO_FPT; + break; + + default: + fError = TRUE; + } + } + if( fError ) { - bError = TRUE; if( !pError ) { pError = hb_errNew(); @@ -3228,34 +4029,24 @@ static ERRCODE hb_dbfReadDBHeader( DBFAREAP pArea ) hb_errPutSubCode( pError, EDBF_CORRUPT ); hb_errPutDescription( pError, hb_langDGetErrorDesc( EG_CORRUPTION ) ); hb_errPutFileName( pError, pArea->szDataFileName ); + hb_errPutOsCode( pError, hb_fsError() ); hb_errPutFlags( pError, EF_CANRETRY | EF_CANDEFAULT ); } - bRetry = ( SELF_ERROR( ( AREAP ) pArea, pError ) == E_RETRY ); + fRetry = ( SELF_ERROR( ( AREAP ) pArea, pError ) == E_RETRY ); } else - bRetry = bError = FALSE; - } while( bRetry ); + fRetry = FALSE; + } while( fRetry ); if( pError ) hb_itemRelease( pError ); /* Read error? */ - if( bError ) + if( fError ) return FAILURE; - pArea->bDay = dbHeader.bDay; - pArea->bMonth = dbHeader.bMonth; - pArea->bYear = dbHeader.bYear; - pArea->fHasTags = ( dbHeader.bHasTags & 0x01 ) != 0; - pArea->bVersion = dbHeader.bVersion; - pArea->bCodePage = dbHeader.bCodePage; - pArea->uiHeaderLen = HB_GET_LE_UINT16( dbHeader.uiHeaderLen ); - pArea->ulRecCount = HB_GET_LE_UINT32( dbHeader.ulRecCount ); - - pArea->fHasMemo = ( pArea->bVersion == 0xF5 || /* FoxPro 2.x or earlier with Memo */ - pArea->bVersion == 0x83 || /* dBase III with Memo */ - ( pArea->bVersion == 0x30 && - ( dbHeader.bHasTags & 0x02 ) ) ); /* VisualFox with Memo */ + pArea->uiHeaderLen = HB_GET_LE_UINT16( pArea->dbfHeader.uiHeaderLen ); + pArea->ulRecCount = HB_GET_LE_UINT32( pArea->dbfHeader.ulRecCount ); return SUCCESS; } @@ -3265,21 +4056,50 @@ static ERRCODE hb_dbfReadDBHeader( DBFAREAP pArea ) */ static ERRCODE hb_dbfWriteDBHeader( DBFAREAP pArea ) { - BOOL fLck = FALSE; - DBFHEADER dbfHeader; int iYear, iMonth, iDay; + BOOL fLck = FALSE; + ERRCODE errCode; + PHB_ITEM pError; HB_TRACE(HB_TR_DEBUG, ("hb_dbfWriteDBHeader(%p)", pArea)); - memset( &dbfHeader, 0, sizeof( DBFHEADER ) ); - dbfHeader.bVersion = pArea->bVersion; + if( pArea->fReadonly ) + { + pError = hb_errNew(); + hb_errPutGenCode( pError, EG_READONLY ); + hb_errPutDescription( pError, hb_langDGetErrorDesc( EG_READONLY ) ); + hb_errPutSubCode( pError, EDBF_READONLY ); + SELF_ERROR( ( AREAP ) pArea, pError ); + hb_itemRelease( pError ); + return FAILURE; + } + + pArea->dbfHeader.bHasTags = pArea->fHasTags ? 0x01 : 0x00; + if( pArea->bTableType == DB_DBF_VFP ) + { + pArea->dbfHeader.bVersion = ( pArea->fAutoInc ? 0x31 : 0x30 ); + if( pArea->bMemoType == DB_MEMO_FPT ) + pArea->dbfHeader.bHasTags |= 0x02; + } + else + { + if( pArea->bMemoType == DB_MEMO_DBT ) + pArea->dbfHeader.bVersion = 0x83; + else if( pArea->bMemoType == DB_MEMO_FPT ) + pArea->dbfHeader.bVersion = 0xF5; + else if( pArea->bMemoType == DB_MEMO_SMT ) + pArea->dbfHeader.bVersion = 0xE5; + else + pArea->dbfHeader.bVersion = 0x03; + + if( pArea->fTableEncrypted && pArea->bCryptType == DB_CRYPT_SIX ) + pArea->dbfHeader.bVersion = ( pArea->dbfHeader.bVersion & 0xf0 ) | 0x06; + } + hb_dateToday( &iYear, &iMonth, &iDay ); - dbfHeader.bYear = ( BYTE ) ( iYear - 1900 ); - dbfHeader.bMonth = ( BYTE ) iMonth; - dbfHeader.bDay = ( BYTE ) iDay; - dbfHeader.bHasTags = ( BYTE ) ( pArea->fHasTags ? 0x01 : 0x00 ) | - ( ( pArea->fHasMemo && pArea->bVersion == 0x30 ) ? 0x02 : 0x00 ); - dbfHeader.bCodePage = pArea->bCodePage; + pArea->dbfHeader.bYear = ( BYTE ) ( iYear - 1900 ); + pArea->dbfHeader.bMonth = ( BYTE ) iMonth; + pArea->dbfHeader.bDay = ( BYTE ) iDay; /* Update record count */ if( pArea->fShared ) @@ -3297,100 +4117,295 @@ static ERRCODE hb_dbfWriteDBHeader( DBFAREAP pArea ) /* Exclusive mode */ /* Seek to logical eof and write eof mark */ hb_fsSeekLarge( pArea->hDataFile, ( HB_FOFFSET ) pArea->uiHeaderLen + - ( HB_FOFFSET ) pArea->uiRecordLen * + ( HB_FOFFSET ) pArea->uiRecordLen * ( HB_FOFFSET ) pArea->ulRecCount, FS_SET ); hb_fsWrite( pArea->hDataFile, ( BYTE * ) "\032", 1 ); hb_fsWrite( pArea->hDataFile, NULL, 0 ); } - HB_PUT_LE_UINT32( dbfHeader.ulRecCount, pArea->ulRecCount ); - HB_PUT_LE_UINT16( dbfHeader.uiHeaderLen, pArea->uiHeaderLen ); - HB_PUT_LE_UINT16( dbfHeader.uiRecordLen, pArea->uiRecordLen ); + HB_PUT_LE_UINT32( pArea->dbfHeader.ulRecCount, pArea->ulRecCount ); + HB_PUT_LE_UINT16( pArea->dbfHeader.uiHeaderLen, pArea->uiHeaderLen ); + HB_PUT_LE_UINT16( pArea->dbfHeader.uiRecordLen, pArea->uiRecordLen ); hb_fsSeek( pArea->hDataFile, 0, FS_SET ); - hb_fsWrite( pArea->hDataFile, ( BYTE * ) &dbfHeader, sizeof( DBFHEADER ) ); + if( hb_fsWrite( pArea->hDataFile, ( BYTE * ) &pArea->dbfHeader, + sizeof( DBFHEADER ) ) == sizeof( DBFHEADER ) ) + { + errCode = SUCCESS; + } + else + { + errCode = FAILURE; + } + /* TODO: add RT error */ pArea->fDataFlush = TRUE; pArea->fUpdateHeader = FALSE; if( fLck ) SELF_RAWLOCK( ( AREAP ) pArea, HEADER_UNLOCK, 0 ); + + if( errCode != SUCCESS ) + { + pError = hb_errNew(); + + hb_errPutGenCode( pError, EG_WRITE ); + hb_errPutDescription( pError, hb_langDGetErrorDesc( EG_WRITE ) ); + hb_errPutSubCode( pError, EDBF_WRITE ); + hb_errPutFileName( pError, pArea->szDataFileName ); + hb_errPutOsCode( pError, hb_fsError() ); + SELF_ERROR( ( AREAP ) pArea, pError ); + hb_itemRelease( pError ); + } + return errCode; +} + +static ERRCODE hb_dbfDrop( LPRDDNODE pRDD, PHB_ITEM pItemTable, PHB_ITEM pItemIndex ) +{ + char szFileName[ _POSIX_PATH_MAX + 1 ], * szFile, * szExt; + PHB_ITEM pFileExt = NULL; + PHB_FNAME pFileName; + BOOL fTable = FALSE, fResult = FALSE; + + HB_TRACE(HB_TR_DEBUG, ("hb_dbfDrop(%p,%p,%p)", pRDD, pItemTable, pItemIndex)); + + szFile = hb_itemGetCPtr( pItemIndex ); + if( !szFile[ 0 ] ) + { + /* Try to delete index file */ + szFile = hb_itemGetCPtr( pItemTable ); + if( !szFile[ 0 ] ) + return FALSE; + fTable = TRUE; + } + + pFileName = hb_fsFNameSplit( szFile ); + + if( !pFileName->szExtension ) + { + /* Add default extension if missing */ + pFileExt = hb_itemPutC( NULL, "" ); + if( SELF_RDDINFO( pRDD, fTable ? RDDI_TABLEEXT : RDDI_ORDBAGEXT, 0, pFileExt ) == SUCCESS ) + pFileName->szExtension = hb_itemGetCPtr( pFileExt ); + } + hb_fsFNameMerge( szFileName, pFileName ); + hb_xfree( pFileName ); + + /* Use hb_spFile first to locate table which can be in differ path */ + if( hb_spFile( ( BYTE * ) szFileName, ( BYTE * ) szFileName ) ) + { + fResult = hb_fsDelete( ( BYTE * ) szFileName ); + if( fResult && fTable ) + { + /* + * Database table file has been deleted, now check if memo is + * supported and if yes then try to delete memo file if it exists + * in the same directory as table file + * hb_fsFNameSplit() repeated intentionally to respect + * the path set by hb_spFile() + */ + pFileName = hb_fsFNameSplit( szFileName ); + pFileExt = hb_itemPutC( pFileExt, "" ); + if( SELF_RDDINFO( pRDD, RDDI_MEMOEXT, 0, pFileExt ) == SUCCESS ) + { + szExt = hb_itemGetCPtr( pFileExt ); + if( szExt[ 0 ] ) + { + pFileName->szExtension = szExt; + hb_fsFNameMerge( szFileName, pFileName ); + hb_fsDelete( ( BYTE * ) szFileName ); + } + } + /* + * and try to delete production index also if it exists + * in the same directory as table file + */ + pFileExt = hb_itemPutC( pFileExt, "" ); + if( SELF_RDDINFO( pRDD, RDDI_ORDSTRUCTEXT, 0, pFileExt ) == SUCCESS ) + { + szExt = hb_itemGetCPtr( pFileExt ); + if( szExt[ 0 ] ) + { + pFileName->szExtension = szExt; + hb_fsFNameMerge( szFileName, pFileName ); + hb_fsDelete( ( BYTE * ) szFileName ); + } + } + hb_xfree( pFileName ); + } + } + if( pFileExt ) + { + hb_itemRelease( pFileExt ); + } + + return fResult ? SUCCESS : FAILURE; +} + +static ERRCODE hb_dbfExists( LPRDDNODE pRDD, PHB_ITEM pItemTable, PHB_ITEM pItemIndex ) +{ + char szFileName[ _POSIX_PATH_MAX + 1 ], * szFile; + PHB_ITEM pFileExt = NULL; + PHB_FNAME pFileName; + BOOL fTable = FALSE; + + HB_TRACE(HB_TR_DEBUG, ("hb_dbfExists(%p,%p,%p)", pRDD, pItemTable, pItemIndex)); + + szFile = hb_itemGetCPtr( pItemIndex ); + if( !szFile[ 0 ] ) + { + szFile = hb_itemGetCPtr( pItemTable ); + if( !szFile[ 0 ] ) + return FALSE; + fTable = TRUE; + } + + pFileName = hb_fsFNameSplit( szFile ); + + if( !pFileName->szExtension ) + { + pFileExt = hb_itemPutC( NULL, "" ); + if( SELF_RDDINFO( pRDD, fTable ? RDDI_TABLEEXT : RDDI_ORDBAGEXT, 0, pFileExt ) == SUCCESS ) + pFileName->szExtension = hb_itemGetCPtr( pFileExt ); + } + hb_fsFNameMerge( szFileName, pFileName ); + hb_xfree( pFileName ); + if( pFileExt ) + { + hb_itemRelease( pFileExt ); + } + + return hb_spFile( ( BYTE * ) szFileName, NULL ) ? SUCCESS : FAILURE; +} + +static ERRCODE hb_dbfInit( LPRDDNODE pRDD ) +{ + HB_TRACE(HB_TR_DEBUG, ("hb_dbfInit(%p)", pRDD)); + + pRDD->lpvCargo = hb_xgrab( sizeof( DBFDATA ) ); + memset( pRDD->lpvCargo, 0, sizeof( DBFDATA ) ); + + ( ( LPDBFDATA ) pRDD->lpvCargo )->bTableType = DB_DBF_STD; + ( ( LPDBFDATA ) pRDD->lpvCargo )->bCryptType = DB_CRYPT_NONE; + return SUCCESS; } -static ERRCODE hb_dbfDrop( PHB_ITEM pItemTable ) +static ERRCODE hb_dbfExit( LPRDDNODE pRDD ) { - HB_TRACE(HB_TR_DEBUG, ("hb_dbfDrop(%p)", pItemTable)); + HB_TRACE(HB_TR_DEBUG, ("hb_dbfExit(%p)", pRDD)); - if ( pItemTable && HB_IS_STRING( pItemTable ) ) + if( pRDD->lpvCargo ) { - BYTE * pBuffer; - char szFileName[ _POSIX_PATH_MAX + 1 ]; - ULONG ulLen; - - pBuffer = (BYTE *) pItemTable->item.asString.value; - szFileName[ _POSIX_PATH_MAX ] = '\0'; - strncpy( (char *) szFileName, (char *) pBuffer, _POSIX_PATH_MAX ); - ulLen = strlen( szFileName ); - if ( ulLen > 0 ) - { - PHB_FNAME pFileName = hb_fsFNameSplit( szFileName ); - if ( !pFileName->szExtension ) - { - strncat( szFileName, DBF_TABLEEXT, _POSIX_PATH_MAX - ulLen ); - } - hb_xfree( pFileName ); - return hb_fsDelete( (BYTE *) szFileName ) ? SUCCESS : FAILURE; - } + hb_xfree( pRDD->lpvCargo ); + pRDD->lpvCargo = NULL; } - return FAILURE; + s_uiRddId = ( USHORT ) -1; + + return SUCCESS; } -/* returns 1 if exists, 0 else */ -BOOL HB_EXPORT hb_dbfExists( PHB_ITEM pItemTable, PHB_ITEM pItemIndex ) +static ERRCODE hb_dbfRddInfo( LPRDDNODE pRDD, USHORT uiIndex, ULONG ulConnect, PHB_ITEM pItem ) { - char szFileName[ _POSIX_PATH_MAX + 1 ]; - BYTE * pBuffer; + LPDBFDATA pData; - pBuffer = (BYTE *) ( pItemIndex != NULL ? pItemIndex->item.asString.value : pItemTable->item.asString.value ); + HB_TRACE(HB_TR_DEBUG, ("hb_dbfRddInfo(%p, %hu, %lu, %p)", pRDD, uiIndex, ulConnect, pItem)); - strcpy( (char *) szFileName, (char *) pBuffer ); - if ( pItemTable && !strchr( szFileName, '.' )) - strcat( szFileName, DBF_TABLEEXT ); - return hb_fsFile( (BYTE *) szFileName ); + pData = ( LPDBFDATA ) pRDD->lpvCargo; + + switch( uiIndex ) + { + case RDDI_ISDBF: + case RDDI_CANPUTREC: + case RDDI_LOCAL: + case RDDI_LARGEFILE: + hb_itemPutL( pItem, TRUE ); + break; + + case RDDI_TABLEEXT: + { + char * szNew = hb_itemGetCPtr( pItem ); + + if( szNew[0] == '.' && szNew[1] ) + szNew = hb_strdup( szNew ); + else + szNew = NULL; + + hb_itemPutC( pItem, pData->szTableExt[ 0 ] ? pData->szTableExt : DBF_TABLEEXT ); + if( szNew ) + { + hb_strncpy( pData->szTableExt, szNew, HB_MAX_FILE_EXT ); + hb_xfree( szNew ); + } + break; + } + case RDDI_TABLETYPE: + { + int iType = hb_itemGetNI( pItem ); + hb_itemPutNI( pItem, pData->bTableType ? pData->bTableType : DB_DBF_STD ); + switch( iType ) + { + case DB_DBF_STD: /* standard dBase/Clipper DBF file */ + case DB_DBF_VFP: /* VFP DBF file */ + pData->bTableType = iType; + } + } + case RDDI_LOCKSCHEME: + { + int iScheme = hb_itemGetNI( pItem ); + + hb_itemPutNI( pItem, pData->bLockType ? pData->bLockType : + hb_set.HB_SET_DBFLOCKSCHEME ); + switch( iScheme ) + { + case DB_DBFLOCK_CLIP: + case DB_DBFLOCK_CL53: + case DB_DBFLOCK_CL53EXT: + case DB_DBFLOCK_VFP: +#ifndef HB_LONG_LONG_OFF + case DB_DBFLOCK_XHB64: +#endif + pData->bLockType = ( int ) iScheme; + } + break; + } + + default: + return SUPER_RDDINFO( pRDD, uiIndex, ulConnect, pItem ); + + } + + return SUCCESS; } -HB_FUNC( _DBFC ) -{ -} +HB_FUNC( _DBFC ) { ; } HB_FUNC( DBF_GETFUNCTABLE ) { RDDFUNCS * pTable; - USHORT * uiCount; + USHORT * uiCount, uiRddId; uiCount = ( USHORT * ) hb_itemGetPtr( hb_param( 1, HB_IT_POINTER ) ); - * uiCount = RDDFUNCSCOUNT; pTable = ( RDDFUNCS * ) hb_itemGetPtr( hb_param( 2, HB_IT_POINTER ) ); + uiRddId = hb_parni( 4 ); HB_TRACE(HB_TR_DEBUG, ("DBF_GETFUNCTABLE(%i, %p)", uiCount, pTable)); if( pTable ) - hb_retni( hb_rddInherit( pTable, &dbfTable, &dbfSuper, 0 ) ); + { + ERRCODE errCode; + + if ( uiCount ) + * uiCount = RDDFUNCSCOUNT; + errCode = hb_rddInherit( pTable, &dbfTable, &dbfSuper, 0 ); + hb_retni( errCode ); + if ( errCode == SUCCESS ) + { + /* + * we successfully register our RDD so now we can initialize it + * You may think that this place is RDD init statement, Druzus + */ + s_uiRddId = uiRddId; + } + } else hb_retni( FAILURE ); } - -HB_FUNC( DBSETDBFVERSION ) -{ - BYTE bOldVersion = s_dbfVersion; - - if ( hb_pcount() > 0 ) - { - BYTE bVersion = ( BYTE ) hb_parni( 1 ); - if ( bVersion == 0x30 || bVersion == 0x03 ) - { - s_dbfVersion = bVersion; - } - } - hb_retni( bOldVersion ); -} - diff --git a/harbour/source/rdd/dbfcdx/Makefile b/harbour/source/rdd/dbfcdx/Makefile index b089207922..3f3edbea4d 100644 --- a/harbour/source/rdd/dbfcdx/Makefile +++ b/harbour/source/rdd/dbfcdx/Makefile @@ -6,9 +6,15 @@ ROOT = ../../../ C_SOURCES=\ dbfcdx1.c \ + sixcdx1.c \ PRG_SOURCES=\ dbfcdx0.prg \ + sixcdx0.prg \ + +ifeq ($(HB_MT),MT) + MT_LIBNAME=$(LIBNAME)mt +endif LIBNAME=dbfcdx diff --git a/harbour/source/rdd/dbfcdx/dbfcdx0.prg b/harbour/source/rdd/dbfcdx/dbfcdx0.prg index 41f03d5def..a88d148da8 100644 --- a/harbour/source/rdd/dbfcdx/dbfcdx0.prg +++ b/harbour/source/rdd/dbfcdx/dbfcdx0.prg @@ -57,6 +57,7 @@ ANNOUNCE DBFCDX procedure DBFCDXInit + REQUEST _DBF REQUEST _DBFCDX rddRegister( "DBF", RDT_FULL ) diff --git a/harbour/source/rdd/dbfcdx/dbfcdx1.c b/harbour/source/rdd/dbfcdx/dbfcdx1.c index 9544fbb766..16d3492913 100644 --- a/harbour/source/rdd/dbfcdx/dbfcdx1.c +++ b/harbour/source/rdd/dbfcdx/dbfcdx1.c @@ -55,9 +55,12 @@ */ #define HB_CDX_CLIP_AUTOPEN -#define HB_CDX_PACKTRAIL #define HB_CDX_NEW_SORT +#if !defined( HB_SIXCDX ) +# define HB_CDX_PACKTRAIL +#endif + #define HB_CDX_DBGCODE /* @@ -75,14 +78,9 @@ #include "hbvm.h" #include "hbset.h" #include "hbrddcdx.h" +#include "hbmath.h" #ifdef __XHARBOUR__ -#include "regex.h" -#endif - -#define __PRG_SOURCE__ __FILE__ -#ifdef HB_PCODE_VER - #undef HB_PRG_PCODE_VER - #define HB_PRG_PCODE_VER HB_PCODE_VER +#include "hbregex.h" #endif #ifndef HB_CDP_SUPPORT_OFF @@ -97,6 +95,12 @@ */ #endif +#define __PRG_SOURCE__ __FILE__ +#ifdef HB_PCODE_VER + #undef HB_PRG_PCODE_VER + #define HB_PRG_PCODE_VER HB_PCODE_VER +#endif + /* * Tag->fRePos = TURE means that rootPage->...->childLeafPage path is @@ -105,7 +109,7 @@ */ /* create a new Tag (make index) */ -static void hb_cdxTagDoIndex( LPCDXTAG pTag ); +static void hb_cdxTagDoIndex( LPCDXTAG pTag, BOOL fReindex ); /* Close Tag */ static void hb_cdxTagClose( LPCDXTAG pTag ); @@ -134,6 +138,8 @@ static int hb_cdxPageRootSplit( LPCDXPAGE pPage ); /* free create index structur */ static void hb_cdxSortFree( LPCDXSORTINFO pSort ); +static USHORT s_uiRddId = ( USHORT ) -1; + static RDDFUNCS cdxSuper; static RDDFUNCS cdxTable = { @@ -175,7 +181,8 @@ static RDDFUNCS cdxTable = ( DBENTRYP_V ) hb_cdxRecall, ( DBENTRYP_ULP ) hb_cdxRecCount, ( DBENTRYP_ISI ) hb_cdxRecInfo, - ( DBENTRYP_I ) hb_cdxRecNo, + ( DBENTRYP_ULP ) hb_cdxRecNo, + ( DBENTRYP_I ) hb_cdxRecId, ( DBENTRYP_S ) hb_cdxSetFieldExtent, @@ -217,7 +224,7 @@ static RDDFUNCS cdxTable = ( DBENTRYP_OI ) hb_cdxOrderListAdd, ( DBENTRYP_V ) hb_cdxOrderListClear, - ( DBENTRYP_VP ) hb_cdxOrderListDelete, + ( DBENTRYP_OI ) hb_cdxOrderListDelete, ( DBENTRYP_OI ) hb_cdxOrderListFocus, ( DBENTRYP_V ) hb_cdxOrderListRebuild, ( DBENTRYP_VOI ) hb_cdxOrderCondition, @@ -238,6 +245,7 @@ static RDDFUNCS cdxTable = ( DBENTRYP_VLO ) hb_cdxSetLocate, ( DBENTRYP_VOS ) hb_cdxSetScope, ( DBENTRYP_VPL ) hb_cdxSkipScope, + ( DBENTRYP_B ) hb_cdxLocate, /* Miscellaneous */ @@ -251,7 +259,7 @@ static RDDFUNCS cdxTable = ( DBENTRYP_VSP ) hb_cdxRawLock, ( DBENTRYP_VL ) hb_cdxLock, - ( DBENTRYP_UL ) hb_cdxUnLock, + ( DBENTRYP_I ) hb_cdxUnLock, /* Memofile functions */ @@ -260,7 +268,7 @@ static RDDFUNCS cdxTable = ( DBENTRYP_VP ) hb_cdxCreateMemFile, ( DBENTRYP_SVPB ) hb_cdxGetValueFile, ( DBENTRYP_VP ) hb_cdxOpenMemFile, - ( DBENTRYP_SVP ) hb_cdxPutValueFile, + ( DBENTRYP_SVPB ) hb_cdxPutValueFile, /* Database file header handling */ @@ -270,9 +278,11 @@ static RDDFUNCS cdxTable = /* non WorkArea functions */ - ( DBENTRYP_I0 ) hb_cdxExit, - ( DBENTRYP_I1 ) hb_cdxDrop, - ( DBENTRYP_I2 ) hb_cdxExists, + ( DBENTRYP_R ) hb_cdxInit, + ( DBENTRYP_R ) hb_cdxExit, + ( DBENTRYP_RVV ) hb_cdxDrop, + ( DBENTRYP_RVV ) hb_cdxExists, + ( DBENTRYP_RSLV ) hb_cdxRddInfo, /* Special and reserved methods */ @@ -280,31 +290,87 @@ static RDDFUNCS cdxTable = ( DBENTRYP_SVP ) hb_cdxWhoCares }; +#if defined( HB_SIXCDX ) + +HB_FUNC( _SIXCDX ) {;} + +HB_FUNC( SIXCDX_GETFUNCTABLE ) +{ + RDDFUNCS * pTable; + USHORT * uiCount, uiRddId; + + uiCount = ( USHORT * ) hb_itemGetPtr( hb_param( 1, HB_IT_POINTER ) ); + pTable = ( RDDFUNCS * ) hb_itemGetPtr( hb_param( 2, HB_IT_POINTER ) ); + uiRddId = hb_parni( 4 ); + + HB_TRACE(HB_TR_DEBUG, ("SIXCDX_GETFUNCTABLE(%i, %p)", uiCount, pTable)); + + if ( pTable ) + { + ERRCODE errCode; + + if ( uiCount ) + * uiCount = RDDFUNCSCOUNT; + errCode = hb_rddInherit( pTable, &cdxTable, &cdxSuper, ( BYTE * ) "DBFFPT" ); + if ( errCode != SUCCESS ) + errCode = hb_rddInherit( pTable, &cdxTable, &cdxSuper, ( BYTE * ) "DBFDBT" ); + if ( errCode != SUCCESS ) + errCode = hb_rddInherit( pTable, &cdxTable, &cdxSuper, ( BYTE * ) "DBF" ); + hb_retni( errCode ); + if ( errCode == SUCCESS ) + { + /* + * we successfully register our RDD so now we can initialize it + * You may think that this place is RDD init statement, Druzus + */ + s_uiRddId = uiRddId; + } + } + else + hb_retni( FAILURE ); +} + + +HB_INIT_SYMBOLS_BEGIN( dbfcdx1__InitSymbols ) +{ "_SIXCDX", HB_FS_PUBLIC, {HB_FUNCNAME( _SIXCDX )}, NULL }, +{ "SIXCDX_GETFUNCTABLE", HB_FS_PUBLIC, {HB_FUNCNAME( SIXCDX_GETFUNCTABLE )}, NULL } +HB_INIT_SYMBOLS_END( dbfcdx1__InitSymbols ) + +#else HB_FUNC( _DBFCDX ) {;} HB_FUNC( DBFCDX_GETFUNCTABLE ) { RDDFUNCS * pTable; - USHORT * uiCount; + USHORT * uiCount, uiRddId; uiCount = ( USHORT * ) hb_itemGetPtr( hb_param( 1, HB_IT_POINTER ) ); pTable = ( RDDFUNCS * ) hb_itemGetPtr( hb_param( 2, HB_IT_POINTER ) ); + uiRddId = hb_parni( 4 ); HB_TRACE(HB_TR_DEBUG, ("DBFCDX_GETFUNCTABLE(%i, %p)", uiCount, pTable)); if ( pTable ) { - SHORT iRet; + ERRCODE errCode; if ( uiCount ) * uiCount = RDDFUNCSCOUNT; - iRet = hb_rddInherit( pTable, &cdxTable, &cdxSuper, ( BYTE * ) "DBFFPT" ); - if ( iRet == FAILURE ) - iRet = hb_rddInherit( pTable, &cdxTable, &cdxSuper, ( BYTE * ) "DBFDBT" ); - if ( iRet == FAILURE ) - iRet = hb_rddInherit( pTable, &cdxTable, &cdxSuper, ( BYTE * ) "DBF" ); - hb_retni( iRet ); + errCode = hb_rddInherit( pTable, &cdxTable, &cdxSuper, ( BYTE * ) "DBFFPT" ); + if ( errCode != SUCCESS ) + errCode = hb_rddInherit( pTable, &cdxTable, &cdxSuper, ( BYTE * ) "DBFDBT" ); + if ( errCode != SUCCESS ) + errCode = hb_rddInherit( pTable, &cdxTable, &cdxSuper, ( BYTE * ) "DBF" ); + if ( errCode == SUCCESS ) + { + /* + * we successfully register our RDD so now we can initialize it + * You may think that this place is RDD init statement, Druzus + */ + s_uiRddId = uiRddId; + } + hb_retni( errCode ); } else hb_retni( FAILURE ); @@ -316,9 +382,11 @@ HB_INIT_SYMBOLS_BEGIN( dbfcdx1__InitSymbols ) { "DBFCDX_GETFUNCTABLE", HB_FS_PUBLIC, {HB_FUNCNAME( DBFCDX_GETFUNCTABLE )}, NULL } HB_INIT_SYMBOLS_END( dbfcdx1__InitSymbols ) +#endif + #if defined(HB_PRAGMA_STARTUP) #pragma startup dbfcdx1__InitSymbols -#elif defined(_MSC_VER) +#elif defined(HB_MSC_STARTUP) #if _MSC_VER >= 1010 #pragma data_seg( ".CRT$XIY" ) #pragma comment( linker, "/Merge:.CRT=.data" ) @@ -329,6 +397,7 @@ HB_INIT_SYMBOLS_END( dbfcdx1__InitSymbols ) #pragma data_seg() #endif + #ifdef HB_CDX_DSPDBG_INFO static void hb_cdxDspTags( LPCDXINDEX pIndex ) { @@ -379,27 +448,38 @@ static SHORT cdxTmpStackSize = 0; /* * internal DBFCDX function */ + + +/* + * generate internal error + */ static void hb_cdxErrInternal( char * szMsg ) { hb_errInternal( 9201, szMsg ? szMsg : "hb_cdxErrInternal: data integrity error.", "", "" ); } +/* + * generate Run-Time error + */ static ERRCODE hb_cdxErrorRT( CDXAREAP pArea, USHORT uiGenCode, USHORT uiSubCode, char * filename, USHORT uiOsCode, USHORT uiFlags ) { PHB_ITEM pError; - ERRCODE iRet; + ERRCODE iRet = FAILURE; - pError = hb_errNew(); - hb_errPutGenCode( pError, uiGenCode ); - hb_errPutSubCode( pError, uiSubCode ); - hb_errPutOsCode( pError, uiOsCode ); - hb_errPutDescription( pError, hb_langDGetErrorDesc( uiGenCode ) ); - if ( filename ) - hb_errPutFileName( pError, filename ); - if ( uiFlags ) - hb_errPutFlags( pError, uiFlags ); - iRet = SELF_ERROR( ( AREAP ) pArea, pError ); - hb_itemRelease( pError ); + if ( hb_vmRequestQuery() == 0 ) + { + pError = hb_errNew(); + hb_errPutGenCode( pError, uiGenCode ); + hb_errPutSubCode( pError, uiSubCode ); + hb_errPutOsCode( pError, uiOsCode ); + hb_errPutDescription( pError, hb_langDGetErrorDesc( uiGenCode ) ); + if ( filename ) + hb_errPutFileName( pError, filename ); + if ( uiFlags ) + hb_errPutFlags( pError, uiFlags ); + iRet = SELF_ERROR( ( AREAP ) pArea, pError ); + hb_errRelease( pError ); + } return iRet; } @@ -606,6 +686,34 @@ static int hb_cdxValCompare( LPCDXTAG pTag, BYTE * val1, BYTE len1, return iResult; } +/* + * get CDX key type for given item + */ +static BYTE hb_cdxItemType( PHB_ITEM pItem ) +{ + switch( hb_itemType( pItem ) ) + { + case HB_IT_STRING: + case HB_IT_STRING | HB_IT_MEMO: + return 'C'; + + case HB_IT_INTEGER: + case HB_IT_LONG: + case HB_IT_DOUBLE: + return 'N'; + + case HB_IT_DATE: + return 'D'; + + case HB_IT_LOGICAL: + return 'L'; + + default: + return 'U'; + } +} + + /* * store Item in index key * TODO: uiType check and generate RT error if necessary @@ -618,15 +726,14 @@ static LPCDXKEY hb_cdxKeyPutItem( LPCDXKEY pKey, PHB_ITEM pItem, ULONG ulRec, LP ptr = &buf[0]; - switch ( hb_itemType( pItem ) ) + switch ( hb_cdxItemType( pItem ) ) { - case HB_IT_STRING: - case HB_IT_STRING | HB_IT_MEMO: + case 'C': len = (BYTE) HB_MIN( pItem->item.asString.length, (ULONG) pTag->uiLen ); if ( fSize && len < pTag->uiLen ) { memcpy( ptr, pItem->item.asString.value, len ); - memset( ptr + len, pTag->uiType == 'C' ? ' ' : '\0', pTag->uiLen - len ); + memset( ptr + len, pTag->bTrail, pTag->uiLen - len ); len = ( BYTE ) pTag->uiLen; } else @@ -634,19 +741,17 @@ static LPCDXKEY hb_cdxKeyPutItem( LPCDXKEY pKey, PHB_ITEM pItem, ULONG ulRec, LP ptr = ( BYTE * ) pItem->item.asString.value; } break; - case HB_IT_INTEGER: - case HB_IT_LONG: - case HB_IT_DOUBLE: + case 'N': d = hb_itemGetND( pItem ); HB_DBL2ORD( &d, ptr ); len = 8; break; - case HB_IT_DATE: + case 'D': d = (double) pItem->item.asDate.value; HB_DBL2ORD( &d, ptr ); len = 8; break; - case HB_IT_LOGICAL: + case 'L': *ptr = (BYTE) ( hb_itemGetL( pItem ) ? 'T' : 'F' ); len = 1; break; @@ -667,18 +772,32 @@ static LPCDXKEY hb_cdxKeyPutItem( LPCDXKEY pKey, PHB_ITEM pItem, ULONG ulRec, LP } /* - * get Item from index key (TODO: add pTag param) + * get Item from index key */ -static PHB_ITEM hb_cdxKeyGetItem( LPCDXKEY pKey, PHB_ITEM pItem, USHORT uiType ) +static PHB_ITEM hb_cdxKeyGetItem( LPCDXKEY pKey, PHB_ITEM pItem, LPCDXTAG pTag, BOOL fTrans ) { double d; if ( pKey ) { - switch( uiType ) + switch( pTag->uiType ) { case 'C': - pItem = hb_itemPutCL( pItem, ( char * ) pKey->val, pKey->len ); +#ifndef HB_CDP_SUPPORT_OFF + if( fTrans && pTag->pIndex->pArea->cdPage != hb_cdp_page ) + { + char * pVal = ( char * ) hb_xgrab( pKey->len + 1 ); + memcpy( pVal, pKey->val, pKey->len ); + pVal[ pKey->len ] = '\0'; + hb_cdpnTranslate( pVal, pTag->pIndex->pArea->cdPage, hb_cdp_page, + pKey->len ); + pItem = hb_itemPutCPtr( pItem, pVal, pKey->len ); + } + else +#endif + { + pItem = hb_itemPutCL( pItem, ( char * ) pKey->val, pKey->len ); + } break; case 'N': HB_ORD2DBL( pKey->val, &d ); @@ -692,9 +811,12 @@ static PHB_ITEM hb_cdxKeyGetItem( LPCDXKEY pKey, PHB_ITEM pItem, USHORT uiType ) pItem = hb_itemPutL( pItem, pKey->val[0] == 'T' ); break; default: - pItem = hb_itemNew( pItem ); + if ( pItem ) + hb_itemClear( pItem ); + else + pItem = hb_itemNew( NULL ); #ifdef HB_CDX_DBGCODE - printf( "hb_cdxKeyGetItem() ??? (%x)\n", uiType ); + printf( "hb_cdxKeyGetItem() ??? (%x)\n", pTag->uiType ); #endif } } @@ -706,50 +828,51 @@ static PHB_ITEM hb_cdxKeyGetItem( LPCDXKEY pKey, PHB_ITEM pItem, USHORT uiType ) return pItem; } +/* + * destroy compiled expression + */ +static void hb_cdxDestroyExp( PHB_ITEM pExp ) +{ + if ( hb_itemType( pExp ) != HB_IT_BLOCK ) + hb_macroDelete( ( HB_MACRO_PTR ) hb_itemGetPtr( pExp ) ); + hb_itemRelease( pExp ); +} + /* * evaluate key expression and create new Key from the result */ -static LPCDXKEY hb_cdxKeyEval( LPCDXKEY pKey, LPCDXTAG pTag, BOOL fSetWA ) +static LPCDXKEY hb_cdxKeyEval( LPCDXKEY pKey, LPCDXTAG pTag ) { - HB_MACRO_PTR pMacro; - int iCurrArea = 0; CDXAREAP pArea = pTag->pIndex->pArea; + PHB_ITEM pItem; #ifndef HB_CDP_SUPPORT_OFF /* TODO: this hack is not thread safe, hb_cdp_page has to be thread specific */ PHB_CODEPAGE cdpTmp = hb_cdp_page; hb_cdp_page = pArea->cdPage; #endif - if ( fSetWA && !pTag->nField ) - { - iCurrArea = hb_rddGetCurrentWorkAreaNumber(); - if ( iCurrArea != pArea->uiArea ) - hb_rddSelectWorkAreaNumber( pArea->uiArea ); - else - iCurrArea = 0; - } - if ( pTag->nField ) { - PHB_ITEM pItem = hb_itemNew( NULL ); + pItem = hb_itemNew( NULL ); SELF_GETVALUE( ( AREAP ) pArea, pTag->nField, pItem ); pKey = hb_cdxKeyPutItem( pKey, pItem, pArea->ulRecNo, pTag, FALSE, TRUE ); hb_itemRelease( pItem ); } - else if ( HB_IS_BLOCK( pTag->pKeyItem ) ) + else { - pKey = hb_cdxKeyPutItem( pKey, hb_vmEvalBlock( pTag->pKeyItem ), pArea->ulRecNo, pTag, FALSE, TRUE ); - } - else - { - pMacro = ( HB_MACRO_PTR ) hb_itemGetPtr( pTag->pKeyItem ); - hb_macroRun( pMacro ); - pKey = hb_cdxKeyPutItem( pKey, hb_stackItemFromTop( -1 ), pArea->ulRecNo, pTag, FALSE, TRUE ); - hb_stackPop(); - } + int iCurrArea = hb_rddGetCurrentWorkAreaNumber(); - if ( iCurrArea ) - hb_rddSelectWorkAreaNumber( iCurrArea ); + if ( iCurrArea != pArea->uiArea ) + hb_rddSelectWorkAreaNumber( pArea->uiArea ); + else + iCurrArea = 0; + + pItem = hb_vmEvalBlockOrMacro( pTag->pKeyItem ); + pKey = hb_cdxKeyPutItem( pKey, pItem, pArea->ulRecNo, pTag, FALSE, TRUE ); + + if ( iCurrArea ) + hb_rddSelectWorkAreaNumber( iCurrArea ); + } #ifndef HB_CDP_SUPPORT_OFF hb_cdp_page = cdpTmp; @@ -758,37 +881,14 @@ static LPCDXKEY hb_cdxKeyEval( LPCDXKEY pKey, LPCDXTAG pTag, BOOL fSetWA ) return pKey; } -/* - * evaluate macro expression - * the result is on the stack hb_stackItemFromTop(-1) - * TODO: eliminate it by implementing macro evaluation - * in SELF_EVALBLOCK( AREAP pArea, PHB_ITEM pExpr) - */ -static void hb_cdxMacroRun( CDXAREAP pArea, HB_MACRO_PTR pMacro ) -{ - int iCurrArea; - iCurrArea = hb_rddGetCurrentWorkAreaNumber(); - if ( iCurrArea != pArea->uiArea ) - hb_rddSelectWorkAreaNumber( pArea->uiArea ); - else - iCurrArea = 0; - hb_macroRun( pMacro ); - if ( iCurrArea ) - hb_rddSelectWorkAreaNumber( iCurrArea ); -} - /* * evaluate conditional expression and return the result */ static BOOL hb_cdxEvalCond( CDXAREAP pArea, PHB_ITEM pCondItem, BOOL fSetWA ) { - HB_MACRO_PTR pMacro; int iCurrArea = 0; BOOL fRet; - if ( !pCondItem ) - return TRUE; - if ( fSetWA ) { iCurrArea = hb_rddGetCurrentWorkAreaNumber(); if ( iCurrArea != pArea->uiArea ) @@ -797,17 +897,7 @@ static BOOL hb_cdxEvalCond( CDXAREAP pArea, PHB_ITEM pCondItem, BOOL fSetWA ) iCurrArea = 0; } - if ( HB_IS_BLOCK( pCondItem ) ) - { - fRet = hb_itemGetL( hb_vmEvalBlock( pCondItem ) ); - } - else - { - pMacro = ( HB_MACRO_PTR ) hb_itemGetPtr( pCondItem ); - hb_macroRun( pMacro ); - fRet = hb_itemGetL( hb_stackItemFromTop( -1 ) ); - hb_stackPop(); - } + fRet = hb_itemGetL( hb_vmEvalBlockOrMacro( pCondItem ) ); if ( iCurrArea ) hb_rddSelectWorkAreaNumber( iCurrArea ); @@ -821,76 +911,19 @@ static BOOL hb_cdxEvalCond( CDXAREAP pArea, PHB_ITEM pCondItem, BOOL fSetWA ) static BOOL hb_cdxEvalSeekCond( LPCDXTAG pTag, PHB_ITEM pCondItem ) { BOOL fRet; - HB_ITEM ItemKey; + PHB_ITEM pKeyVal, pKeyRec; - if ( ! HB_IS_BLOCK( pCondItem ) ) - return TRUE; + pKeyVal = hb_cdxKeyGetItem( pTag->CurKey, NULL, pTag, TRUE ); + pKeyRec = hb_itemPutNInt( NULL, pTag->CurKey->rec ); - ItemKey.type = HB_IT_NIL; - hb_cdxKeyGetItem( pTag->CurKey, &ItemKey, pTag->uiType ); + fRet = hb_itemGetL( hb_vmEvalBlockV( pCondItem, 2, pKeyVal, pKeyRec ) ); - hb_vmPushSymbol( &hb_symEval ); - hb_vmPush( pCondItem ); - hb_vmPush( &ItemKey ); - hb_vmPushLong( ( LONG ) pTag->CurKey->rec ); - hb_vmDo( 2 ); - fRet = hb_itemGetL( hb_stackReturnItem() ); - - hb_itemClear( &ItemKey ); + hb_itemRelease( pKeyVal ); + hb_itemRelease( pKeyRec ); return fRet; } -/* - * find field index for single field expressions - */ -static USHORT hb_cdxFieldIndex( CDXAREAP pArea, char * cExpr ) -{ - char szKeyExpr[ CDX_MAXKEY + 1 ], - szAlias[ HARBOUR_MAX_RDD_ALIAS_LENGTH + 1 ]; - int i, j, l, n = 0; - - if ( SELF_ALIAS( ( AREAP ) pArea, ( BYTE * ) szAlias ) == SUCCESS ) - l = strlen( szAlias ); - else - l = 0; - - hb_strncpyUpperTrim( szKeyExpr, cExpr, CDX_MAXKEY ); - - /* - * strip the _FIELD-> and FIELD-> prefix, it could be nested so repeat - * this process until all prefixes will be removed - */ - do - { - j = n; - if ( strncmp( &szKeyExpr[ n ], "FIELD", 5 ) == 0 ) - i = 5; - else if ( strncmp( &szKeyExpr[ n ], "_FIELD", 6 ) == 0 ) - i = 6; - else if ( l > 0 && strncmp( &szKeyExpr[ n ], szAlias, l ) == 0 ) - i = l; - else - i = 0; - - if ( i > 0 ) - { - i = n + 5; - while ( szKeyExpr[ i ] == ' ' ) - i++; - if ( szKeyExpr[ i ] == '-' && szKeyExpr[ i + 1 ] == '>' ) - { - n = i + 2; - while ( szKeyExpr[ n ] == ' ' ) - n++; - } - } - } - while ( n != j ); - - return hb_rddFieldIndex( ( AREAP ) pArea, &szKeyExpr[ n ] ); -} - /* * check if Key is in top scope */ @@ -938,15 +971,20 @@ static BOOL hb_cdxBottomScope( LPCDXTAG pTag ) } /* - * clear scopes + * clear top or bottom scope */ static void hb_cdxTagClearScope( LPCDXTAG pTag, USHORT nScope ) { - PHB_ITEM *pScope; + CDXAREAP pArea = pTag->pIndex->pArea; LPCDXKEY *pScopeKey; + PHB_ITEM *pScope; HB_TRACE(HB_TR_DEBUG, ("hb_cdxTagClearScope(%p, %hu)", pTag, nScope)); + /* resolve any pending scope relations first */ + if( pArea->lpdbPendingRel && pArea->lpdbPendingRel->isScoped ) + SELF_FORCEREL( ( AREAP ) pArea ); + if ( pTag->UsrAscend ? nScope == 0 : nScope != 0 ) { pScope = &pTag->topScope; @@ -972,6 +1010,99 @@ static void hb_cdxTagClearScope( LPCDXTAG pTag, USHORT nScope ) } } +/* + * set top or bottom scope + */ +static void hb_cdxTagSetScope( LPCDXTAG pTag, USHORT nScope, PHB_ITEM pItem ) +{ + CDXAREAP pArea = pTag->pIndex->pArea; + PHB_ITEM pScopeVal; + + /* resolve any pending scope relations first */ + if( pArea->lpdbPendingRel && pArea->lpdbPendingRel->isScoped ) + SELF_FORCEREL( ( AREAP ) pArea ); + + pScopeVal = ( hb_itemType( pItem ) == HB_IT_BLOCK ) ? + hb_vmEvalBlock( pItem ) : pItem; + + if ( pTag->uiType == hb_cdxItemType( pScopeVal ) ) + { + PHB_ITEM *pScope; + LPCDXKEY *pScopeKey; + ULONG ulRec; + + if ( pTag->UsrAscend ? nScope == 0 : nScope != 0 ) + { + pScope = &(pTag->topScope); + pScopeKey = &(pTag->topScopeKey); + ulRec = CDX_IGNORE_REC_NUM; + } + else + { + pScope = &(pTag->bottomScope); + pScopeKey = &(pTag->bottomScopeKey); + ulRec = CDX_MAX_REC_NUM; + } + + if ( *pScope == NULL ) + *pScope = hb_itemNew( NULL ); + hb_itemCopy( *pScope, pItem ); + *pScopeKey = hb_cdxKeyPutItem( *pScopeKey, pScopeVal, ulRec, pTag, TRUE, FALSE ); + pTag->curKeyState &= ~( CDX_CURKEY_RAWCNT | CDX_CURKEY_LOGCNT ); + if ( nScope == 0 ) + pTag->curKeyState &= ~( CDX_CURKEY_RAWPOS | CDX_CURKEY_LOGPOS ); + } + else + { + /* TODO: !!! + * RT error: DBFCDX/1051 Scope Type Mismatch + * hb_cdxErrorRT + */ + } +} + +static void hb_cdxTagGetScope( LPCDXTAG pTag, USHORT nScope, PHB_ITEM pItem ) +{ + CDXAREAP pArea = pTag->pIndex->pArea; + PHB_ITEM *pScope; + + /* resolve any pending scoped relations first */ + if( pArea->lpdbPendingRel && pArea->lpdbPendingRel->isScoped ) + SELF_FORCEREL( ( AREAP ) pArea ); + + pScope = ( pTag->UsrAscend ? nScope == 0 : nScope != 0 ) ? + &(pTag->topScope) : &(pTag->bottomScope); + if ( *pScope ) + hb_itemCopy( pItem, *pScope ); + else + hb_itemClear( pItem ); +} + +/* + * refresh top and bottom scope value if set as codeblock + */ +static void hb_cdxTagRefreshScope( LPCDXTAG pTag ) +{ + PHB_ITEM pItem; + + if( pTag->pIndex->pArea->lpdbPendingRel && + pTag->pIndex->pArea->lpdbPendingRel->isScoped ) + SELF_FORCEREL( ( AREAP ) pTag->pIndex->pArea ); + + if ( hb_itemType( pTag->topScope ) == HB_IT_BLOCK ) + { + pItem = hb_vmEvalBlock( pTag->topScope ); + pTag->topScopeKey = hb_cdxKeyPutItem( pTag->topScopeKey, pItem, + pTag->topScopeKey->rec, pTag, TRUE, FALSE ); + } + if ( hb_itemType( pTag->bottomScope ) == HB_IT_BLOCK ) + { + pItem = hb_vmEvalBlock( pTag->bottomScope ); + pTag->bottomScopeKey = hb_cdxKeyPutItem( pTag->bottomScopeKey, pItem, + pTag->bottomScopeKey->rec, pTag, TRUE, FALSE ); + } +} + #ifdef HB_CDX_DBGCODE_EXT /* * check internal integrity of page pool @@ -1065,7 +1196,7 @@ static ULONG hb_cdxIndexGetAvailPage( LPCDXINDEX pIndex, BOOL bHeader ) } else { - if ( hb_fsSeek( hFile, ulPos, FS_SET ) != ulPos || + if ( hb_fsSeekLarge( hFile, ulPos, FS_SET ) != ( HB_FOFFSET ) ulPos || hb_fsRead( hFile, (BYTE *) byBuf, 4 ) != 4 ) hb_errInternal( EDBF_READ, "hb_cdxIndexGetAvailPage: Read index page failed.", "", "" ); pIndex->freePage = HB_GET_LE_UINT32( byBuf ); @@ -1081,7 +1212,7 @@ static ULONG hb_cdxIndexGetAvailPage( LPCDXINDEX pIndex, BOOL bHeader ) if ( pIndex->nextAvail != CDX_DUMMYNODE ) ulPos = pIndex->nextAvail; else - ulPos = hb_fsSeek( hFile, 0, FS_END ); + ulPos = ( ULONG ) hb_fsSeekLarge( hFile, 0, FS_END ); pIndex->nextAvail = ulPos + iCnt * CDX_PAGELEN; /* TODO: ### */ @@ -1089,7 +1220,7 @@ static ULONG hb_cdxIndexGetAvailPage( LPCDXINDEX pIndex, BOOL bHeader ) { BYTE byBuf[CDX_PAGELEN]; memset( byBuf, 0, CDX_PAGELEN ); - if ( hb_fsSeek( hFile, ulPos, FS_SET ) != ulPos ) + if ( hb_fsSeekLarge( hFile, ulPos, FS_SET ) != ( HB_FOFFSET ) ulPos ) hb_errInternal( EDBF_WRITE, "Write in index page failed.(1)", "", "" ); while ( iCnt-- ) { @@ -1138,18 +1269,23 @@ static void hb_cdxIndexFlushAvailPage( LPCDXINDEX pIndex ) LPCDXLIST pLst = pIndex->freeLst; BYTE byPageBuf[CDX_PAGELEN]; ULONG ulPos; + BOOL fClean = TRUE; if ( pIndex->fReadonly ) hb_errInternal( 9101, "hb_cdxIndexPutAvailPage on readonly database.", "", "" ); if ( pIndex->fShared && !pIndex->lockWrite ) hb_errInternal( 9102, "hb_cdxIndexPutAvailPage on not locked index file.", "", "" ); - memset( byPageBuf, 0, CDX_PAGELEN ); ulPos = pIndex->freePage; while ( pLst && pLst->fStat ) { + if ( fClean ) + { + memset( byPageBuf, 0, CDX_PAGELEN ); + fClean = FALSE; + } HB_PUT_LE_UINT32( byPageBuf, pLst->ulAddr ); - if ( hb_fsSeek( pIndex->hFile, ulPos, FS_SET ) != ulPos || + if ( hb_fsSeekLarge( pIndex->hFile, ulPos, FS_SET ) != ( HB_FOFFSET ) ulPos || hb_fsWrite( pIndex->hFile, byPageBuf, CDX_PAGELEN ) != CDX_PAGELEN ) { hb_errInternal( EDBF_WRITE, "Write in index page failed.", "", "" ); @@ -1190,7 +1326,7 @@ static void hb_cdxIndexPageWrite( LPCDXINDEX pIndex, ULONG ulPos, BYTE * pBuffer if ( pIndex->fShared && !pIndex->lockWrite ) hb_errInternal( 9102, "hb_cdxIndexPageWrite on not locked index file.", "", "" ); - if ( hb_fsSeek( pIndex->hFile, ulPos, FS_SET ) != ulPos || + if ( hb_fsSeekLarge( pIndex->hFile, ulPos, FS_SET ) != ( HB_FOFFSET ) ulPos || hb_fsWrite( pIndex->hFile, pBuffer, uiSize ) != uiSize ) hb_errInternal( EDBF_WRITE, "Write in index page failed.", "", "" ); pIndex->fChanged = TRUE; @@ -1208,7 +1344,7 @@ static void hb_cdxIndexPageRead( LPCDXINDEX pIndex, ULONG ulPos, BYTE * pBuffer, if ( pIndex->fShared && !( pIndex->lockRead || pIndex->lockWrite ) ) hb_errInternal( 9103, "hb_cdxIndexPageRead on not locked index file.", "", "" ); - if ( hb_fsSeek( pIndex->hFile, ulPos, FS_SET ) != ulPos || + if ( hb_fsSeekLarge( pIndex->hFile, ulPos, FS_SET ) != ( HB_FOFFSET ) ulPos || hb_fsRead( pIndex->hFile, pBuffer, uiSize ) != uiSize ) hb_errInternal( EDBF_READ, "hb_cdxIndexPageRead: Read index page failed.", "", "" ); #ifdef HB_CDX_DBGUPDT @@ -1292,8 +1428,10 @@ static BOOL hb_cdxIndexLockWrite( LPCDXINDEX pIndex ) { BOOL ret; + if ( pIndex->fReadonly ) + hb_errInternal( 9101, "hb_cdxIndexLockWrite: readonly index.", "", "" ); if ( pIndex->lockRead ) - hb_errInternal( 9105, "hb_cdxIndexLockRead: writeLock after readLock.", "", "" ); + hb_errInternal( 9105, "hb_cdxIndexLockWrite: writeLock after readLock.", "", "" ); if ( pIndex->lockWrite > 0 ) { pIndex->lockWrite++; @@ -1374,7 +1512,7 @@ static BOOL hb_cdxIndexUnLockWrite( LPCDXINDEX pIndex ) if ( pIndex->lockWrite < 1 ) { - hb_errInternal( 9106, "hb_cdxIndexUnLockRead: bad count of locks.", "", "" ); + hb_errInternal( 9106, "hb_cdxIndexUnLockWrite: bad count of locks.", "", "" ); } if ( pIndex->lockRead ) { @@ -1531,7 +1669,7 @@ static BYTE * hb_cdxPageGetKeyVal( LPCDXPAGE pPage, SHORT iKey ) BYTE bTrail; iLen = pPage->TagParent->uiLen; - bTrail = ( BYTE ) ( pPage->TagParent->uiType == 'C' ? ' ' : '\0' ); + bTrail = pPage->TagParent->bTrail; if ( iKey < pPage->bufKeyNum - 1 ) pPage->bufKeyNum = 0; if ( pPage->bufKeyNum == 0 ) @@ -1661,7 +1799,7 @@ static void hb_cdxPageCheckDupTrl( LPCDXPAGE pPage, BYTE * pKeyBuf, SHORT iKeys, SHORT iNum = pPage->TagParent->uiLen, iKey, iPos, iFree = CDX_EXT_FREESPACE; SHORT iLen = iNum + 6; BYTE bDup, bTrl; - BYTE bTrail = ( pPage->TagParent->uiType == 'C' ) ? ' ' : '\0'; + BYTE bTrail = pPage->TagParent->bTrail; BOOL bErr = FALSE; for ( iKey = 0; iKey < iKeys; iKey++ ) @@ -1846,7 +1984,7 @@ static void hb_cdxPageLeafEncode( LPCDXPAGE pPage, BYTE * pKeyBuf, SHORT iKeys ) static void hb_cdxPageLeafDecode( LPCDXPAGE pPage, BYTE * pKeyBuf ) { int iKey, iTmp, iBits, iDup, iTrl, iNew, iReq, iLen = pPage->TagParent->uiLen; - BYTE *pDst, *pSrc, *pRec, *pTmp, bTrail = ( pPage->TagParent->uiType == 'C' ) ? ' ' : '\0'; + BYTE *pDst, *pSrc, *pRec, *pTmp, bTrail = pPage->TagParent->bTrail; ULONG ulRec; #ifdef HB_CDX_DBGCODE @@ -1914,7 +2052,7 @@ static void hb_cdxPageLeafInitSpace( LPCDXPAGE pPage ) SHORT iLen = pPage->TagParent->uiLen; BYTE bBits; - for ( bBits = 0; iLen; bBits++, iLen >>= 1 ); + for ( bBits = 0; iLen; bBits++, iLen >>= 1 ) {} pPage->ReqByte = 3; pPage->RNBits = 24 - ( bBits << 1 ); pPage->DCBits = pPage->TCBits = bBits; @@ -2083,7 +2221,7 @@ static int hb_cdxPageLeafAddKey( LPCDXPAGE pPage, LPCDXKEY pKey ) { SHORT iKey, iNum = pPage->TagParent->uiLen; SHORT iLen = iNum + 6, iSpc, iTrl, iDup, iMax, iPos; - BYTE bTrail = ( pPage->TagParent->uiType == 'C' ) ? ' ' : '\0'; + BYTE bTrail = pPage->TagParent->bTrail; int iRet = 0; #ifdef HB_CDX_DSPDBG_INFO @@ -2226,7 +2364,7 @@ static void hb_cdxPageIntSetKey( LPCDXPAGE pPage, SHORT iKey, BOOL fIns, BYTE * memcpy( &pPage->node.intNode.keyPool[ iPos ], pbVal, iLen ); else if ( fIns ) memset( &pPage->node.intNode.keyPool[ iPos ], - ( pPage->TagParent->uiType == 'C' ) ? ' ' : '\0', iLen ); + pPage->TagParent->bTrail, iLen ); if ( ulRec ) HB_PUT_BE_UINT32( &pPage->node.intNode.keyPool[ iPos + iLen ], ulRec ); HB_PUT_BE_UINT32( &pPage->node.intNode.keyPool[ iPos + iLen + 4 ], ulPag ); @@ -2718,7 +2856,7 @@ static int hb_cdxPageKeyLeafBalance( LPCDXPAGE pPage, int iChildRet ) bMax = iLen - 6 - HB_MAX( pPtr[ iKeys * iLen - 1 ], bMax ); #endif for ( j = 0; j < bMax && - pPtr[ ( iKeys - 1 ) * iLen + j ] == pbKey[ j ]; j++ ); + pPtr[ ( iKeys - 1 ) * iLen + j ] == pbKey[ j ]; j++ ) {} #ifdef HB_CDX_DSPDBG_INFO printf("\r\nbDup=%d, bTrl=%d ", j, iLen - 6 - bMax ); fflush(stdout); #endif @@ -3436,133 +3574,93 @@ static void hb_cdxTagHeaderStore( LPCDXTAG pTag ) */ static void hb_cdxTagLoad( LPCDXTAG pTag ) { - CDXTAGHEADER pHeader; - HB_MACRO_PTR pMacro; + CDXTAGHEADER tagHeader; + USHORT uiForPos, uiForLen, uiKeyPos, uiKeyLen; ULONG ulRecNo; /* read the page from a file */ - hb_cdxIndexPageRead( pTag->pIndex, pTag->TagBlock, (BYTE *) &pHeader, sizeof( CDXTAGHEADER ) ); - pTag->RootBlock = HB_GET_LE_UINT32( pHeader.rootPtr ); + hb_cdxIndexPageRead( pTag->pIndex, pTag->TagBlock, (BYTE *) &tagHeader, sizeof( CDXTAGHEADER ) ); + + uiForPos = HB_GET_LE_UINT16( tagHeader.forExpPos ); + uiForLen = HB_GET_LE_UINT16( tagHeader.forExpLen ); + uiKeyPos = HB_GET_LE_UINT16( tagHeader.keyExpPos ); + uiKeyLen = HB_GET_LE_UINT16( tagHeader.keyExpLen ); + + pTag->RootBlock = HB_GET_LE_UINT32( tagHeader.rootPtr ); + /* Return if: * no root page allocated * invalid root page offset (position inside an index file) * invalid key value length */ if ( pTag->RootBlock == 0 || pTag->RootBlock % CDX_PAGELEN != 0 || - pTag->RootBlock >= hb_fsSeek( pTag->pIndex->hFile, 0, FS_END ) || - HB_GET_LE_UINT16( pHeader.keySize ) > CDX_MAXKEY ) + ( HB_FOFFSET ) pTag->RootBlock >= hb_fsSeekLarge( pTag->pIndex->hFile, 0, FS_END ) || + HB_GET_LE_UINT16( tagHeader.keySize ) > CDX_MAXKEY || + uiForPos + uiForLen > CDX_HEADEREXPLEN || + uiKeyPos + uiKeyLen > CDX_HEADEREXPLEN ) { - /* TODO: pTag->RootBlock = 0; || {internal,RT}Error ? */ + pTag->RootBlock = 0; /* To force RT error - index corrupted */ return; } - pTag->uiLen = HB_GET_LE_UINT16( pHeader.keySize ); + pTag->uiLen = HB_GET_LE_UINT16( tagHeader.keySize ); pTag->MaxKeys = CDX_INT_FREESPACE / ( pTag->uiLen + 8 ); - pTag->OptFlags = pHeader.indexOpt; + pTag->OptFlags = tagHeader.indexOpt; pTag->UniqueKey = ( pTag->OptFlags & CDX_TYPE_UNIQUE ) != 0; pTag->Temporary = ( pTag->OptFlags & CDX_TYPE_TEMPORARY ) != 0; pTag->Custom = ( pTag->OptFlags & CDX_TYPE_CUSTOM ) != 0; - pTag->AscendKey = pTag->UsrAscend = ( HB_GET_LE_UINT16( pHeader.ascendFlg ) == 0 ); + pTag->AscendKey = pTag->UsrAscend = ( HB_GET_LE_UINT16( tagHeader.ascendFlg ) == 0 ); pTag->UsrUnique = FALSE; - pTag->KeyExpr = ( char * ) hb_xgrab( CDX_MAXKEY + 1 ); - hb_strncpyTrim( pTag->KeyExpr, ( const char * ) pHeader.keyExpPool, CDX_MAXKEY ); + pTag->KeyExpr = ( char * ) hb_xgrab( CDX_MAXEXP + 1 ); + hb_strncpyTrim( pTag->KeyExpr, ( const char * ) tagHeader.keyExpPool, CDX_MAXEXP ); - if ( ( pTag->OptFlags & CDX_TYPE_STRUCTURE ) || pTag->KeyExpr[ 0 ] == 0 ) + if ( pTag->OptFlags & CDX_TYPE_STRUCTURE || ! *pTag->KeyExpr ) return; - SELF_COMPILE( ( AREAP ) pTag->pIndex->pArea, ( BYTE * ) pTag->KeyExpr ); - /* TODO: RT error if SELF_COMPILE return FAILURE */ + if ( SELF_COMPILE( ( AREAP ) pTag->pIndex->pArea, ( BYTE * ) pTag->KeyExpr ) == FAILURE ) + { + pTag->RootBlock = 0; /* To force RT error - index corrupted */ + return; + } pTag->pKeyItem = pTag->pIndex->pArea->valResult; pTag->pIndex->pArea->valResult = NULL; - /* Get a blank record before testing expression */ + + /* go to a blank record before testing expression */ ulRecNo = pTag->pIndex->pArea->ulRecNo; SELF_GOTO( ( AREAP ) pTag->pIndex->pArea, 0 ); - hb_macroRun( ( HB_MACRO_PTR ) hb_itemGetPtr( pTag->pKeyItem ) ); - switch( hb_itemType( hb_stackItemFromTop( -1 ) ) ) - { - case HB_IT_INTEGER: - case HB_IT_LONG: - case HB_IT_DOUBLE: - pTag->uiType = 'N'; - pTag->uiLen = 8; - break; - case HB_IT_DATE: - pTag->uiType = 'D'; - pTag->uiLen = 8; - break; - - case HB_IT_LOGICAL: - pTag->uiType = 'L'; - pTag->uiLen = 1; - break; - - case HB_IT_STRING: - pTag->uiType = 'C'; - /* TODO: is this safe? */ - /* pTag->uiLen = HB_CDXMAXKEY( ( hb_stackItemFromTop( -1 ) )->item.asString.length ); */ - break; - } - hb_stackPop(); /* pop macro evaluated value */ + pTag->uiType = hb_cdxItemType( hb_vmEvalBlockOrMacro( pTag->pKeyItem ) ); + pTag->bTrail = ( pTag->uiType == 'C' ) ? ' ' : '\0'; if ( pTag->uiType == 'C' ) hb_cdxMakeSortTab( pTag->pIndex->pArea ); - pTag->nField = hb_cdxFieldIndex( pTag->pIndex->pArea, pTag->KeyExpr ); + pTag->nField = hb_rddFieldExpIndex( ( AREAP ) pTag->pIndex->pArea, + pTag->KeyExpr ); - /* Check if there is a FOR expression CDX_TYPE_FORFILTER */ - if ( pHeader.keyExpPool[ strlen( pTag->KeyExpr ) + 1 ] != 0 ) + /* Check if there is a FOR expression: pTag->OptFlags & CDX_TYPE_FORFILTER */ + if ( tagHeader.keyExpPool[ uiForPos ] != 0 ) { - pTag->ForExpr = ( char * ) hb_xgrab( CDX_MAXKEY + 1 ); - hb_strncpyTrim( pTag->ForExpr, ( const char * ) pHeader.keyExpPool + - strlen( pTag->KeyExpr ) + 1, CDX_MAXKEY ); - SELF_COMPILE( ( AREAP ) pTag->pIndex->pArea, ( BYTE * ) pTag->ForExpr ); - /* TODO: RT error if SELF_COMPILE return FAILURE */ - pTag->pForItem = pTag->pIndex->pArea->valResult; - pTag->pIndex->pArea->valResult = NULL; - pMacro = ( HB_MACRO_PTR ) hb_itemGetPtr( pTag->pForItem ); - hb_macroRun( pMacro ); - if ( hb_itemType( hb_stackItemFromTop( -1 ) ) != HB_IT_LOGICAL ) + pTag->ForExpr = ( char * ) hb_xgrab( CDX_MAXEXP + 1 ); + hb_strncpyTrim( pTag->ForExpr, ( const char * ) tagHeader.keyExpPool + + uiForPos, CDX_MAXEXP ); + if ( SELF_COMPILE( ( AREAP ) pTag->pIndex->pArea, ( BYTE * ) pTag->ForExpr ) == FAILURE ) + pTag->RootBlock = 0; /* To force RT error - index corrupted */ + else { - hb_macroDelete( pMacro ); - hb_itemRelease( pTag->pForItem ); - pTag->pForItem = NULL; - hb_xfree( pTag->ForExpr ); - pTag->ForExpr = NULL; + pTag->pForItem = pTag->pIndex->pArea->valResult; + pTag->pIndex->pArea->valResult = NULL; + if ( hb_cdxItemType( hb_vmEvalBlockOrMacro( pTag->pForItem ) ) != 'L' ) + pTag->RootBlock = 0; /* To force RT error - index corrupted */ } - hb_stackPop(); } SELF_GOTO( ( AREAP ) pTag->pIndex->pArea, ulRecNo ); -} -/* - * Creates a new structure with a tag information - * TagHdr = offset of index page where a tag header is stored - * if CDX_DUMMYNODE then allocate space ofor a new tag header - */ -static LPCDXTAG hb_cdxTagNew( LPCDXINDEX pIndex, char *szTagName, ULONG TagHdr ) -{ - LPCDXTAG pTag; - - pTag = ( LPCDXTAG ) hb_xgrab( sizeof( CDXTAG ) ); - memset( pTag, 0, sizeof( CDXTAG ) ); - pTag->szName = ( char * ) hb_xgrab( CDX_MAXTAGNAMELEN + 1 ); - hb_strncpyUpperTrim( pTag->szName, szTagName, CDX_MAXTAGNAMELEN ); - pTag->pIndex = pIndex; - pTag->AscendKey = pTag->UsrAscend = TRUE; - pTag->UsrUnique = FALSE; - pTag->uiType = 'C'; - pTag->CurKey = hb_cdxKeyNew(); - if ( TagHdr == CDX_DUMMYNODE ) + if ( pTag->uiLen > CDX_MAXKEY || pTag->uiType == 'U' || + ( pTag->uiType == 'N' && pTag->uiLen != 8 ) || + ( pTag->uiType == 'D' && pTag->uiLen != 8 ) || + ( pTag->uiType == 'L' && pTag->uiLen != 1 ) ) { - pTag->TagBlock = hb_cdxIndexGetAvailPage( pIndex, TRUE ); - pTag->TagChanged = TRUE; - pTag->OptFlags = CDX_TYPE_COMPACT | CDX_TYPE_COMPOUND; + pTag->RootBlock = 0; /* To force RT error - index corrupted */ } - else - { - pTag->TagBlock = TagHdr; - hb_cdxTagLoad( pTag ); - } - return pTag; } /* @@ -3584,19 +3682,11 @@ static void hb_cdxTagFree( LPCDXTAG pTag ) if ( pTag->KeyExpr != NULL ) hb_xfree( pTag->KeyExpr ); if ( pTag->pKeyItem != NULL ) - { - if ( hb_itemType( pTag->pKeyItem ) != HB_IT_BLOCK ) - hb_macroDelete( ( HB_MACRO_PTR ) hb_itemGetPtr( pTag->pKeyItem ) ); - hb_itemRelease( pTag->pKeyItem ); - } + hb_cdxDestroyExp( pTag->pKeyItem ); if ( pTag->ForExpr != NULL ) hb_xfree( pTag->ForExpr ); if ( pTag->pForItem != NULL ) - { - if ( hb_itemType( pTag->pForItem ) != HB_IT_BLOCK ) - hb_macroDelete( ( HB_MACRO_PTR ) hb_itemGetPtr( pTag->pForItem ) ); - hb_itemRelease( pTag->pForItem ); - } + hb_cdxDestroyExp( pTag->pForItem ); hb_cdxKeyFree( pTag->CurKey ); if ( pTag->HotKey ) hb_cdxKeyFree( pTag->HotKey ); @@ -3605,6 +3695,46 @@ static void hb_cdxTagFree( LPCDXTAG pTag ) hb_xfree( pTag ); } +/* + * Creates a new structure with a tag information + * TagHdr = offset of index page where a tag header is stored + * if CDX_DUMMYNODE then allocate space ofor a new tag header + */ +static LPCDXTAG hb_cdxTagNew( LPCDXINDEX pIndex, char *szTagName, ULONG TagHdr ) +{ + LPCDXTAG pTag; + char szName[ CDX_MAXTAGNAMELEN + 1 ]; + + pTag = ( LPCDXTAG ) hb_xgrab( sizeof( CDXTAG ) ); + memset( pTag, 0, sizeof( CDXTAG ) ); + hb_strncpyUpperTrim( szName, szTagName, CDX_MAXTAGNAMELEN ); + pTag->szName = hb_strdup( szName ); + pTag->pIndex = pIndex; + pTag->AscendKey = pTag->UsrAscend = TRUE; + pTag->UsrUnique = FALSE; + pTag->uiType = 'C'; + pTag->bTrail = ' '; + pTag->CurKey = hb_cdxKeyNew(); + if ( TagHdr == CDX_DUMMYNODE ) + { + pTag->TagBlock = hb_cdxIndexGetAvailPage( pIndex, TRUE ); + pTag->TagChanged = TRUE; + pTag->OptFlags = CDX_TYPE_COMPACT | CDX_TYPE_COMPOUND; + } + else + { + pTag->TagBlock = TagHdr; + hb_cdxTagLoad( pTag ); + if ( pTag->RootBlock == 0 ) + { + /* index file is corrupted */ + hb_cdxTagFree( pTag ); + pTag = NULL; + } + } + return pTag; +} + /* * close Tag (free used pages into page pool) */ @@ -3824,6 +3954,30 @@ static BOOL hb_cdxCheckRecordScope( CDXAREAP pArea, ULONG ulRec ) return TRUE; } +/* + * check and avaluate record filter + */ +static BOOL hb_cdxCheckRecordFilter( CDXAREAP pArea, ULONG ulRecNo ) +{ + BOOL lResult = FALSE; + + if ( pArea->dbfi.itmCobExpr || hb_set.HB_SET_DELETED ) + { + if( pArea->ulRecNo != ulRecNo || pArea->lpdbPendingRel ) + SELF_GOTO( ( AREAP ) pArea, ulRecNo ); + + if( hb_set.HB_SET_DELETED ) + SUPER_DELETED( ( AREAP ) pArea, &lResult ); + + if( !lResult && pArea->dbfi.itmCobExpr ) + { + PHB_ITEM pResult = hb_vmEvalBlock( pArea->dbfi.itmCobExpr ); + lResult = HB_IS_LOGICAL( pResult ) && !hb_itemGetL( pResult ); + } + } + return !lResult; +} + /* * read Top Key from Page or its children */ @@ -3875,27 +4029,21 @@ static BOOL hb_cdxPageReadPrevKey( LPCDXPAGE pPage ) pPage = pPage->Child; } - do + pPage->iCurKey--; + while ( pPage->iCurKey < 0 ) { - pPage->iCurKey--; - if ( pPage->iCurKey < 0 ) + if ( pPage->Left == CDX_DUMMYNODE || !pOwnerPage ) { - while ( pPage->Left == CDX_DUMMYNODE || !pOwnerPage ) - { - pPage->iCurKey = 0; - if ( pPage->iKeys > 0 ) - hb_cdxSetCurKey( pPage ); - return FALSE; - } - pOwnerPage->Child = hb_cdxPageNew( pPage->TagParent, pPage->Owner, pPage->Left ); - hb_cdxPageFree( pPage, !pPage->fChanged ); - pPage = pOwnerPage->Child; - pPage->iCurKey = pPage->iKeys - 1; + pPage->iCurKey = 0; + if ( pPage->iKeys > 0 ) + hb_cdxSetCurKey( pPage ); + return FALSE; } + pOwnerPage->Child = hb_cdxPageNew( pPage->TagParent, pPage->Owner, pPage->Left ); + hb_cdxPageFree( pPage, !pPage->fChanged ); + pPage = pOwnerPage->Child; + pPage->iCurKey = pPage->iKeys - 1; } - while ( ( pPage->TagParent->OptFlags & CDX_TYPE_STRUCTURE ) == 0 && - ! hb_cdxCheckRecordScope( pPage->TagParent->pIndex->pArea, - hb_cdxPageGetKeyRec( pPage, pPage->iCurKey ) ) ); hb_cdxSetCurKey( pPage ); return TRUE; @@ -3914,25 +4062,19 @@ static BOOL hb_cdxPageReadNextKey( LPCDXPAGE pPage ) pPage = pPage->Child; } - do + pPage->iCurKey++; + while ( pPage->iCurKey >= pPage->iKeys ) { - pPage->iCurKey++; - while ( pPage->iCurKey >= pPage->iKeys ) + if ( pPage->Right == CDX_DUMMYNODE || !pOwnerPage ) { - if ( pPage->Right == CDX_DUMMYNODE || !pOwnerPage ) - { - pPage->iCurKey = pPage->iKeys; - return FALSE; - } - pOwnerPage->Child = hb_cdxPageNew( pPage->TagParent, pPage->Owner, pPage->Right ); - hb_cdxPageFree( pPage, !pPage->fChanged ); - pPage = pOwnerPage->Child; - pPage->iCurKey = 0; + pPage->iCurKey = pPage->iKeys; + return FALSE; } + pOwnerPage->Child = hb_cdxPageNew( pPage->TagParent, pPage->Owner, pPage->Right ); + hb_cdxPageFree( pPage, !pPage->fChanged ); + pPage = pOwnerPage->Child; + pPage->iCurKey = 0; } - while ( ( pPage->TagParent->OptFlags & CDX_TYPE_STRUCTURE ) == 0 && - ! hb_cdxCheckRecordScope( pPage->TagParent->pIndex->pArea, - hb_cdxPageGetKeyRec( pPage, pPage->iCurKey ) ) ); hb_cdxSetCurKey( pPage ); return TRUE; @@ -4144,7 +4286,6 @@ static ULONG hb_cdxTagKeyFind( LPCDXTAG pTag, LPCDXKEY pKey ) int K; ULONG ulKeyRec = pKey->rec; - pTag->CurKey->rec = 0; pTag->fRePos = FALSE; hb_cdxTagOpen( pTag ); @@ -4154,7 +4295,10 @@ static ULONG hb_cdxTagKeyFind( LPCDXTAG pTag, LPCDXKEY pKey ) K = - K; if ( K > 0 ) + { + pTag->CurKey->rec = 0; pTag->TagEOF = TRUE; + } else { hb_cdxSetCurKey( pTag->RootPage ); @@ -4220,7 +4364,7 @@ static BOOL hb_cdxTagKeyAdd( LPCDXTAG pTag, LPCDXKEY pKey ) hb_cdxTagOpen( pTag ); if ( hb_cdxPageSeekKey( pTag->RootPage, pKey, pTag->UniqueKey ? CDX_IGNORE_REC_NUM : pKey->rec, - TRUE ) != 0 ) + TRUE ) != 0 || pTag->Custom ) { hb_cdxPageKeyInsert( pTag->RootPage, pKey ); pTag->curKeyState &= ~( CDX_CURKEY_RAWPOS | CDX_CURKEY_LOGPOS | @@ -4255,6 +4399,7 @@ static BOOL hb_cdxTagKeyDel( LPCDXTAG pTag, LPCDXKEY pKey ) static void hb_cdxTagGoTop( LPCDXTAG pTag ) { LPCDXKEY pKey = pTag->UsrAscend ? pTag->topScopeKey : pTag->bottomScopeKey; + ULONG ulPos = 1; if ( pKey ) hb_cdxTagKeyFind( pTag, pKey ); @@ -4265,17 +4410,19 @@ static void hb_cdxTagGoTop( LPCDXTAG pTag ) { if ( pTag->CurKey->rec == 0 || pTag->TagEOF || ! hb_cdxBottomScope( pTag ) ) { + pTag->TagBOF = pTag->TagEOF = TRUE; pTag->CurKey->rec = 0; break; } else if ( ( pTag->OptFlags & CDX_TYPE_STRUCTURE ) != 0 || hb_cdxCheckRecordScope( pTag->pIndex->pArea, pTag->CurKey->rec ) ) { - pTag->rawKeyPos = 1; + pTag->rawKeyPos = ulPos; CURKEY_SETRAWPOS( pTag ); break; } hb_cdxTagKeyRead( pTag, NEXT_RECORD ); + ulPos++; } while ( TRUE ); } @@ -4286,6 +4433,7 @@ static void hb_cdxTagGoTop( LPCDXTAG pTag ) static void hb_cdxTagGoBottom( LPCDXTAG pTag ) { LPCDXKEY pKey = pTag->UsrAscend ? pTag->bottomScopeKey : pTag->topScopeKey; + ULONG ulPos = 0; if ( pKey ) hb_cdxTagKeyFind( pTag, pKey ); @@ -4296,6 +4444,7 @@ static void hb_cdxTagGoBottom( LPCDXTAG pTag ) { if ( pTag->CurKey->rec == 0 || pTag->TagBOF || ! hb_cdxTopScope( pTag ) ) { + pTag->TagBOF = pTag->TagEOF = TRUE; pTag->CurKey->rec = 0; break; } @@ -4304,12 +4453,13 @@ static void hb_cdxTagGoBottom( LPCDXTAG pTag ) { if ( CURKEY_RAWCNT( pTag ) ) { - pTag->rawKeyPos = pTag->rawKeyCount; + pTag->rawKeyPos = pTag->rawKeyCount - ulPos; CURKEY_SETRAWPOS( pTag ); } break; } hb_cdxTagKeyRead( pTag, PREV_RECORD ); + ulPos++; } while ( TRUE ); } @@ -4342,6 +4492,7 @@ static void hb_cdxTagSkipNext( LPCDXTAG pTag ) hb_cdxCheckRecordScope( pTag->pIndex->pArea, pTag->CurKey->rec ) ) break; hb_cdxTagKeyRead( pTag, NEXT_RECORD ); + ulSkip++; } if ( fEof ) @@ -4381,6 +4532,7 @@ static void hb_cdxTagSkipPrev( LPCDXTAG pTag ) hb_cdxCheckRecordScope( pTag->pIndex->pArea, pTag->CurKey->rec ) ) break; hb_cdxTagKeyRead( pTag, PREV_RECORD ); + ulSkip++; } @@ -4427,25 +4579,35 @@ static void hb_cdxReorderTagList( LPCDXTAG * TagListPtr ) /* * create new order header, store it and then make an order */ -static void hb_cdxTagIndexTagNew( LPCDXTAG pTag, - char * KeyExp, PHB_ITEM pKeyItem, - BYTE bType, USHORT uiLen, - char * ForExp, PHB_ITEM pForItem, - BOOL fAscnd, BOOL fUniq, BOOL fCustom ) +static LPCDXTAG hb_cdxIndexCreateTag( BOOL fStruct, LPCDXINDEX pIndex, + char * szTagName, + char * KeyExp, PHB_ITEM pKeyItem, + BYTE bType, USHORT uiLen, + char * ForExp, PHB_ITEM pForItem, + BOOL fAscnd, BOOL fUniq, BOOL fCustom, + BOOL fReindex ) { + LPCDXTAG pTag; + + pTag = hb_cdxTagNew( pIndex, szTagName, CDX_DUMMYNODE ); + + if ( fStruct ) + pTag->OptFlags |= CDX_TYPE_STRUCTURE; + if ( bType == 'C' ) hb_cdxMakeSortTab( pTag->pIndex->pArea ); if ( KeyExp != NULL ) { - pTag->KeyExpr = ( char * ) hb_xgrab( CDX_MAXKEY + 1 ); - hb_strncpyTrim( pTag->KeyExpr, KeyExp, CDX_MAXKEY ); - pTag->nField = hb_cdxFieldIndex( pTag->pIndex->pArea, pTag->KeyExpr ); + pTag->KeyExpr = ( char * ) hb_xgrab( CDX_MAXEXP + 1 ); + hb_strncpyTrim( pTag->KeyExpr, KeyExp, CDX_MAXEXP ); + pTag->nField = hb_rddFieldExpIndex( ( AREAP ) pTag->pIndex->pArea, + pTag->KeyExpr ); } pTag->pKeyItem = pKeyItem; if ( ForExp != NULL ) { - pTag->ForExpr = ( char * ) hb_xgrab( CDX_MAXKEY + 1 ); - hb_strncpyTrim( pTag->ForExpr, ForExp, CDX_MAXKEY ); + pTag->ForExpr = ( char * ) hb_xgrab( CDX_MAXEXP + 1 ); + hb_strncpyTrim( pTag->ForExpr, ForExp, CDX_MAXEXP ); } pTag->pForItem = pForItem; pTag->AscendKey = pTag->UsrAscend = fAscnd; @@ -4453,10 +4615,24 @@ static void hb_cdxTagIndexTagNew( LPCDXTAG pTag, pTag->UsrUnique = FALSE; pTag->Custom = fCustom; pTag->uiType = bType; + pTag->bTrail = ( pTag->uiType == 'C' ) ? ' ' : '\0'; pTag->uiLen = uiLen; pTag->MaxKeys = CDX_INT_FREESPACE / ( uiLen + 8 ); pTag->TagChanged = TRUE; - hb_cdxTagDoIndex( pTag ); + hb_cdxTagDoIndex( pTag, fReindex ); + + return pTag; +} + +/* + * create structural (compound) tag + */ +static void hb_cdxIndexCreateStruct( LPCDXINDEX pIndex, char * szTagName ) +{ + /* here we can change default tag name */ + pIndex->pCompound = hb_cdxIndexCreateTag( TRUE, pIndex, szTagName, + NULL, NULL, 'C', CDX_MAXTAGNAMELEN, NULL, NULL, + TRUE, FALSE, FALSE, FALSE ); } /* @@ -4494,7 +4670,8 @@ static void hb_cdxIndexDelTag( LPCDXINDEX pIndex, char * szTagName ) if ( *pTagPtr ) { LPCDXTAG pTag = *pTagPtr; - LPCDXKEY pKey = hb_cdxKeyPutC( NULL, szTagName, CDX_MAXTAGNAMELEN, pTag->TagBlock ); + LPCDXKEY pKey = hb_cdxKeyPutC( NULL, szTagName, pIndex->pCompound->uiLen, + pTag->TagBlock ); if ( hb_cdxTagKeyDel( pIndex->pCompound, pKey ) ) { if ( pTag != pIndex->TagList || pTag->pNext != NULL ) @@ -4526,7 +4703,8 @@ static LPCDXTAG hb_cdxIndexAddTag( LPCDXINDEX pIndex, char * szTagName, char * szKeyExp, PHB_ITEM pKeyItem, BYTE bType, USHORT uiLen, char * szForExp, PHB_ITEM pForItem, - BOOL fAscend, BOOL fUnique, BOOL fCustom ) + BOOL fAscend, BOOL fUnique, BOOL fCustom, + BOOL fReindex ) { LPCDXTAG pTag, *pTagPtr; LPCDXKEY pKey; @@ -4537,15 +4715,14 @@ static LPCDXTAG hb_cdxIndexAddTag( LPCDXINDEX pIndex, char * szTagName, hb_cdxIndexDelTag( pIndex, szTagName ); /* Create new tag an add to tag list */ - pTag = hb_cdxTagNew( pIndex, szTagName, CDX_DUMMYNODE ); - hb_cdxTagIndexTagNew( pTag, szKeyExp, pKeyItem, bType, uiLen, - szForExp, pForItem, - fAscend, fUnique, fCustom ); + pTag = hb_cdxIndexCreateTag( FALSE, pIndex, szTagName, szKeyExp, pKeyItem, + bType, uiLen, szForExp, pForItem, + fAscend, fUnique, fCustom, fReindex ); pTagPtr = &pIndex->TagList; while ( *pTagPtr ) pTagPtr = &(*pTagPtr)->pNext; *pTagPtr = pTag; - pKey = hb_cdxKeyPutC( NULL, szTagName, CDX_MAXTAGNAMELEN, pTag->TagBlock ); + pKey = hb_cdxKeyPutC( NULL, szTagName, pIndex->pCompound->uiLen, pTag->TagBlock ); hb_cdxTagKeyAdd( pIndex->pCompound, pKey ); hb_cdxKeyFree( pKey ); return pTag; @@ -4576,10 +4753,7 @@ static void hb_cdxIndexReindex( LPCDXINDEX pIndex ) /* Rebuild the compound (master) tag */ if ( pCompound ) { - pIndex->pCompound = hb_cdxTagNew( pIndex, pCompound->szName, CDX_DUMMYNODE ); - pIndex->pCompound->OptFlags = CDX_TYPE_COMPACT | CDX_TYPE_COMPOUND | CDX_TYPE_STRUCTURE; - hb_cdxTagIndexTagNew( pIndex->pCompound, NULL, NULL, 'C', - CDX_MAXTAGNAMELEN, NULL, NULL, TRUE, FALSE, FALSE ); + hb_cdxIndexCreateStruct( pIndex, pCompound->szName ); hb_cdxTagFree( pCompound ); } @@ -4589,7 +4763,7 @@ static void hb_cdxIndexReindex( LPCDXINDEX pIndex ) pTag = pTagList; hb_cdxIndexAddTag( pIndex, pTag->szName, pTag->KeyExpr, pTag->pKeyItem, (BYTE) pTag->uiType, pTag->uiLen, pTag->ForExpr, pTag->pForItem, - pTag->AscendKey, pTag->UniqueKey, pTag->Custom ); + pTag->AscendKey, pTag->UniqueKey, pTag->Custom, TRUE ); pTagList = pTag->pNext; pTag->pKeyItem = pTag->pForItem = NULL; hb_cdxTagFree( pTag ); @@ -4613,15 +4787,12 @@ static LPCDXINDEX hb_cdxIndexNew( CDXAREAP pArea ) } /* - * free (close) index and all tags in it + * free (close) all tag in index file */ -static void hb_cdxIndexFree( LPCDXINDEX pIndex ) +static void hb_cdxIndexFreeTags( LPCDXINDEX pIndex ) { LPCDXTAG pTag; - /* Free List of Free Pages */ - hb_cdxIndexDropAvailPage( pIndex ); - /* Free Compound tag */ if ( pIndex->pCompound != NULL ) { @@ -4629,26 +4800,50 @@ static void hb_cdxIndexFree( LPCDXINDEX pIndex ) pIndex->pCompound = NULL; } - /* Free all tags */ while ( pIndex->TagList ) { pTag = pIndex->TagList; pIndex->TagList = pTag->pNext; hb_cdxTagFree( pTag ); } - /* Close file */ - if ( pIndex->hFile != FS_ERROR ) - hb_fsClose( pIndex->hFile ); +} + +/* + * free (close) index and all tags in it + */ +static void hb_cdxIndexFree( LPCDXINDEX pIndex ) +{ + /* Free List of Free Pages */ + hb_cdxIndexDropAvailPage( pIndex ); + + /* free all tags */ + hb_cdxIndexFreeTags( pIndex ); + + /* Close file */ + if( pIndex->hFile != FS_ERROR ) + { + hb_fsClose( pIndex->hFile ); + if( pIndex->fDelete ) + { + hb_fsDelete( ( BYTE * ) ( pIndex->szRealName ? + pIndex->szRealName : pIndex->szFileName ) ); + } + } - if ( pIndex->fShared && ( pIndex->lockWrite || pIndex->lockRead ) ) - hb_errInternal( 9104, "hb_cdxIndexFree: index file still locked.", "", "" ); #ifdef HB_CDX_DBGCODE - if ( pIndex->WrLck || pIndex->RdLck ) + if( pIndex->fShared && ( pIndex->lockWrite || pIndex->lockRead ) && + hb_vmRequestQuery() == 0 ) + hb_errInternal( 9104, "hb_cdxIndexFree: index file still locked.", "", "" ); + + if( ( pIndex->WrLck || pIndex->RdLck ) && + hb_vmRequestQuery() == 0 ) hb_errInternal( 9104, "hb_cdxIndexFree: index file still locked (*)", "", "" ); #endif if ( pIndex->szFileName != NULL ) hb_xfree( pIndex->szFileName ); + if( pIndex->szRealName ) + hb_xfree( pIndex->szRealName ); hb_xfree( pIndex ); } @@ -4656,35 +4851,51 @@ static void hb_cdxIndexFree( LPCDXINDEX pIndex ) /* * load orders from index file */ -static void hb_cdxIndexLoad( LPCDXINDEX pIndex, char * szBaseName ) +static BOOL hb_cdxIndexLoad( LPCDXINDEX pIndex, char * szBaseName ) { LPCDXTAG TagList, * pTagPtr; + BOOL fResult = FALSE; - /* TODO: check if index file is not corrupted */ + TagList = NULL; + pTagPtr = &TagList; hb_cdxIndexLockRead( pIndex ); /* load the tags*/ pIndex->pCompound = hb_cdxTagNew( pIndex, szBaseName, 0L ); - pIndex->pCompound->OptFlags = CDX_TYPE_COMPACT | CDX_TYPE_COMPOUND | CDX_TYPE_STRUCTURE; - TagList = NULL; - pTagPtr = &TagList; - hb_cdxTagGoTop( pIndex->pCompound ); - while ( !pIndex->pCompound->TagEOF ) + + /* check if index is not corrupted */ + if ( pIndex->pCompound ) { - (*pTagPtr) = hb_cdxTagNew( pIndex, (char *) pIndex->pCompound->CurKey->val, - pIndex->pCompound->CurKey->rec ); - pTagPtr = &(*pTagPtr)->pNext; - hb_cdxTagSkipNext( pIndex->pCompound ); + fResult = TRUE; + pIndex->pCompound->OptFlags = CDX_TYPE_COMPACT | CDX_TYPE_COMPOUND | CDX_TYPE_STRUCTURE; + hb_cdxTagGoTop( pIndex->pCompound ); + while ( !pIndex->pCompound->TagEOF ) + { + *pTagPtr = hb_cdxTagNew( pIndex, (char *) pIndex->pCompound->CurKey->val, + pIndex->pCompound->CurKey->rec ); + /* tag is corrupted - break tags loading */ + if ( *pTagPtr == NULL ) + { + fResult = FALSE; + break; + } + pTagPtr = &(*pTagPtr)->pNext; + hb_cdxTagSkipNext( pIndex->pCompound ); + } } + hb_cdxIndexUnLockRead( pIndex ); hb_cdxReorderTagList( &TagList ); pTagPtr = &pIndex->TagList; while ( *pTagPtr != NULL ) pTagPtr = &(*pTagPtr)->pNext; (*pTagPtr) = TagList; + #ifdef HB_CDX_DSPDBG_INFO hb_cdxDspTags( pIndex ); #endif + + return fResult; } /* @@ -4694,8 +4905,8 @@ static void hb_cdxCreateFName( CDXAREAP pArea, char * szBagName, char * szFileName, char * szBaseName ) { PHB_FNAME pFileName; - BOOL fName = szBagName && strlen( szBagName ) > 0; - char * szExt = NULL; + BOOL fName = szBagName && *szBagName; + PHB_ITEM pExt = NULL; pFileName = hb_fsFNameSplit( fName ? szBagName : pArea->szDataFileName ); @@ -4708,19 +4919,18 @@ static void hb_cdxCreateFName( CDXAREAP pArea, char * szBagName, { DBORDERINFO pExtInfo; memset( &pExtInfo, 0, sizeof( pExtInfo ) ); - pExtInfo.itmResult = hb_itemPutC( NULL, "" ); + pExt = pExtInfo.itmResult = hb_itemPutC( NULL, "" ); if ( SELF_ORDINFO( ( AREAP ) pArea, DBOI_BAGEXT, &pExtInfo ) == SUCCESS && hb_itemGetCLen( pExtInfo.itmResult ) > 0 ) { - pFileName->szExtension = szExt = hb_strdup( hb_itemGetCPtr( pExtInfo.itmResult ) ); + pFileName->szExtension = hb_itemGetCPtr( pExtInfo.itmResult ); } - hb_itemRelease( pExtInfo.itmResult ); } hb_fsFNameMerge( szFileName, pFileName ); - if ( szExt ) - hb_xfree( szExt ); + if ( pExt ) + hb_itemRelease( pExt ); hb_xfree( pFileName ); } @@ -4819,13 +5029,13 @@ static USHORT hb_cdxGetTagNumber( CDXAREAP pArea, LPCDXTAG pFindTag ) { USHORT uiTag = 0; LPCDXTAG pTag = NULL; - LPCDXINDEX pCdx = pArea->lpIndexes; + LPCDXINDEX pIndex = pArea->lpIndexes; if ( pFindTag ) { - while ( pCdx && ( pTag != pFindTag ) ) + while ( pIndex && ( pTag != pFindTag ) ) { - pTag = pCdx->TagList; + pTag = pIndex->TagList; while ( pTag ) { uiTag++; @@ -4833,7 +5043,7 @@ static USHORT hb_cdxGetTagNumber( CDXAREAP pArea, LPCDXTAG pFindTag ) break; pTag = pTag->pNext; } - pCdx = pCdx->pNext; + pIndex = pIndex->pNext; } if ( !pTag ) uiTag = 0; @@ -4848,50 +5058,68 @@ static LPCDXTAG hb_cdxFindTag( CDXAREAP pArea, PHB_ITEM pTagItem, PHB_ITEM pBagItem, USHORT *puiTag ) { LPCDXTAG pTag = NULL; - USHORT uiTag = 0, uiFind = 0; - LPCDXINDEX pIndex, pBagIndex; - char szName[ CDX_MAXTAGNAMELEN + 1 ]; + int iTag = 0, iFind = 0; + char szTag[ CDX_MAXTAGNAMELEN + 1 ]; + LPCDXINDEX pIndex = pArea->lpIndexes; + BOOL fBag; - szName[ 0 ] = '\0'; - if ( HB_IS_STRING( pTagItem ) ) + hb_strncpyUpperTrim( szTag, hb_itemGetCPtr( pTagItem ), CDX_MAXTAGNAMELEN ); + if( ! szTag[0] ) + iFind = hb_itemGetNI( pTagItem ); + + fBag = hb_itemGetCLen( pBagItem ) > 0; + if( fBag ) { - hb_strncpyUpperTrim( szName, pTagItem->item.asString.value, - HB_MIN( pTagItem->item.asString.length, CDX_MAXTAGNAMELEN ) ); + if( szTag[ 0 ] ) + pIndex = hb_cdxFindBag( pArea, hb_itemGetCPtr( pBagItem ) ); } - else if ( HB_IS_NUMERIC( pTagItem ) ) + else { - uiFind = hb_itemGetNI( pTagItem ); + int iBag = hb_itemGetNI( pBagItem ); + + if( iBag > 0 ) + { + fBag = TRUE; + while( pIndex ) + { + if( --iBag == 0 ) + break; + pIndex = pIndex->pNext; + } + } + else if( iBag < 0 ) + { + pIndex = NULL; + } } - pIndex = pArea->lpIndexes; - if ( pIndex && ( uiFind != 0 || szName[ 0 ] ) ) + if( pIndex && ( iFind > 0 || szTag[0] ) ) { - if ( pBagItem && HB_IS_STRING( pBagItem ) && pBagItem->item.asString.length > 0 ) - pBagIndex = hb_cdxFindBag( pArea, pBagItem->item.asString.value ); - else - pBagIndex = NULL; - - while ( pIndex ) + do { pTag = pIndex->TagList; - while ( pTag ) + while( pTag ) { - uiTag++; - if ( ( ! pBagIndex || pBagIndex == pIndex ) && - ( uiFind != 0 ? uiTag == uiFind : !hb_stricmp( pTag->szName, szName ) ) ) + iTag++; + if ( ( iFind != 0 ? iTag == iFind : !hb_stricmp( pTag->szName, szTag ) ) ) break; pTag = pTag->pNext; } - if ( pTag || pBagIndex == pIndex ) + if ( pTag || fBag ) break; pIndex = pIndex->pNext; - } - if ( !pTag ) - uiTag = 0; + } while ( pIndex ); } - if ( puiTag ) - *puiTag = uiTag; + if( puiTag ) + { + if( !pTag ) + *puiTag = 0; + else if( fBag ) + *puiTag = hb_cdxGetTagNumber( pArea, pTag ); + else + *puiTag = iTag; + } return pTag; } @@ -4930,22 +5158,23 @@ static BOOL hb_cdxCurKeyRefresh( CDXAREAP pArea, LPCDXTAG pTag ) { BYTE buf[CDX_MAXKEY]; BOOL fBuf = FALSE; + LPCDXKEY pKey = NULL; /* Try to find previous if it's key for the same record */ if ( pTag->CurKey->rec == pArea->ulRecNo ) { fBuf = TRUE; memcpy( buf, pTag->CurKey->val, pTag->CurKey->len ); - hb_cdxTagKeyFind( pTag, pTag->CurKey ); + pKey = hb_cdxKeyCopy( pKey, pTag->CurKey ); + hb_cdxTagKeyFind( pTag, pKey ); } if ( pTag->CurKey->rec != pArea->ulRecNo ) { BOOL fValidBuf = pArea->fValidBuffer; - LPCDXKEY pKey = hb_cdxKeyEval( NULL, pTag, TRUE ); /* not found, create new key from DBF and if differs seek again */ + pKey = hb_cdxKeyEval( pKey, pTag ); if ( !fBuf || memcmp( buf, pKey->val, pKey->len ) != 0 ) { - memcpy( buf, pKey->val, pKey->len ); hb_cdxTagKeyFind( pTag, pKey ); } /* not found, if key was generated from DBF buffer then force to @@ -4953,19 +5182,20 @@ static BOOL hb_cdxCurKeyRefresh( CDXAREAP pArea, LPCDXTAG pTag ) if ( pTag->CurKey->rec != pArea->ulRecNo && fValidBuf ) { SELF_GOTO( ( AREAP ) pArea, pArea->ulRecNo ); - pKey = hb_cdxKeyEval( pKey, pTag, TRUE ); + memcpy( buf, pKey->val, pKey->len ); + pKey = hb_cdxKeyEval( pKey, pTag ); if ( memcmp( buf, pKey->val, pKey->len ) != 0 ) hb_cdxTagKeyFind( pTag, pKey ); } - hb_cdxKeyFree( pKey ); } + hb_cdxKeyFree( pKey ); return ( pTag->CurKey->rec != 0 && pTag->CurKey->rec == pArea->ulRecNo ); } return TRUE; } /* - * skip to next unique key + * skip to next/previous unique key */ static ERRCODE hb_cdxDBOISkipUnique( CDXAREAP pArea, LPCDXTAG pTag, BOOL fForward ) { @@ -4997,6 +5227,7 @@ static ERRCODE hb_cdxDBOISkipUnique( CDXAREAP pArea, LPCDXTAG pTag, BOOL fForwar BOOL fOut = FALSE; hb_cdxIndexLockRead( pTag->pIndex ); + hb_cdxTagRefreshScope( pTag ); if ( ! hb_cdxCurKeyRefresh( pArea, pTag ) ) { if ( pTag->TagEOF ) @@ -5004,7 +5235,7 @@ static ERRCODE hb_cdxDBOISkipUnique( CDXAREAP pArea, LPCDXTAG pTag, BOOL fForwar else if ( ( fForward ? pTag->UsrAscend : !pTag->UsrAscend ) && pTag->CurKey->rec != 0 ) { - pKey = hb_cdxKeyEval( pKey, pTag, TRUE ); + pKey = hb_cdxKeyEval( pKey, pTag ); } } if ( fForward ) @@ -5102,6 +5333,7 @@ static BOOL hb_cdxDBOISkipEval( CDXAREAP pArea, LPCDXTAG pTag, BOOL fForward, pArea->fTop = pArea->fBottom = FALSE; hb_cdxIndexLockRead( pTag->pIndex ); + hb_cdxTagRefreshScope( pTag ); if ( ! hb_cdxCurKeyRefresh( pArea, pTag ) ) { if ( !pTag->TagEOF && pTag->CurKey->rec != 0 && @@ -5195,6 +5427,7 @@ static BOOL hb_cdxDBOISkipWild( CDXAREAP pArea, LPCDXTAG pTag, BOOL fForward, pArea->fTop = pArea->fBottom = FALSE; hb_cdxIndexLockRead( pTag->pIndex ); + hb_cdxTagRefreshScope( pTag ); if ( ! hb_cdxCurKeyRefresh( pArea, pTag ) ) { if ( !pTag->TagEOF && pTag->CurKey->rec != 0 && @@ -5268,44 +5501,27 @@ static BOOL hb_cdxDBOISkipRegEx( CDXAREAP pArea, LPCDXTAG pTag, BOOL fForward, PHB_ITEM pRegExItm ) { BOOL fFound = FALSE, fFirst = TRUE; - regex_t re, *pReg; - regmatch_t aMatches[1]; - int CFlags = REG_EXTENDED, EFlags = 0; - char *szMask = hb_itemGetCPtr( pRegExItm ); - BOOL fFree = FALSE; + HB_REGEX RegEx; - HB_TRACE(HB_TR_DEBUG, ("hb_cdxDBOISkipRegEx(%p, %p, %i, %s)", pArea, pTag, fForward, szMask)); + HB_TRACE(HB_TR_DEBUG, ("hb_cdxDBOISkipRegEx(%p, %p, %i, %p)", pArea, pTag, fForward, pRegExItm)); if ( FAST_GOCOLD( ( AREAP ) pArea ) == FAILURE ) return FALSE; - if ( ! pTag || pTag->uiType != 'C' || !szMask || !*szMask ) + if( !pTag || pTag->uiType != 'C' || !hb_regexGet( &RegEx, pRegExItm, 0, 0 ) ) { if ( SELF_SKIP( ( AREAP ) pArea, fForward ? 1 : -1 ) == FAILURE ) return FALSE; return fForward ? pArea->fPositioned : !pArea->fBof; } - if ( hb_isregexstring( pRegExItm ) ) - { - pReg = (regex_t *) ( szMask + 3 ); - } - else - { - if( regcomp( &re, szMask, CFlags ) != 0 ) - { - return FALSE; - } - pReg = &re; - fFree = TRUE; - } - if( pArea->lpdbPendingRel ) SELF_FORCEREL( ( AREAP ) pArea ); pArea->fTop = pArea->fBottom = FALSE; hb_cdxIndexLockRead( pTag->pIndex ); + hb_cdxTagRefreshScope( pTag ); if ( ! hb_cdxCurKeyRefresh( pArea, pTag ) ) { if ( !pTag->TagEOF && pTag->CurKey->rec != 0 && @@ -5318,12 +5534,12 @@ static BOOL hb_cdxDBOISkipRegEx( CDXAREAP pArea, LPCDXTAG pTag, BOOL fForward, hb_cdxTagSkipNext( pTag ); while ( !pTag->TagEOF ) { - if( regexec( pReg, (const char *) pTag->CurKey->val, 1, aMatches, EFlags ) == 0 ) + if( hb_regexMatch( &RegEx, (const char *) pTag->CurKey->val, FALSE ) ) { ULONG ulRecNo = pArea->ulRecNo; SELF_SKIPFILTER( ( AREAP ) pArea, 1 ); if ( pArea->ulRecNo == ulRecNo || - regexec( pReg, (const char *) pTag->CurKey->val, 1, aMatches, EFlags ) == 0 ) + hb_regexMatch( &RegEx, (const char *) pTag->CurKey->val, FALSE ) ) { fFound = TRUE; break; @@ -5339,12 +5555,12 @@ static BOOL hb_cdxDBOISkipRegEx( CDXAREAP pArea, LPCDXTAG pTag, BOOL fForward, hb_cdxTagSkipPrev( pTag ); while ( !pTag->TagBOF ) { - if( regexec( pReg, (const char *) pTag->CurKey->val, 1, aMatches, EFlags ) == 0 ) + if( hb_regexMatch( &RegEx, (const char *) pTag->CurKey->val, FALSE ) ) { ULONG ulRecNo = pArea->ulRecNo; SELF_SKIPFILTER( ( AREAP ) pArea, -1 ); if ( pArea->ulRecNo == ulRecNo || - regexec( pReg, (const char *) pTag->CurKey->val, 1, aMatches, EFlags ) == 0 ) + hb_regexMatch( &RegEx, (const char *) pTag->CurKey->val, FALSE ) ) { fFound = TRUE; break; @@ -5368,8 +5584,7 @@ static BOOL hb_cdxDBOISkipRegEx( CDXAREAP pArea, LPCDXTAG pTag, BOOL fForward, else pArea->fEof = FALSE; - if( fFree ) - regfree( pReg ); + hb_regexFree( &RegEx ); return fFound; } @@ -5378,7 +5593,7 @@ static BOOL hb_cdxDBOISkipRegEx( CDXAREAP pArea, LPCDXTAG pTag, BOOL fForward, /* * evaluate given C function in given scope */ -ULONG hb_cdxDBOIScopeEval( LPCDXTAG pTag, HB_EVALSCOPE_FUNC pFunc, void *pParam, PHB_ITEM pItemLo, PHB_ITEM pItemHi ) +static ULONG hb_cdxDBOIScopeEval( LPCDXTAG pTag, HB_EVALSCOPE_FUNC pFunc, void *pParam, PHB_ITEM pItemLo, PHB_ITEM pItemHi ) { ULONG ulCount = 0, ulLen = ( ULONG ) pTag->uiLen; LPCDXKEY pCurKey = hb_cdxKeyCopy( NULL, pTag->CurKey ), @@ -5398,7 +5613,7 @@ ULONG hb_cdxDBOIScopeEval( LPCDXTAG pTag, HB_EVALSCOPE_FUNC pFunc, void *pParam, hb_cdxIndexLockRead( pTag->pIndex ); hb_cdxTagGoTop( pTag ); - while ( !pTag->TagEOF && hb_cdxBottomScope( pTag ) ) + while( !pTag->TagEOF ) { pFunc( pTag->CurKey->rec, pTag->CurKey->val, ulLen, pParam ); ulCount++; @@ -5426,78 +5641,49 @@ ULONG hb_cdxDBOIScopeEval( LPCDXTAG pTag, HB_EVALSCOPE_FUNC pFunc, void *pParam, */ static LONG hb_cdxDBOIKeyCount( CDXAREAP pArea, LPCDXTAG pTag, BOOL fFilters ) { - ULONG lKeyCount = 0; + ULONG ulKeyCount = 0; + BOOL fLogOpt = pArea->dbfi.itmCobExpr || !pArea->dbfi.fFilter; - /* TODO: what with deleted flag? */ - if ( fFilters && ! pArea->dbfi.itmCobExpr ) - fFilters = FALSE; - - if ( fFilters ) + if ( pTag && ( fFilters ? fLogOpt && CURKEY_LOGCNT( pTag ) : CURKEY_RAWCNT( pTag ) ) ) { - if ( pTag && CURKEY_LOGCNT( pTag ) ) - { - lKeyCount = pTag->logKeyCount; - } - else - { - PHB_ITEM pRecNo; - ULONG ulRec; - USHORT uiTag; - - uiTag = pArea->uiTag; - pArea->uiTag = hb_cdxGetTagNumber( pArea, pTag ); - - pRecNo = hb_itemPutNL( NULL, 0 ); - SELF_RECNO( ( AREAP ) pArea, pRecNo ); - ulRec = hb_itemGetNL( pRecNo ); - hb_itemRelease( pRecNo ); - - SELF_GOTOP( ( AREAP ) pArea ); - while ( !pArea->fEof ) - { - lKeyCount++; - SELF_SKIP( ( AREAP ) pArea, 1 ); - } - SELF_GOTO( ( AREAP ) pArea, ulRec ); - pArea->uiTag = uiTag; - if ( pTag ) - { - pTag->logKeyCount = lKeyCount; - pTag->curKeyState |= CDX_CURKEY_LOGCNT; - } - } + ulKeyCount = fFilters ? pTag->logKeyCount : pTag->rawKeyCount; } else if ( pTag ) { + BOOL fCheckFilter = ( fLogOpt && fFilters && pArea->dbfi.itmCobExpr ); + ULONG ulRecNo = pArea->ulRecNo; LPCDXKEY pCurKey; hb_cdxIndexLockRead( pTag->pIndex ); + hb_cdxTagRefreshScope( pTag ); - if ( CURKEY_RAWCNT( pTag ) ) - { - lKeyCount = pTag->rawKeyCount; - } - else if ( pTag->topScopeKey || pTag->bottomScopeKey || pTag->UsrUnique || pArea->dbfi.fFilter ) + if ( pTag->topScopeKey || pTag->bottomScopeKey || pTag->UsrUnique || pArea->dbfi.fFilter ) { pCurKey = hb_cdxKeyCopy( NULL, pTag->CurKey ); hb_cdxTagGoTop( pTag ); - while ( !pTag->TagEOF && hb_cdxBottomScope( pTag ) ) + while ( !pTag->TagEOF ) { - lKeyCount++; + if ( !fCheckFilter || hb_cdxCheckRecordFilter( pArea, pTag->CurKey->rec ) ) + ulKeyCount++; hb_cdxTagSkipNext( pTag ); } pTag->fRePos = TRUE; hb_cdxKeyCopy( pTag->CurKey, pCurKey ); hb_cdxKeyFree( pCurKey ); + if ( fCheckFilter ) + SELF_GOTO( ( AREAP ) pArea, ulRecNo ); } else { LPCDXPAGE pPage; pCurKey = hb_cdxKeyCopy( NULL, pTag->CurKey ); - hb_cdxTagGoTop( pTag ); + if ( pTag->UsrAscend ) + hb_cdxTagGoTop( pTag ); + else + hb_cdxTagGoBottom( pTag ); pPage = pTag->RootPage; while ( pPage->Child ) pPage = pPage->Child; - lKeyCount = pPage->iKeys; + ulKeyCount = pPage->iKeys; if ( pPage->Right != CDX_DUMMYNODE ) { ULONG ulPage = pPage->Right; @@ -5506,7 +5692,7 @@ static LONG hb_cdxDBOIKeyCount( CDXAREAP pArea, LPCDXTAG pTag, BOOL fFilters ) while ( pPage->Page != CDX_DUMMYNODE ) { hb_cdxPageLoad( pPage ); - lKeyCount += pPage->iKeys; + ulKeyCount += pPage->iKeys; pPage->Page = pPage->Right; } hb_cdxPageFree( pPage, TRUE ); @@ -5515,15 +5701,41 @@ static LONG hb_cdxDBOIKeyCount( CDXAREAP pArea, LPCDXTAG pTag, BOOL fFilters ) hb_cdxKeyCopy( pTag->CurKey, pCurKey ); hb_cdxKeyFree( pCurKey ); } - pTag->rawKeyCount = lKeyCount; - pTag->curKeyState |= CDX_CURKEY_RAWCNT; hb_cdxIndexUnLockRead( pTag->pIndex ); + if ( !fFilters ) + { + pTag->rawKeyCount = ulKeyCount; + pTag->curKeyState |= CDX_CURKEY_RAWCNT; + } + else if ( fLogOpt ) + { + pTag->logKeyCount = ulKeyCount; + pTag->curKeyState |= CDX_CURKEY_LOGCNT; + } } else /* no filter, no order */ { - SELF_RECCOUNT( ( AREAP ) pArea, &lKeyCount ); + if ( fLogOpt && fFilters && pArea->dbfi.itmCobExpr ) + { + ULONG ulRecNo = pArea->ulRecNo; + + if ( SELF_GOTOP( ( AREAP ) pArea ) == SUCCESS ) + { + while ( !pArea->fEof ) + { + ulKeyCount++; + if ( SELF_SKIP( ( AREAP ) pArea, 1 ) != SUCCESS ) + break; + } + SELF_GOTO( ( AREAP ) pArea, ulRecNo ); + } + } + else + { + SELF_RECCOUNT( ( AREAP ) pArea, &ulKeyCount ); + } } - return lKeyCount; + return ulKeyCount; } /* @@ -5531,75 +5743,48 @@ static LONG hb_cdxDBOIKeyCount( CDXAREAP pArea, LPCDXTAG pTag, BOOL fFilters ) */ static LONG hb_cdxDBOIKeyNo( CDXAREAP pArea, LPCDXTAG pTag, BOOL fFilters ) { - ULONG lKeyNo = 0; + ULONG ulKeyNo = 0; + BOOL fLogOpt = pArea->dbfi.itmCobExpr || !pArea->dbfi.fFilter; if( pArea->lpdbPendingRel ) SELF_FORCEREL( ( AREAP ) pArea ); - /* TODO: what with deleted flag? */ - if ( fFilters && ! pArea->dbfi.itmCobExpr ) - fFilters = FALSE; - if ( !pArea->fPositioned ) - lKeyNo = 0; - else if ( fFilters ) + ulKeyNo = 0; + else if ( pTag && ( fFilters ? ( fLogOpt && CURKEY_LOGPOS( pTag ) ) : + ( CURKEY_RAWPOS( pTag ) && + pTag->rawKeyRec == pArea->ulRecNo ) ) ) { - if ( pTag && CURKEY_LOGPOS( pTag ) ) - { - lKeyNo = pTag->logKeyPos; - } - else - { - PHB_ITEM pRecNo; - ULONG ulRec; - USHORT uiTag; - - /* TODO !!!: check for EOF and current filter */ - - uiTag = pArea->uiTag; - pArea->uiTag = hb_cdxGetTagNumber( pArea, pTag ); - - pRecNo = hb_itemPutNL( NULL, 0 ); - SELF_RECNO( ( AREAP ) pArea, pRecNo ); - ulRec = hb_itemGetNL( pRecNo ); - hb_itemRelease( pRecNo ); - do - { - lKeyNo++; - SELF_SKIP( ( AREAP ) pArea, -1 ); - } while ( !( ( AREAP ) pArea )->fBof ); - SELF_GOTO( ( AREAP ) pArea, ulRec ); - pArea->uiTag = uiTag; - if ( pTag ) - { - pTag->logKeyPos = lKeyNo; - CURKEY_SETLOGPOS( pTag ); - } - } + ulKeyNo = fFilters ? pTag->logKeyPos : pTag->rawKeyPos; } else if ( pTag ) { + BOOL fCheckFilter = ( fLogOpt && fFilters && pArea->dbfi.itmCobExpr ); + ULONG ulRecNo = pArea->ulRecNo; + hb_cdxIndexLockRead( pTag->pIndex ); + hb_cdxTagRefreshScope( pTag ); hb_cdxTagOpen( pTag ); if ( hb_cdxCurKeyRefresh( pArea, pTag ) ) { - if ( CURKEY_RAWPOS( pTag ) ) + if ( pTag->topScopeKey || pTag->bottomScopeKey || pTag->UsrUnique || pArea->dbfi.fFilter ) { - lKeyNo = pTag->rawKeyPos; - } - else if ( pTag->topScopeKey || pTag->bottomScopeKey || pTag->UsrUnique || pArea->dbfi.fFilter ) - { - if ( hb_cdxBottomScope( pTag ) ) + if ( hb_cdxBottomScope( pTag ) && + ( !fCheckFilter || hb_cdxCheckRecordFilter( pArea, ulRecNo ) ) ) { + LPCDXKEY pCurKey = hb_cdxKeyCopy( NULL, pTag->CurKey ); while ( !pTag->TagBOF ) { - lKeyNo++; + if ( !fCheckFilter || hb_cdxCheckRecordFilter( pArea, pTag->CurKey->rec ) ) + ulKeyNo++; hb_cdxTagSkipPrev( pTag ); } pTag->fRePos = TRUE; hb_cdxKeyCopy( pTag->CurKey, pCurKey ); hb_cdxKeyFree( pCurKey ); + if ( fCheckFilter ) + SELF_GOTO( ( AREAP ) pArea, ulRecNo ); } } else @@ -5609,7 +5794,7 @@ static LONG hb_cdxDBOIKeyNo( CDXAREAP pArea, LPCDXTAG pTag, BOOL fFilters ) pPage = pPage->Child; if ( pTag->UsrAscend ) { - lKeyNo = pPage->iCurKey + 1; + ulKeyNo = pPage->iCurKey + 1; if ( pPage->Left != CDX_DUMMYNODE ) { ULONG ulPage = pPage->Left; @@ -5618,7 +5803,7 @@ static LONG hb_cdxDBOIKeyNo( CDXAREAP pArea, LPCDXTAG pTag, BOOL fFilters ) while ( pPage->Page != CDX_DUMMYNODE ) { hb_cdxPageLoad( pPage ); - lKeyNo += pPage->iKeys; + ulKeyNo += pPage->iKeys; pPage->Page = pPage->Left; } hb_cdxPageFree( pPage, TRUE ); @@ -5626,7 +5811,7 @@ static LONG hb_cdxDBOIKeyNo( CDXAREAP pArea, LPCDXTAG pTag, BOOL fFilters ) } else { - lKeyNo = pPage->iKeys - pPage->iCurKey; + ulKeyNo = pPage->iKeys - pPage->iCurKey; if ( pPage->Right != CDX_DUMMYNODE ) { ULONG ulPage = pPage->Right; @@ -5635,30 +5820,52 @@ static LONG hb_cdxDBOIKeyNo( CDXAREAP pArea, LPCDXTAG pTag, BOOL fFilters ) while ( pPage->Page != CDX_DUMMYNODE ) { hb_cdxPageLoad( pPage ); - lKeyNo += pPage->iKeys; + ulKeyNo += pPage->iKeys; pPage->Page = pPage->Right; } hb_cdxPageFree( pPage, TRUE ); } } } - if ( lKeyNo != 0 ) + if ( ulKeyNo != 0 ) { - pTag->rawKeyPos = lKeyNo; - CURKEY_SETRAWPOS( pTag ); + if ( !fFilters ) + { + pTag->rawKeyPos = ulKeyNo; + CURKEY_SETRAWPOS( pTag ); + } + else if ( fLogOpt ) + { + pTag->logKeyPos = ulKeyNo; + CURKEY_SETLOGPOS( pTag ); + } } } hb_cdxIndexUnLockRead( pTag->pIndex ); } else { - PHB_ITEM pRecNo; - pRecNo = hb_itemPutNL( NULL, 0 ); - SELF_RECNO( ( AREAP ) pArea, pRecNo ); - lKeyNo = hb_itemGetNL( pRecNo ); - hb_itemRelease( pRecNo ); + ULONG ulRecNo = pArea->ulRecNo; + + if ( fLogOpt && fFilters && pArea->dbfi.itmCobExpr ) + { + if ( hb_cdxCheckRecordFilter( pArea, ulRecNo ) ) + { + do + { + ulKeyNo++; + if ( SELF_SKIP( ( AREAP ) pArea, -1 ) != SUCCESS ) + break; + } while ( !( ( AREAP ) pArea )->fBof ); + SELF_GOTO( ( AREAP ) pArea, ulRecNo ); + } + } + else + { + ulKeyNo = ulRecNo; + } } - return lKeyNo; + return ulKeyNo; } /* @@ -5668,39 +5875,37 @@ static ERRCODE hb_cdxDBOIKeyGoto( CDXAREAP pArea, LPCDXTAG pTag, ULONG ulKeyNo, { ERRCODE retval; ULONG ulKeyCnt = ulKeyNo; - - if( pArea->lpdbPendingRel ) - SELF_FORCEREL( ( AREAP ) pArea ); - - /* TODO: what with deleted flag? */ - if ( fFilters && ! pArea->dbfi.itmCobExpr ) - fFilters = 0; + BOOL fLogOpt = pArea->dbfi.itmCobExpr || !pArea->dbfi.fFilter; if ( ulKeyNo == 0 ) retval = SELF_GOTO( ( AREAP ) pArea, 0 ); - else if ( fFilters ) + else if ( pTag && ! pArea->lpdbPendingRel && ( fFilters ? + fLogOpt && CURKEY_LOGPOS( pTag ) && pTag->logKeyPos == ulKeyNo : + ( CURKEY_RAWPOS( pTag ) && pTag->rawKeyPos == ulKeyNo ) ) ) { - USHORT uiTag = pArea->uiTag; - pArea->uiTag = hb_cdxGetTagNumber( pArea, pTag ); - retval = SELF_GOTOP( ( AREAP ) pArea ); - while ( !pArea->fEof && --ulKeyCnt ) - retval = SELF_SKIP( ( AREAP ) pArea, 1 ); - pArea->uiTag = uiTag; - if ( pTag && pArea->fPositioned ) - { - pTag->logKeyPos = ulKeyNo; - CURKEY_SETLOGPOS( pTag ); - } + retval = SELF_GOTO( ( AREAP ) pArea, fFilters ? pTag->logKeyRec : pTag->rawKeyRec ); } else if ( pTag ) { + BOOL fCheckFilter = ( fLogOpt && fFilters && pArea->dbfi.itmCobExpr ); hb_cdxIndexLockRead( pTag->pIndex ); + hb_cdxTagRefreshScope( pTag ); if ( pTag->topScopeKey || pTag->bottomScopeKey || pTag->UsrUnique || pArea->dbfi.fFilter ) { hb_cdxTagGoTop( pTag ); - while ( !pTag->TagBOF && !pTag->TagEOF && hb_cdxBottomScope( pTag ) && - --ulKeyCnt ) - hb_cdxTagSkipNext( pTag ); + if ( fCheckFilter ) + while ( !pTag->TagEOF ) + { + if ( hb_cdxCheckRecordFilter( pArea, pTag->CurKey->rec ) ) + { + if ( ! --ulKeyCnt ) + break; + } + hb_cdxTagSkipNext( pTag ); + } + else + while( !pTag->TagEOF && --ulKeyCnt ) + hb_cdxTagSkipNext( pTag ); } else { @@ -5736,18 +5941,351 @@ static ERRCODE hb_cdxDBOIKeyGoto( CDXAREAP pArea, LPCDXTAG pTag, ULONG ulKeyNo, retval = SELF_GOTO( ( AREAP ) pArea, pTag->CurKey->rec ); if ( pArea->fPositioned ) { - pTag->rawKeyPos = ulKeyNo; - CURKEY_SETRAWPOS( pTag ); + if ( !fFilters ) + { + pTag->rawKeyPos = ulKeyNo; + CURKEY_SETRAWPOS( pTag ); + } + else if ( fLogOpt ) + { + pTag->logKeyPos = ulKeyNo; + CURKEY_SETLOGPOS( pTag ); + } } } else { - retval = SELF_GOTO( ( AREAP ) pArea, ulKeyNo ); + if ( fLogOpt && fFilters && pArea->dbfi.itmCobExpr ) + { + SELF_GOTOP( ( AREAP ) pArea ); + retval = SELF_SKIP( ( AREAP ) pArea, ulKeyCnt ); + } + else + { + retval = SELF_GOTO( ( AREAP ) pArea, ulKeyNo ); + } } return retval; } +static double hb_cdxCountRelKeyPos( LPCDXPAGE pPage ) +{ + return ( ( pPage->Child ? hb_cdxCountRelKeyPos( pPage->Child ) : 0.5 ) + + pPage->iCurKey ) / pPage->iKeys; +} + +static BOOL hb_cdxGoToRelKeyPos( LPCDXPAGE pPage, double dPos ) +{ + do + { + if( pPage->iKeys == 0 ) + return FALSE; + + pPage->iCurKey = ( SHORT ) ( dPos * pPage->iKeys ); + if( pPage->iCurKey >= pPage->iKeys ) + pPage->iCurKey = pPage->iKeys - 1; + + if( ( pPage->PageType & CDX_NODE_LEAF ) != 0 ) + break; + + dPos = dPos * pPage->iKeys - pPage->iCurKey; + if( dPos < 0.0 ) + dPos = 0.0; + else if( dPos >= 1.0 ) + dPos = 1.0; + + hb_cdxPageGetChild( pPage ); + pPage = pPage->Child; + } + while( pPage ); + + return TRUE; +} + +static double hb_cdxDBOIGetRelKeyPos( CDXAREAP pArea, LPCDXTAG pTag ) +{ + ULONG ulRecNo = 0, ulRecCount = 0; + double dPos = 0.0; + + /* resolve any pending relations */ + SELF_RECNO( ( AREAP ) pArea, &ulRecNo ); + + if( !pArea->fPositioned ) + { + if( ulRecNo > 1 ) + dPos = 1.0; + } + else if( !pTag ) + { + SELF_RECCOUNT( ( AREAP ) pArea, &ulRecCount ); + if( ulRecCount != 0 ) + dPos = ( 0.5 + ulRecNo ) / ulRecCount; + } + else + { + LPCDXKEY pKey; + double dStart, dStop, dFact = 0.0000000000001; + BOOL fOK = TRUE; + + if( pTag->UsrAscend ) + { + dStart = 0.0; + dStop = 1.0; + } + else + { + dStart = 1.0; + dStop = 0.0; + } + + hb_cdxIndexLockRead( pTag->pIndex ); + hb_cdxTagRefreshScope( pTag ); + + pKey = pTag->UsrAscend ? pTag->topScopeKey : pTag->bottomScopeKey; + if( pKey ) + { + hb_cdxTagKeyFind( pTag, pKey ); + if( pTag->CurKey->rec == 0 || pTag->TagEOF || ! hb_cdxBottomScope( pTag ) ) + fOK = FALSE; + else + dStart = hb_cdxCountRelKeyPos( pTag->RootPage ); + } + pKey = pTag->UsrAscend ? pTag->bottomScopeKey : pTag->topScopeKey; + if( pKey && fOK ) + { + hb_cdxTagKeyFind( pTag, pKey ); + if( pTag->CurKey->rec == 0 || pTag->TagBOF || ! hb_cdxTopScope( pTag ) ) + fOK = FALSE; + else + dStop = hb_cdxCountRelKeyPos( pTag->RootPage ); + } + if( fOK ) + { + if( !pTag->UsrAscend ) + { + double dTmp = dStart; + dStart = dStop; + dStop = dTmp; + } + pTag->fRePos = TRUE; + if( hb_cdxCurKeyRefresh( pArea, pTag ) && + hb_cdxTopScope( pTag ) && hb_cdxBottomScope( pTag ) ) + { + if( dStart >= dStop - dFact ) + dPos = 0.5; + else + { + dPos = hb_cdxCountRelKeyPos( pTag->RootPage ); + dPos = ( dPos - dStart ) / ( dStop - dStart ); + if( !pTag->UsrAscend ) + dPos = 1.0 - dPos; + /* fix possible differences in FL representation */ + if( dPos <= 0.0 ) + dPos = 0.0; + else if( dPos >= 1.0 ) + dPos = 1.0; + } + } + } + hb_cdxIndexUnLockRead( pTag->pIndex ); + } + + return dPos; +} + +static void hb_cdxDBOISetRelKeyPos( CDXAREAP pArea, LPCDXTAG pTag, double dPos ) +{ + if( !pTag ) + { + if( dPos >= 1.0 ) + { + SELF_GOBOTTOM( ( AREAP ) pArea ); + } + else if( dPos <= 0.0 ) + { + SELF_GOTOP( ( AREAP ) pArea ); + } + else + { + ULONG ulRecCount, ulRecNo; + SELF_RECCOUNT( ( AREAP ) pArea, &ulRecCount ); + ulRecNo = ( ULONG ) dPos * ulRecCount + 1; + if( ulRecNo >= ulRecCount ) + ulRecNo = ulRecCount; + SELF_GOTO( ( AREAP ) pArea, ulRecNo ); + SELF_SKIPFILTER( ( AREAP ) pArea, 1 ); + if( pArea->fEof ) + SELF_GOTOP( ( AREAP ) pArea ); + } + } + else + { + BOOL fForward = TRUE, fOK = TRUE, fTop = FALSE; + hb_cdxIndexLockRead( pTag->pIndex ); + hb_cdxTagRefreshScope( pTag ); + + if( dPos >= 1.0 ) + { + fForward = FALSE; + } + else if( dPos <= 0.0 ) + { + fTop = TRUE; + } + else + { + LPCDXKEY pKey; + double dStart, dStop, dFact = 0.0000000000001; + BOOL fOK = TRUE; + + if( pTag->UsrAscend ) + { + dStart = 0.0; + dStop = 1.0; + } + else + { + dStart = 1.0; + dStop = 0.0; + } + + pKey = pTag->UsrAscend ? pTag->topScopeKey : pTag->bottomScopeKey; + if( pKey ) + { + hb_cdxTagKeyFind( pTag, pKey ); + if( pTag->CurKey->rec == 0 || pTag->TagEOF || ! hb_cdxBottomScope( pTag ) ) + fOK = FALSE; + else + dStart = hb_cdxCountRelKeyPos( pTag->RootPage ); + } + pKey = pTag->UsrAscend ? pTag->bottomScopeKey : pTag->topScopeKey; + if( pKey && fOK ) + { + hb_cdxTagKeyFind( pTag, pKey ); + if( pTag->CurKey->rec == 0 || pTag->TagBOF || ! hb_cdxTopScope( pTag ) ) + fOK = FALSE; + else + dStop = hb_cdxCountRelKeyPos( pTag->RootPage ); + } + if( fOK ) + { + if( !pTag->UsrAscend ) + { + double dTmp = dStart; + dStart = dStop; + dStop = dTmp; + dPos = 1.0 - dPos; + } + if( dStart >= dStop - dFact ) + { + fTop = TRUE; + } + else + { + dPos = dPos * ( dStop - dStart ) + dStart; + pTag->fRePos = FALSE; + hb_cdxTagOpen( pTag ); + pTag->TagBOF = pTag->TagEOF = FALSE; + if( !hb_cdxGoToRelKeyPos( pTag->RootPage, dPos ) ) + { + fTop = TRUE; + } + else + { + hb_cdxSetCurKey( pTag->RootPage ); + if( !hb_cdxTopScope( pTag ) ) + fTop = TRUE; + else if( !hb_cdxBottomScope( pTag ) ) + fForward = FALSE; + } + } + } + } + if( !fOK ) + { + SELF_GOTO( ( AREAP ) pArea, 0 ); + } + else + { + if( fForward ) + { + if( fTop ) + hb_cdxTagGoTop( pTag ); + while( !pTag->TagEOF ) + { + if ( hb_cdxCheckRecordFilter( pArea, pTag->CurKey->rec ) ) + break; + hb_cdxTagSkipNext( pTag ); + } + if( pTag->TagEOF && !fTop ) + fForward = FALSE; + } + if( !fForward ) + { + hb_cdxTagGoBottom( pTag ); + while( !pTag->TagBOF ) + { + if ( hb_cdxCheckRecordFilter( pArea, pTag->CurKey->rec ) ) + break; + hb_cdxTagSkipPrev( pTag ); + } + if( pTag->TagBOF ) + { + pTag->CurKey->rec = 0; + } + } + SELF_GOTO( ( AREAP ) pArea, pTag->CurKey->rec ); + } + hb_cdxIndexUnLockRead( pTag->pIndex ); + } +} + +/* + * DBOI_FINDREC find a specific record in the tag - it's useful for + * custom indexes when the same record can be stored more then once + * or when the used index key is unknown + */ +static BOOL hb_cdxDBOIFindRec( CDXAREAP pArea, LPCDXTAG pTag, ULONG ulRecNo, BOOL fCont ) +{ + BOOL fFound = FALSE; + + if ( pTag && ulRecNo ) + { + if( pArea->lpdbPendingRel && pArea->lpdbPendingRel->isScoped ) + SELF_FORCEREL( ( AREAP ) pArea ); + + hb_cdxIndexLockRead( pTag->pIndex ); + hb_cdxTagRefreshScope( pTag ); + if ( fCont ) + { + if ( ! hb_cdxCurKeyRefresh( pArea, pTag ) ) + ulRecNo = 0; + else + hb_cdxTagSkipNext( pTag ); + } + else + { + hb_cdxTagGoTop( pTag ); + } + if ( ulRecNo ) + { + while ( !pTag->TagBOF && !pTag->TagEOF && hb_cdxBottomScope( pTag ) ) + { + if ( pTag->CurKey->rec == ulRecNo ) + { + fFound = TRUE; + break; + } + hb_cdxTagSkipNext( pTag ); + } + } + hb_cdxIndexUnLockRead( pTag->pIndex ); + } + SELF_GOTO( ( AREAP ) pArea, fFound ? ulRecNo : 0 ); + return fFound; +} + static void hb_cdxClearLogPosInfo( CDXAREAP pArea ) { LPCDXINDEX pIndex = pArea->lpIndexes; @@ -5792,6 +6330,7 @@ static ERRCODE hb_cdxGoBottom( CDXAREAP pArea ) SELF_FORCEREL( ( AREAP ) pArea ); hb_cdxIndexLockRead( pTag->pIndex ); + hb_cdxTagRefreshScope( pTag ); hb_cdxTagGoBottom( pTag ); @@ -5804,7 +6343,7 @@ static ERRCODE hb_cdxGoBottom( CDXAREAP pArea ) { retval = SELF_SKIPFILTER( ( AREAP ) pArea, -1 ); - if ( CURKEY_LOGCNT( pTag ) && pArea->fPositioned ) + if ( pArea->fPositioned && CURKEY_LOGCNT( pTag ) ) { pTag->logKeyPos = pTag->logKeyCount; CURKEY_SETLOGPOS( pTag ); @@ -5837,6 +6376,7 @@ static ERRCODE hb_cdxGoTop( CDXAREAP pArea ) SELF_FORCEREL( ( AREAP ) pArea ); hb_cdxIndexLockRead( pTag->pIndex ); + hb_cdxTagRefreshScope( pTag ); hb_cdxTagGoTop( pTag ); @@ -5848,8 +6388,11 @@ static ERRCODE hb_cdxGoTop( CDXAREAP pArea ) if ( retval != FAILURE && pArea->fPositioned ) retval = SELF_SKIPFILTER( ( AREAP ) pArea, 1 ); - pTag->logKeyPos = 1; - CURKEY_SETLOGPOS( pTag ); + if ( retval != FAILURE && pArea->fPositioned ) + { + pTag->logKeyPos = 1; + CURKEY_SETLOGPOS( pTag ); + } hb_cdxIndexUnLockRead( pTag->pIndex ); return retval; @@ -5894,6 +6437,7 @@ static ERRCODE hb_cdxSeek( CDXAREAP pArea, BOOL fSoftSeek, PHB_ITEM pKeyItm, BOO pKey = hb_cdxKeyPutItem( NULL, pKeyItm, fLast ? CDX_MAX_REC_NUM : CDX_IGNORE_REC_NUM, pTag, TRUE, FALSE ); hb_cdxIndexLockRead( pTag->pIndex ); + hb_cdxTagRefreshScope( pTag ); ulRec = hb_cdxTagKeyFind( pTag, pKey ); if ( ( ulRec == 0 && ! fSoftSeek ) || pTag->TagEOF ) fEOF = TRUE; @@ -5946,7 +6490,7 @@ static ERRCODE hb_cdxSkip( CDXAREAP pArea, LONG lToSkip ) HB_TRACE(HB_TR_DEBUG, ("hb_cdxSkip(%p, %ld)", pArea, lToSkip)); pTag = lToSkip == 0 ? NULL : hb_cdxGetActiveTag( pArea ); - ulPos = ( pTag && CURKEY_LOGPOS( pTag ) ) ? pTag->logKeyPos : 0; + ulPos = ( pTag && pArea->fPositioned && CURKEY_LOGPOS( pTag ) ) ? pTag->logKeyPos : 0; if ( SUPER_SKIP( ( AREAP ) pArea, lToSkip ) == FAILURE ) return FAILURE; @@ -5971,8 +6515,11 @@ static ERRCODE hb_cdxSkip( CDXAREAP pArea, LONG lToSkip ) } else if ( pArea->fBof ) { - pTag->logKeyPos = 1; - CURKEY_SETLOGPOS( pTag ); + if ( pArea->fPositioned ) + { + pTag->logKeyPos = 1; + CURKEY_SETLOGPOS( pTag ); + } } else if ( ulPos ) { @@ -6008,6 +6555,7 @@ static ERRCODE hb_cdxSkipRaw( CDXAREAP pArea, LONG lToSkip ) fForward = ( lToSkip > 0 ); hb_cdxIndexLockRead( pTag->pIndex ); + hb_cdxTagRefreshScope( pTag ); if ( ! hb_cdxCurKeyRefresh( pArea, pTag ) ) { if ( fForward ) @@ -6062,6 +6610,13 @@ static ERRCODE hb_cdxSkipRaw( CDXAREAP pArea, LONG lToSkip ) pArea->fBof = fOut; } hb_cdxIndexUnLockRead( pTag->pIndex ); + /* Update Bof and Eof flags */ + /* + if( fForward ) + pArea->fBof = FALSE; + else + pArea->fEof = FALSE; + */ return retval; } @@ -6131,6 +6686,7 @@ static ERRCODE hb_cdxGoCold( CDXAREAP pArea ) LPCDXTAG pTag = pArea->lpIndexes->TagList; LPCDXKEY pKey = NULL; BOOL fAdd, fDel, fLck = FALSE; + LPDBRELINFO lpdbPendingRel; if ( pArea->fShared ) { @@ -6147,6 +6703,12 @@ static ERRCODE hb_cdxGoCold( CDXAREAP pArea ) pArea->fCdxAppend = FALSE; } } + + /* The pending relation may move the record pointer so we should + disable them for KEY/FOR evaluation */ + lpdbPendingRel = pArea->lpdbPendingRel; + pArea->lpdbPendingRel = NULL; + /* TODO: * There is possible race condition here but not very dangerous. * To avoid it we should Lock all index file before SUPER_GOCOLD @@ -6162,7 +6724,8 @@ static ERRCODE hb_cdxGoCold( CDXAREAP pArea ) { if ( !pTag->Custom ) { - pKey = hb_cdxKeyEval( pKey, pTag, TRUE ); + pKey = hb_cdxKeyEval( pKey, pTag ); + if ( pTag->pForItem != NULL ) fAdd = hb_cdxEvalCond ( pArea, pTag->pForItem, TRUE ); else @@ -6218,8 +6781,12 @@ static ERRCODE hb_cdxGoCold( CDXAREAP pArea ) pTag = NULL; } } + if ( pKey ) hb_cdxKeyFree( pKey ); + + /* Restore disabled pending relation */ + pArea->lpdbPendingRel = lpdbPendingRel; } return SUCCESS; @@ -6247,7 +6814,7 @@ static ERRCODE hb_cdxGoHot( CDXAREAP pArea ) { if ( !pTag->Custom ) { - pTag->HotKey = hb_cdxKeyEval( pTag->HotKey, pTag, TRUE ); + pTag->HotKey = hb_cdxKeyEval( pTag->HotKey, pTag ); pTag->HotFor = pTag->pForItem == NULL || hb_cdxEvalCond( pArea, pTag->pForItem, TRUE ); } @@ -6270,7 +6837,8 @@ static ERRCODE hb_cdxGoHot( CDXAREAP pArea ) /* ( DBENTRYP_V ) hb_cdxRecall : NULL */ /* ( DBENTRYP_ULP ) hb_cdxRecCount : NULL */ /* ( DBENTRYP_ISI ) hb_cdxRecInfo : NULL */ -/* ( DBENTRYP_I ) hb_cdxRecNo : NULL */ +/* ( DBENTRYP_ULP ) hb_cdxRecNo : NULL */ +/* ( DBENTRYP_I ) hb_cdxRecId : NULL */ /* ( DBENTRYP_S ) hb_cdxSetFieldExtent : NULL */ /* ( DBENTRYP_P ) hb_cdxAlias : NULL */ @@ -6280,47 +6848,54 @@ static ERRCODE hb_cdxGoHot( CDXAREAP pArea ) */ static ERRCODE hb_cdxClose( CDXAREAP pArea ) { + ERRCODE errCode; + HB_TRACE(HB_TR_DEBUG, ("hb_cdxClose(%p)", pArea)); - if ( FAST_GOCOLD( ( AREAP ) pArea ) == FAILURE ) + if ( SELF_GOCOLD( ( AREAP ) pArea ) == FAILURE ) return FAILURE; - if ( pArea->pSort ) - { - hb_cdxSortFree( pArea->pSort ); - pArea->pSort = NULL; - } + errCode = SUPER_CLOSE( ( AREAP ) pArea ); - hb_cdxOrdListClear( pArea, TRUE, NULL ); - if ( pArea->bCdxSortTab ) + if( errCode == SUCCESS ) { - hb_xfree( pArea->bCdxSortTab ); - pArea->bCdxSortTab = NULL; - } + if ( pArea->pSort ) + { + hb_cdxSortFree( pArea->pSort ); + pArea->pSort = NULL; + } + + hb_cdxOrdListClear( pArea, TRUE, NULL ); + if ( pArea->bCdxSortTab ) + { + hb_xfree( pArea->bCdxSortTab ); + pArea->bCdxSortTab = NULL; + } #ifdef HB_CDX_DBGTIME - printf( "\r\ncdxTimeIntBld=%f, cdxTimeExtBld=%f, cdxTimeBld=%f\r\n" - "cdxTimeGetKey=%f, cdxTimeFreeKey=%f\r\n" - "cdxTimeExtBlc=%f, cdxTimeIntBlc=%f\r\n" - "cdxTimeIdxBld=%f\r\n" - "cdxTimeTotal=%f\r\n", - (double) cdxTimeIntBld / 1000000, (double) cdxTimeExtBld / 1000000, - (double) ( cdxTimeIntBld + cdxTimeExtBld ) / 1000000, - (double) cdxTimeGetKey / 1000000, (double) cdxTimeFreeKey / 1000000, - (double) cdxTimeIntBlc / 1000000, (double) cdxTimeExtBlc / 1000000, - (double) cdxTimeIdxBld / 1000000, - (double) ( cdxTimeIntBld + cdxTimeExtBld + cdxTimeIdxBld + - cdxTimeGetKey + cdxTimeFreeKey + - cdxTimeExtBlc + cdxTimeIntBlc ) / 1000000 ); - fflush(stdout); - cdxTimeIntBld = cdxTimeExtBld = 0; + printf( "\r\ncdxTimeIntBld=%f, cdxTimeExtBld=%f, cdxTimeBld=%f\r\n" + "cdxTimeGetKey=%f, cdxTimeFreeKey=%f\r\n" + "cdxTimeExtBlc=%f, cdxTimeIntBlc=%f\r\n" + "cdxTimeIdxBld=%f\r\n" + "cdxTimeTotal=%f\r\n", + (double) cdxTimeIntBld / 1000000, (double) cdxTimeExtBld / 1000000, + (double) ( cdxTimeIntBld + cdxTimeExtBld ) / 1000000, + (double) cdxTimeGetKey / 1000000, (double) cdxTimeFreeKey / 1000000, + (double) cdxTimeIntBlc / 1000000, (double) cdxTimeExtBlc / 1000000, + (double) cdxTimeIdxBld / 1000000, + (double) ( cdxTimeIntBld + cdxTimeExtBld + cdxTimeIdxBld + + cdxTimeGetKey + cdxTimeFreeKey + + cdxTimeExtBlc + cdxTimeIntBlc ) / 1000000 ); + fflush(stdout); + cdxTimeIntBld = cdxTimeExtBld = 0; #endif #ifdef HB_CDX_DBGUPDT - printf( "\r\n#reads=%ld, #writes=%ld, stacksize=%d\r\n", cdxReadNO, cdxWriteNO, cdxStackSize ); - fflush(stdout); - cdxReadNO = cdxWriteNO = 0; + printf( "\r\n#reads=%ld, #writes=%ld, stacksize=%d\r\n", cdxReadNO, cdxWriteNO, cdxStackSize ); + fflush(stdout); + cdxReadNO = cdxWriteNO = 0; #endif + } - return SUPER_CLOSE( ( AREAP ) pArea ); + return errCode; } /* ( DBENTRYP_VP ) hb_cdxCreate : NULL */ @@ -6333,14 +6908,24 @@ static ERRCODE hb_cdxClose( CDXAREAP pArea ) */ static ERRCODE hb_cdxOpen( CDXAREAP pArea, LPDBOPENINFO pOpenInfo ) { + ERRCODE errCode = SUCCESS; + HB_TRACE(HB_TR_DEBUG, ("hb_cdxOpen(%p, %p)", pArea, pOpenInfo)); if ( !pArea->bLockType ) { - if ( hb_set.HB_SET_DBFLOCKSCHEME ) - pArea->bLockType = hb_set.HB_SET_DBFLOCKSCHEME; - else - pArea->bLockType = HB_SET_DBFLOCK_VFP; + PHB_ITEM pItem = hb_itemNew( NULL ); + if( SELF_INFO( ( AREAP ) pArea, DBI_LOCKSCHEME, pItem ) != SUCCESS ) + { + hb_itemRelease( pItem ); + return FAILURE; + } + pArea->bLockType = hb_itemGetNI( pItem ); + hb_itemRelease( pItem ); + if( pArea->bLockType == 0 ) + { + pArea->bLockType = DB_DBFLOCK_VFP; + } } if ( SUPER_OPEN( ( AREAP ) pArea, pOpenInfo ) == FAILURE ) { @@ -6354,24 +6939,28 @@ static ERRCODE hb_cdxOpen( CDXAREAP pArea, LPDBOPENINFO pOpenInfo ) if ( pArea->fHasTags && hb_set.HB_SET_AUTOPEN ) #endif { - char szFileName[ _POSIX_PATH_MAX + 1 ], szSpFile[ _POSIX_PATH_MAX + 1 ]; - DBORDERINFO pOrderInfo; + char szFileName[ _POSIX_PATH_MAX + 1 ]; hb_cdxCreateFName( pArea, NULL, szFileName, NULL ); - - if ( hb_spFile( ( BYTE * ) szFileName, ( BYTE * ) szSpFile ) ) + if ( hb_spFile( ( BYTE * ) szFileName, NULL ) ) { - pOrderInfo.itmResult = hb_itemPutNI( NULL, 0 ); - pOrderInfo.atomBagName = hb_itemPutC( NULL, szSpFile ); - pOrderInfo.itmOrder = NULL; - SELF_ORDLSTADD( ( AREAP ) pArea, &pOrderInfo ); - pOrderInfo.itmOrder = hb_itemPutNI( NULL, hb_set.HB_SET_AUTORDER ); - SELF_ORDLSTFOCUS( ( AREAP ) pArea, &pOrderInfo ); - hb_itemRelease( pOrderInfo.atomBagName ); - hb_itemRelease( pOrderInfo.itmOrder ); - hb_itemRelease( pOrderInfo.itmResult ); + DBORDERINFO pOrderInfo; - SELF_GOTOP( ( AREAP ) pArea ); + pOrderInfo.itmResult = hb_itemPutNI( NULL, 0 ); + pOrderInfo.atomBagName = hb_itemPutC( NULL, szFileName ); + pOrderInfo.itmNewVal = NULL; + pOrderInfo.itmOrder = NULL; + errCode = SELF_ORDLSTADD( ( AREAP ) pArea, &pOrderInfo ); + if( errCode == SUCCESS ) + { + pOrderInfo.itmOrder = hb_itemPutNI( NULL, hb_set.HB_SET_AUTORDER ); + errCode = SELF_ORDLSTFOCUS( ( AREAP ) pArea, &pOrderInfo ); + hb_itemRelease( pOrderInfo.itmOrder ); + if( errCode == SUCCESS ) + errCode = SELF_GOTOP( ( AREAP ) pArea ); + } + hb_itemRelease( pOrderInfo.atomBagName ); + hb_itemRelease( pOrderInfo.itmResult ); } else { @@ -6383,7 +6972,7 @@ static ERRCODE hb_cdxOpen( CDXAREAP pArea, LPDBOPENINFO pOpenInfo ) pArea->fHasTags = FALSE; } - return SUCCESS; + return errCode; } /* ( DBENTRYP_V ) hb_cdxRelease : NULL */ @@ -6410,7 +6999,11 @@ static ERRCODE hb_cdxSysName( CDXAREAP pArea, BYTE * pBuffer ) HB_TRACE(HB_TR_DEBUG, ("hb_cdxSysName(%p, %p)", pArea, pBuffer)); HB_SYMBOL_UNUSED( pArea ); +#if defined( HB_SIXCDX ) + strncpy( ( char * ) pBuffer, "SIXCDX", 7 /* HARBOUR_MAX_RDD_DRIVERNAME_LENGTH */ ); +#else strncpy( ( char * ) pBuffer, "DBFCDX", 7 /* HARBOUR_MAX_RDD_DRIVERNAME_LENGTH */ ); +#endif return SUCCESS; } @@ -6469,9 +7062,9 @@ static ERRCODE hb_cdxOrderListAdd( CDXAREAP pArea, LPDBORDERINFO pOrderInfo ) { USHORT uiFlags; FHANDLE hFile; - char szBaseName[ CDX_MAXTAGNAMELEN ]; - char szSpFile[ _POSIX_PATH_MAX + 1 ], szFileName[ _POSIX_PATH_MAX + 1 ]; - LPCDXINDEX pIndex, pIndexTmp; + char szBaseName[ CDX_MAXTAGNAMELEN + 1 ]; + char szFileName[ _POSIX_PATH_MAX + 1 ]; + LPCDXINDEX pIndex, * pIndexPtr; BOOL bRetry; HB_TRACE(HB_TR_DEBUG, ("hb_cdxOrderListAdd(%p, %p)", pArea, pOrderInfo)); @@ -6485,49 +7078,40 @@ static ERRCODE hb_cdxOrderListAdd( CDXAREAP pArea, LPDBORDERINFO pOrderInfo ) hb_cdxCreateFName( pArea, hb_itemGetCPtr( pOrderInfo->atomBagName ), szFileName, szBaseName ); - if ( strlen( szBaseName ) == 0 ) + if ( ! szBaseName[0] ) return FAILURE; - if ( pArea->lpIndexes != NULL ) + pIndex = hb_cdxFindBag( pArea, szFileName ); + + if ( pIndex ) { - pIndexTmp = pArea->lpIndexes; - while ( pIndexTmp && ( hb_stricmp( szBaseName, pIndexTmp->pCompound->szName ) != 0 ) ) - pIndexTmp = pIndexTmp->pNext; - if ( pIndexTmp ) + /* index already open, do nothing */ + if ( ! pArea->uiTag ) { - /* - * index already open, do nothing - * TODO: the full pathname should be compared when APIs are available - * ??? I'm not sure, it breaks upper lewel API if we have - * two Bags with the same name. But we can close the old bag - * and open the new one - 10/05/2003 Druzus - */ - if ( ! pArea->uiTag ) - { - pArea->uiTag = hb_cdxGetTagNumber( pArea, pIndexTmp->TagList ); - SELF_GOTOP( ( AREAP ) pArea ); - } - return FAILURE; + pArea->uiTag = hb_cdxGetTagNumber( pArea, pIndex->TagList ); + SELF_GOTOP( ( AREAP ) pArea ); } + return SUCCESS; } uiFlags = ( pArea->fReadonly ? FO_READ : FO_READWRITE ) | ( pArea->fShared ? FO_DENYNONE : FO_EXCLUSIVE ); do { - hb_spFile( ( BYTE * ) szFileName, ( BYTE * ) szSpFile ); - hFile = hb_spOpen( ( BYTE * ) szSpFile , uiFlags ); - if ( hFile == FS_ERROR ) - bRetry = ( hb_cdxErrorRT( pArea, EG_OPEN, 1003, szSpFile, + hFile = hb_fsExtOpen( ( BYTE * ) szFileName, NULL, uiFlags | + FXO_DEFAULTS | FXO_SHARELOCK | FXO_COPYNAME, + NULL, NULL ); + if( hFile == FS_ERROR ) + bRetry = ( hb_cdxErrorRT( pArea, EG_OPEN, EDBF_OPEN_INDEX, szFileName, hb_fsError(), EF_CANRETRY | EF_CANDEFAULT ) == E_RETRY ); else { - if ( hb_fsSeek( hFile, 0, FS_END ) <= sizeof( CDXTAGHEADER ) ) + if( hb_fsSeekLarge( hFile, 0, FS_END ) <= ( HB_FOFFSET ) sizeof( CDXTAGHEADER ) ) { hb_fsClose( hFile ); hFile = FS_ERROR; hb_cdxErrorRT( pArea, EG_CORRUPTION, EDBF_CORRUPT, - szSpFile, hb_fsError(), EF_CANDEFAULT ); + szFileName, hb_fsError(), EF_CANDEFAULT ); } bRetry = FALSE; } @@ -6543,22 +7127,22 @@ static ERRCODE hb_cdxOrderListAdd( CDXAREAP pArea, LPDBORDERINFO pOrderInfo ) pIndex->hFile = hFile; pIndex->fShared = pArea->fShared; pIndex->fReadonly = pArea->fReadonly; - pIndex->szFileName = hb_strdup( szSpFile ); + pIndex->szFileName = hb_strdup( szFileName ); - if ( pArea->lpIndexes == NULL ) - { - pArea->lpIndexes = pIndex; - } - else - { - pIndexTmp = pArea->lpIndexes; - while ( pIndexTmp->pNext ) - pIndexTmp = pIndexTmp->pNext; - pIndexTmp->pNext = pIndex; - } + pIndexPtr = &pArea->lpIndexes; + while ( *pIndexPtr != NULL ) + pIndexPtr = &( *pIndexPtr )->pNext; + *pIndexPtr = pIndex; - /* TODO: check if index file is not corrupted */ - hb_cdxIndexLoad( pIndex, szBaseName ); + if ( ! hb_cdxIndexLoad( pIndex, szBaseName ) ) + { + /* index file is corrupted */ + *pIndexPtr = NULL; + hb_cdxIndexFree( pIndex ); + hb_cdxErrorRT( pArea, EG_CORRUPTION, EDBF_CORRUPT, + szFileName, hb_fsError(), EF_CANDEFAULT ); + return FAILURE; + } /* dbfcdx specific: If there was no controlling order, set this one. * This is the behaviour of Clipper's dbfcdx, although @@ -6583,14 +7167,18 @@ static ERRCODE hb_cdxOrderListClear( CDXAREAP pArea ) if ( FAST_GOCOLD( ( AREAP ) pArea ) == FAILURE ) return FAILURE; - hb_cdxOrdListClear( pArea, FALSE, NULL ); +#ifdef HB_CDX_CLIP_AUTOPEN + hb_cdxOrdListClear( pArea, !hb_set.HB_SET_AUTOPEN, NULL ); +#else + hb_cdxOrdListClear( pArea, !pArea->fHasTags || !hb_set.HB_SET_AUTOPEN, NULL ); +#endif pArea->uiTag = 0; return SUCCESS; } /* TODO: in the future, now there is no API call to SELF_ORDLSTDELETE */ -/* ( DBENTRYP_VP ) hb_cdxOrderListDelete : NULL */ +/* ( DBENTRYP_OI ) hb_cdxOrderListDelete : NULL */ /* ( DBENTRYP_OI ) hb_cdxOrderListFocus */ static ERRCODE hb_cdxOrderListFocus( CDXAREAP pArea, LPDBORDERINFO pOrderInfo ) @@ -6610,8 +7198,10 @@ static ERRCODE hb_cdxOrderListFocus( CDXAREAP pArea, LPDBORDERINFO pOrderInfo ) pOrderInfo->itmResult = hb_itemPutC( pOrderInfo->itmResult, pTag->szName ); if ( pOrderInfo->itmOrder ) + { hb_cdxFindTag( pArea, pOrderInfo->itmOrder, pOrderInfo->atomBagName, &(pArea->uiTag) ); /* TODO: RTerror if not found? */ + } return SUCCESS; } @@ -6672,24 +7262,25 @@ static ERRCODE hb_cdxOrderListRebuild( CDXAREAP pArea ) static ERRCODE hb_cdxOrderCreate( CDXAREAP pArea, LPDBORDERCREATEINFO pOrderInfo ) { ULONG ulRecNo; - BOOL fNewFile, fOpenedIndex; - PHB_ITEM pKeyExp, pForExp, pResult; - HB_MACRO_PTR pExpMacro, pForMacro; + BOOL fNewFile, fOpenedIndex, fProd = FALSE, fAscend = TRUE, fCustom = FALSE, + fTemporary = FALSE, fExclusive = FALSE; + PHB_ITEM pKeyExp, pForExp = NULL, pResult; char szCpndTagName[ CDX_MAXTAGNAMELEN + 1 ], szTagName[ CDX_MAXTAGNAMELEN + 1 ]; - char szFileName[ _POSIX_PATH_MAX + 1 ], szSpFile[ _POSIX_PATH_MAX + 1 ]; + char szFileName[ _POSIX_PATH_MAX + 1 ], szTempFile[ _POSIX_PATH_MAX + 1 ]; + char *szFor = NULL; LPCDXINDEX pIndex; LPCDXTAG pTag; - USHORT uiType, uiLen; + USHORT uiLen; BYTE bType; - pForExp = NULL; - pExpMacro = pForMacro = NULL; - HB_TRACE(HB_TR_DEBUG, ("hb_cdxOrderCreate(%p, %p)", pArea, pOrderInfo)); if ( FAST_GOCOLD( ( AREAP ) pArea ) == FAILURE ) return FAILURE; + if( pArea->lpdbPendingRel ) + SELF_FORCEREL( ( AREAP ) pArea ); + /* If we have a codeblock for the expression, use it */ if ( pOrderInfo->itmCobExpr ) pKeyExp = hb_itemNew( pOrderInfo->itmCobExpr ); @@ -6704,124 +7295,94 @@ static ERRCODE hb_cdxOrderCreate( CDXAREAP pArea, LPDBORDERCREATEINFO pOrderInfo /* Get a blank record before testing expression */ ulRecNo = pArea->ulRecNo; SELF_GOTO( ( AREAP ) pArea, 0 ); - if ( hb_itemType( pKeyExp ) == HB_IT_BLOCK ) + if ( SELF_EVALBLOCK( ( AREAP ) pArea, pKeyExp ) == FAILURE ) { - if ( SELF_EVALBLOCK( ( AREAP ) pArea, pKeyExp ) == FAILURE ) - { - hb_itemRelease( pKeyExp ); - SELF_GOTO( ( AREAP ) pArea, ulRecNo ); - return FAILURE; - } - pResult = pArea->valResult; - pArea->valResult = NULL; - } - else - { - pExpMacro = ( HB_MACRO_PTR ) hb_itemGetPtr( pKeyExp ); - hb_cdxMacroRun( pArea, pExpMacro ); - pResult = hb_itemNew( hb_stackItemFromTop( -1 ) ); - } - uiType = hb_itemType( pResult ); - switch ( uiType ) - { - case HB_IT_INTEGER: - case HB_IT_LONG: - case HB_IT_DOUBLE: - bType = 'N'; - uiLen = 8; - break; - case HB_IT_DATE: - bType = 'D'; - uiLen = 8; - break; - case HB_IT_LOGICAL: - bType = 'L'; - uiLen = 1; - break; - case HB_IT_STRING: - bType = 'C'; - uiLen = HB_CDXMAXKEY( pResult->item.asString.length ); - break; - default: - hb_itemRelease( pKeyExp ); - if ( pExpMacro != NULL ) - hb_macroDelete( pExpMacro ); - SELF_GOTO( ( AREAP ) pArea, ulRecNo ); - hb_cdxErrorRT( pArea, EG_DATATYPE, 1026, NULL, 0, 0 ); - /* TODO: !!! runtime error ? */ - hb_itemRelease( pResult ); - return FAILURE; - } - hb_itemRelease( pResult ); - if ( uiLen == 0 ) - { - hb_itemRelease( pKeyExp ); - if ( pExpMacro != NULL ) - hb_macroDelete( pExpMacro ); + hb_cdxDestroyExp( pKeyExp ); SELF_GOTO( ( AREAP ) pArea, ulRecNo ); - hb_cdxErrorRT( pArea, EG_DATAWIDTH, 1026, NULL, 0, 0 ); return FAILURE; } - /* Check conditional expression */ + pResult = pArea->valResult; + pArea->valResult = NULL; + + bType = hb_cdxItemType( pResult ); + switch ( bType ) + { + case 'N': + case 'D': + uiLen = 8; + break; + case 'L': + uiLen = 1; + break; + case 'C': + uiLen = HB_CDXMAXKEY( hb_itemGetCLen( pResult ) ); + break; + default: + bType = 'U'; + uiLen = 0; + } + hb_itemRelease( pResult ); + + if ( bType == 'U' || uiLen == 0 ) + { + hb_cdxDestroyExp( pKeyExp ); + SELF_GOTO( ( AREAP ) pArea, ulRecNo ); + hb_cdxErrorRT( pArea, bType == 'U' ? EG_DATATYPE : EG_DATAWIDTH, + 1026, NULL, 0, 0 ); + return FAILURE; + } if ( pArea->lpdbOrdCondInfo ) { - /* If we have a codeblock for the conditional expression, use it */ + fAscend = !pArea->lpdbOrdCondInfo->fDescending; + fCustom = pArea->lpdbOrdCondInfo->fCustom; + fTemporary = pArea->lpdbOrdCondInfo->fTemporary; + fExclusive = pArea->lpdbOrdCondInfo->fExclusive; + + /* Check conditional expression */ + szFor = ( char * ) pArea->lpdbOrdCondInfo->abFor; if ( pArea->lpdbOrdCondInfo->itmCobFor ) + /* If we have a codeblock for the conditional expression, use it */ pForExp = hb_itemNew( pArea->lpdbOrdCondInfo->itmCobFor ); - else /* Otherwise, try compiling the conditional expression string */ + else if ( pArea->lpdbOrdCondInfo->abFor ) { - if ( pArea->lpdbOrdCondInfo->abFor ) + /* Otherwise, try compiling the conditional expression string */ + if ( SELF_COMPILE( (AREAP) pArea, pArea->lpdbOrdCondInfo->abFor ) == FAILURE ) { - if ( SELF_COMPILE( (AREAP) pArea, pArea->lpdbOrdCondInfo->abFor ) == FAILURE ) - { - hb_itemRelease( pKeyExp ); - if ( pExpMacro != NULL ) - hb_macroDelete( pExpMacro ); - SELF_GOTO( ( AREAP ) pArea, ulRecNo ); - return FAILURE; - } - pForExp = pArea->valResult; - pArea->valResult = NULL; + hb_cdxDestroyExp( pKeyExp ); + SELF_GOTO( ( AREAP ) pArea, ulRecNo ); + return FAILURE; } + pForExp = pArea->valResult; + pArea->valResult = NULL; } } /* Test conditional expression */ if ( pForExp ) { - if ( hb_itemType( pForExp ) == HB_IT_BLOCK ) + USHORT uiType; + + if ( SELF_EVALBLOCK( ( AREAP ) pArea, pForExp ) == FAILURE ) { - if ( SELF_EVALBLOCK( ( AREAP ) pArea, pForExp ) == FAILURE ) - { - hb_itemRelease( pKeyExp ); - hb_itemRelease( pForExp ); - if ( pExpMacro != NULL ) - hb_macroDelete( pExpMacro ); - SELF_GOTO( ( AREAP ) pArea, ulRecNo ); - return FAILURE; - } - uiType = hb_itemType( pArea->valResult ); - hb_itemRelease( pArea->valResult ); - pArea->valResult = NULL; - } - else - { - pForMacro = ( HB_MACRO_PTR ) hb_itemGetPtr( pForExp ); - hb_cdxMacroRun( pArea, pForMacro ); - uiType = hb_itemType( hb_stackItemFromTop( -1 ) ); + hb_cdxDestroyExp( pKeyExp ); + hb_cdxDestroyExp( pForExp ); + SELF_GOTO( ( AREAP ) pArea, ulRecNo ); + return FAILURE; } + uiType = hb_itemType( pArea->valResult ); + hb_itemRelease( pArea->valResult ); + pArea->valResult = NULL; if ( uiType != HB_IT_LOGICAL ) { - hb_itemRelease( pKeyExp ); - hb_itemRelease( pForExp ); - if ( pExpMacro != NULL ) - hb_macroDelete( pExpMacro ); - if ( pForMacro != NULL ) - hb_macroDelete( pForMacro ); + hb_cdxDestroyExp( pKeyExp ); + hb_cdxDestroyExp( pForExp ); SELF_GOTO( ( AREAP ) pArea, ulRecNo ); /* TODO: !!! runtime error ? */ return FAILURE; } } + + SELF_GOTO( ( AREAP ) pArea, ulRecNo ); + /* * abBagName -> cBag, atomBagName -> cTag * The following scheme implemented: @@ -6833,7 +7394,7 @@ static ERRCODE hb_cdxOrderCreate( CDXAREAP pArea, LPDBORDERCREATEINFO pOrderInfo hb_cdxCreateFName( pArea, ( char * ) pOrderInfo->abBagName, szFileName, szCpndTagName ); - if ( pOrderInfo->atomBagName && strlen( ( char * ) pOrderInfo->atomBagName ) > 0 ) + if ( pOrderInfo->atomBagName && pOrderInfo->atomBagName[0] ) { hb_strncpyUpperTrim( szTagName, ( char * ) pOrderInfo->atomBagName, CDX_MAXTAGNAMELEN ); fNewFile = FALSE; @@ -6846,7 +7407,11 @@ static ERRCODE hb_cdxOrderCreate( CDXAREAP pArea, LPDBORDERCREATEINFO pOrderInfo if ( !pArea->lpdbOrdCondInfo || ( pArea->lpdbOrdCondInfo->fAll && !pArea->lpdbOrdCondInfo->fAdditive ) ) - hb_cdxOrdListClear( pArea, FALSE, NULL ); +#ifdef HB_CDX_CLIP_AUTOPEN + hb_cdxOrdListClear( pArea, !hb_set.HB_SET_AUTOPEN, NULL ); +#else + hb_cdxOrdListClear( pArea, !pArea->fHasTags || !hb_set.HB_SET_AUTOPEN, NULL ); +#endif pIndex = hb_cdxFindBag( pArea, szFileName ); @@ -6870,59 +7435,72 @@ static ERRCODE hb_cdxOrderCreate( CDXAREAP pArea, LPDBORDERCREATEINFO pOrderInfo if ( !fOpenedIndex ) { FHANDLE hFile; - BOOL bRetry; + BOOL bRetry, fShared = pArea->fShared && !fTemporary && !fExclusive; do { - if ( ! hb_spFile( ( BYTE * ) szFileName, ( BYTE * ) szSpFile ) ) + if( fTemporary ) { + hFile = hb_fsCreateTemp( NULL, NULL, FC_NORMAL, ( BYTE * ) szTempFile ); fNewFile = TRUE; } - - if ( fNewFile ) - { - hFile = hb_spCreate( ( BYTE * ) szSpFile, FC_NORMAL ); - } else { - hFile = hb_spOpen( ( BYTE * ) szSpFile, - FO_READWRITE | ( pArea->fShared ? FO_DENYNONE : FO_EXCLUSIVE ) ); + hFile = hb_fsExtOpen( ( BYTE * ) szFileName, NULL, FO_READWRITE | + ( fShared ? FO_DENYNONE : FO_EXCLUSIVE ) | + ( fNewFile ? FXO_TRUNCATE : FXO_APPEND ) | + FXO_DEFAULTS | FXO_SHARELOCK | FXO_COPYNAME, + NULL, NULL ); } - if ( hFile == FS_ERROR ) - bRetry = ( hb_cdxErrorRT( pArea, EG_CREATE, EDBF_CREATE, szSpFile, + if( hFile == FS_ERROR ) + bRetry = ( hb_cdxErrorRT( pArea, EG_CREATE, EDBF_CREATE, szFileName, hb_fsError(), EF_CANRETRY | EF_CANDEFAULT ) == E_RETRY ); else + { bRetry = FALSE; + if ( !fNewFile ) + fNewFile = ( hb_fsSeekLarge( hFile, 0, FS_END ) == 0 ); + } } while ( bRetry ); + if ( hFile != FS_ERROR ) + { + pIndex = hb_cdxIndexNew( pArea ); + pIndex->hFile = hFile; + pIndex->fShared = fShared; + pIndex->fReadonly = FALSE; + pIndex->szFileName = hb_strdup( szFileName ); + pIndex->fDelete = fTemporary; + if( fTemporary ) + pIndex->szRealName = hb_strdup( szTempFile ); + + if ( !fNewFile ) + { + /* index file is corrupted? */ + if ( ! hb_cdxIndexLoad( pIndex, szCpndTagName ) ) + { + /* TODO: What should be default? */ + /* + hb_cdxIndexFree( pIndex ); + hb_fsClose( hFile ); + hFile = FS_ERROR; + hb_cdxErrorRT( pArea, EG_CORRUPTION, EDBF_CORRUPT, + szFileName, hb_fsError(), EF_CANDEFAULT ); + */ + hb_cdxIndexFreeTags( pIndex ); + fNewFile = TRUE; + } + } + } + if ( hFile == FS_ERROR ) { - hb_itemRelease( pKeyExp ); + hb_cdxDestroyExp( pKeyExp ); if ( pForExp != NULL ) - hb_itemRelease( pForExp ); - if ( pExpMacro != NULL ) - hb_macroDelete( pExpMacro ); - if ( pForMacro != NULL ) - hb_macroDelete( pForMacro ); - SELF_GOTO( ( AREAP ) pArea, ulRecNo ); + hb_cdxDestroyExp( pForExp ); return FAILURE; } - - pIndex = hb_cdxIndexNew( pArea ); - pIndex->hFile = hFile; - pIndex->fShared = pArea->fShared; - pIndex->fReadonly = FALSE; - pIndex->szFileName = hb_strdup( szSpFile ); - - if ( !fNewFile ) - { - /* TODO: check if index file is not corrupted */ - /* cut corrupted files */ - fNewFile = ( hb_fsSeek( hFile, 0, FS_END ) <= sizeof( CDXTAGHEADER ) ); - } - if ( !fNewFile ) - hb_cdxIndexLoad( pIndex, szCpndTagName ); } hb_cdxIndexLockWrite( pIndex ); @@ -6942,14 +7520,25 @@ static ERRCODE hb_cdxOrderCreate( CDXAREAP pArea, LPDBORDERCREATEINFO pOrderInfo if ( pIndex->pCompound != NULL ) hb_cdxTagFree( pIndex->pCompound ); pIndex->nextAvail = pIndex->freePage = 0; - pIndex->pCompound = hb_cdxTagNew( pIndex, szCpndTagName, CDX_DUMMYNODE ); - pIndex->pCompound->OptFlags = CDX_TYPE_COMPACT | CDX_TYPE_COMPOUND | CDX_TYPE_STRUCTURE; - hb_cdxTagIndexTagNew( pIndex->pCompound, NULL, NULL, 'C', 10, NULL, NULL, - TRUE, FALSE, FALSE ); + hb_cdxIndexCreateStruct( pIndex, szCpndTagName ); } + pTag = hb_cdxIndexAddTag( pIndex, szTagName, pOrderInfo->abExpr->item.asString.value, + pKeyExp, bType, uiLen, szFor, pForExp, + fAscend , pOrderInfo->fUnique, fCustom, FALSE ); + + if ( pArea->lpdbOrdCondInfo && ( !pArea->lpdbOrdCondInfo->fAll && + !pArea->lpdbOrdCondInfo->fAdditive ) ) + { +#ifdef HB_CDX_CLIP_AUTOPEN + hb_cdxOrdListClear( pArea, !hb_set.HB_SET_AUTOPEN, pIndex ); +#else + hb_cdxOrdListClear( pArea, !pArea->fHasTags || !hb_set.HB_SET_AUTOPEN, pIndex ); +#endif + } + hb_cdxIndexUnLockWrite( pIndex ); /* Update DBF header */ - if ( !pArea->fHasTags ) + if( !pArea->fHasTags && !fOpenedIndex && !pIndex->fDelete ) { PHB_FNAME pFileName; pFileName = hb_fsFNameSplit( pArea->szDataFileName ); @@ -6957,7 +7546,7 @@ static ERRCODE hb_cdxOrderCreate( CDXAREAP pArea, LPDBORDERCREATEINFO pOrderInfo hb_xfree( pFileName ); if ( hb_stricmp( szFileName, szCpndTagName ) == 0 ) { - pArea->fHasTags = TRUE; + pArea->fHasTags = fProd = TRUE; #ifdef HB_CDX_CLIP_AUTOPEN if ( !pArea->fReadonly && hb_set.HB_SET_AUTOPEN ) #else @@ -6966,23 +7555,13 @@ static ERRCODE hb_cdxOrderCreate( CDXAREAP pArea, LPDBORDERCREATEINFO pOrderInfo SELF_WRITEDBHEADER( ( AREAP ) pArea ); } } - - pTag = hb_cdxIndexAddTag( pIndex, szTagName, pOrderInfo->abExpr->item.asString.value, - pKeyExp, bType, uiLen, ( char * ) ( pArea->lpdbOrdCondInfo ? pArea->lpdbOrdCondInfo->abFor : - NULL ), pForExp, - ( pArea->lpdbOrdCondInfo ? !pArea->lpdbOrdCondInfo->fDescending : TRUE ) , pOrderInfo->fUnique, - ( pArea->lpdbOrdCondInfo ? pArea->lpdbOrdCondInfo->fCustom : FALSE ) ); - - if ( pArea->lpdbOrdCondInfo && ( !pArea->lpdbOrdCondInfo->fAll && - !pArea->lpdbOrdCondInfo->fAdditive ) ) - { - hb_cdxOrdListClear( pArea, FALSE, pIndex ); - } - hb_cdxIndexUnLockWrite( pIndex ); if ( !fOpenedIndex ) { - if ( pArea->lpIndexes == NULL ) + if ( fProd || pArea->lpIndexes == NULL ) + { + pIndex->pNext = pArea->lpIndexes; pArea->lpIndexes = pIndex; + } else { LPCDXINDEX pIndexTmp = pArea->lpIndexes; @@ -7005,7 +7584,6 @@ static ERRCODE hb_cdxOrderDestroy( CDXAREAP pArea, LPDBORDERINFO pOrderInfo ) { LPCDXINDEX pIndex, pIndexTmp; LPCDXTAG pTag; - char * szFileName; HB_TRACE(HB_TR_DEBUG, ("hb_cdxOrderDestroy(%p, %p)", pArea, pOrderInfo)); @@ -7054,10 +7632,8 @@ static ERRCODE hb_cdxOrderDestroy( CDXAREAP pArea, LPDBORDERINFO pOrderInfo ) pIndexTmp->pNext = pIndex->pNext; } } - szFileName = hb_strdup( pIndex->szFileName ); + pIndex->fDelete = TRUE; hb_cdxIndexFree( pIndex ); - hb_fsDelete( (BYTE *) szFileName ); - hb_xfree( szFileName ); } } else @@ -7076,30 +7652,122 @@ static ERRCODE hb_cdxOrderDestroy( CDXAREAP pArea, LPDBORDERINFO pOrderInfo ) */ static ERRCODE hb_cdxOrderInfo( CDXAREAP pArea, USHORT uiIndex, LPDBORDERINFO pOrderInfo ) { - LPCDXTAG pTag = NULL; + LPCDXTAG pTag; USHORT uiTag = 0; HB_TRACE(HB_TR_DEBUG, ("hb_cdxOrderInfo(%p, %hu, %p)", pArea, uiIndex, pOrderInfo)); - if ( FAST_GOCOLD( ( AREAP ) pArea ) == FAILURE ) - return FAILURE; - switch( uiIndex ) { - case DBOI_ORDERCOUNT: case DBOI_BAGEXT: + if( pOrderInfo->itmResult ) + hb_itemClear( pOrderInfo->itmResult ); + else + pOrderInfo->itmResult = hb_itemNew( NULL ); + return SELF_RDDINFO( SELF_RDDNODE( pArea ), RDDI_ORDBAGEXT, 0, pOrderInfo->itmResult ); + + case DBOI_EVALSTEP: + pOrderInfo->itmResult = hb_itemPutNL( pOrderInfo->itmResult, + pArea->lpdbOrdCondInfo ? pArea->lpdbOrdCondInfo->lStep : 0 ); + return SUCCESS; + + case DBOI_KEYSINCLUDED: + pOrderInfo->itmResult = hb_itemPutNL( pOrderInfo->itmResult, + pArea->pSort ? pArea->pSort->ulTotKeys : 0 ); + return SUCCESS; + + case DBOI_I_TAGNAME: + pOrderInfo->itmResult = hb_itemPutC( pOrderInfo->itmResult, + pArea->pSort ? pArea->pSort->pTag->szName : NULL ); + return SUCCESS; + + case DBOI_I_BAGNAME: + pOrderInfo->itmResult = hb_itemPutC( pOrderInfo->itmResult, + pArea->pSort ? pArea->pSort->pTag->pIndex->szFileName : NULL ); + return SUCCESS; + + case DBOI_ISREINDEX: + pOrderInfo->itmResult = hb_itemPutL( pOrderInfo->itmResult, + pArea->pSort ? pArea->pSort->fReindex : FALSE ); + return SUCCESS; + case DBOI_LOCKOFFSET: case DBOI_HPLOCKING: - case DBOI_KEYSINCLUDED: - break; - default: - if ( pOrderInfo->itmOrder ) - pTag = hb_cdxFindTag( pArea, pOrderInfo->itmOrder, pOrderInfo->atomBagName, &uiTag ); + { + HB_FOFFSET ulPos, ulPool; + + hb_dbfLockIdxGetData( pArea->bLockType, &ulPos, &ulPool ); + if ( uiIndex == DBOI_LOCKOFFSET ) + pOrderInfo->itmResult = hb_itemPutNInt( pOrderInfo->itmResult, ulPos ); else + pOrderInfo->itmResult = hb_itemPutL( pOrderInfo->itmResult, ulPool > 0 ); + return SUCCESS; + } + + case DBOI_ORDERCOUNT: + { + LPCDXINDEX pIndex; + char *pszBag = hb_itemGetCLen( pOrderInfo->atomBagName ) > 0 ? + hb_itemGetCPtr( pOrderInfo->atomBagName ) : NULL; + pIndex = pszBag ? hb_cdxFindBag( pArea, pszBag ) : pArea->lpIndexes; + while ( pIndex ) { - uiTag = pArea->uiTag; - pTag = hb_cdxGetTagByNumber( pArea, uiTag ); + pTag = pIndex->TagList; + while ( pTag ) + { + ++uiTag; + pTag = pTag->pNext; + } + pIndex = pszBag ? NULL : pIndex->pNext; } + pOrderInfo->itmResult = hb_itemPutNI( pOrderInfo->itmResult, uiTag ); + return SUCCESS; + } + + case DBOI_BAGORDER: + { + LPCDXINDEX pIndex = pArea->lpIndexes, pIndexSeek; + + if( hb_itemGetCLen( pOrderInfo->atomBagName ) > 0 ) + pIndexSeek = hb_cdxFindBag( pArea, + hb_itemGetCPtr( pOrderInfo->atomBagName ) ); + else + pIndexSeek = pIndex; + + if( pIndexSeek ) + { + ++uiTag; + do + { + if( pIndex == pIndexSeek ) + break; + pTag = pIndex->TagList; + while ( pTag ) + { + ++uiTag; + pTag = pTag->pNext; + } + pIndex = pIndex->pNext; + } + while ( pIndex ); + } + pOrderInfo->itmResult = hb_itemPutNI( pOrderInfo->itmResult, + pIndex ? uiTag : 0 ); + return SUCCESS; + } + } + + if( FAST_GOCOLD( ( AREAP ) pArea ) == FAILURE ) + return FAILURE; + + if( pOrderInfo->itmOrder ) + { + pTag = hb_cdxFindTag( pArea, pOrderInfo->itmOrder, pOrderInfo->atomBagName, &uiTag ); + } + else + { + uiTag = pArea->uiTag; + pTag = hb_cdxGetTagByNumber( pArea, uiTag ); } switch( uiIndex ) @@ -7115,59 +7783,61 @@ static ERRCODE hb_cdxOrderInfo( CDXAREAP pArea, USHORT uiIndex, LPDBORDERINFO pO } if ( pTag->pForItem != NULL ) { - if ( hb_itemType( pTag->pForItem ) != HB_IT_BLOCK ) - hb_macroDelete( ( HB_MACRO_PTR ) hb_itemGetPtr( pTag->pForItem ) ); - hb_itemRelease( pTag->pForItem ); + hb_cdxDestroyExp( pTag->pForItem ); pTag->pForItem = NULL; } if ( hb_itemGetCLen( pOrderInfo->itmNewVal ) > 0 ) { - HB_MACRO_PTR pMacro; char * pForExpr = hb_itemGetCPtr( pOrderInfo->itmNewVal ); - if ( SELF_COMPILE( ( AREAP ) pTag->pIndex->pArea, ( BYTE *) pForExpr ) == SUCCESS ) - /* TODO: RT error if SELF_COMPILE return FAILURE */ + if ( SELF_COMPILE( ( AREAP ) pArea, ( BYTE *) pForExpr ) == SUCCESS ) { - pTag->pForItem = pTag->pIndex->pArea->valResult; - pTag->pIndex->pArea->valResult = NULL; - pMacro = ( HB_MACRO_PTR ) hb_itemGetPtr( pTag->pForItem ); - hb_macroRun( pMacro ); - if ( hb_itemType( hb_stackItemFromTop( -1 ) ) == HB_IT_LOGICAL ) + PHB_ITEM pForItem = pArea->valResult; + pArea->valResult = NULL; + if ( SELF_EVALBLOCK( ( AREAP ) pArea, pForItem ) == SUCCESS ) { - pTag->ForExpr = ( char * ) hb_xgrab( CDX_MAXKEY + 1 ); - hb_strncpyTrim( pTag->ForExpr, pForExpr, CDX_MAXKEY ); + if ( hb_itemType( pArea->valResult ) == HB_IT_LOGICAL ) + { + pTag->pForItem = pForItem; + pForItem = NULL; + } + hb_itemRelease( pArea->valResult ); + pArea->valResult = NULL; } - else - { - hb_macroDelete( pMacro ); - hb_itemRelease( pTag->pForItem ); - pTag->pForItem = NULL; - } - hb_stackPop(); + if ( pForItem ) + hb_cdxDestroyExp( pForItem ); } } } break; case DBOI_EXPRESSION: - pOrderInfo->itmResult = hb_itemPutC( pOrderInfo->itmResult, ( pTag ? pTag->KeyExpr : "" ) ); + pOrderInfo->itmResult = hb_itemPutC( pOrderInfo->itmResult, pTag ? pTag->KeyExpr : "" ); break; case DBOI_POSITION: if ( pOrderInfo->itmNewVal && HB_IS_NUMERIC( pOrderInfo->itmNewVal ) ) { - pOrderInfo->itmResult = hb_itemPutL( pOrderInfo->itmResult, - hb_cdxDBOIKeyGoto( pArea, pTag, - hb_itemGetNL( pOrderInfo->itmNewVal ), TRUE ) == SUCCESS ); + pOrderInfo->itmResult = hb_itemPutL( pOrderInfo->itmResult, + hb_cdxDBOIKeyGoto( pArea, pTag, + hb_itemGetNL( pOrderInfo->itmNewVal ), TRUE ) == SUCCESS ); } else pOrderInfo->itmResult = hb_itemPutNL( pOrderInfo->itmResult, hb_cdxDBOIKeyNo( pArea, pTag, TRUE ) ); break; - case DBOI_RECNO: /* TODO: is this ok? DBOI_RECNO == DBOI_KEYNORAW ? */ + /* TODO: is this ok? DBOI_RECNO == DBOI_KEYNORAW ? No, it isn't. */ + /* case DBOI_RECNO: */ case DBOI_KEYNORAW: - pOrderInfo->itmResult = hb_itemPutNL( pOrderInfo->itmResult, + if ( pOrderInfo->itmNewVal && HB_IS_NUMERIC( pOrderInfo->itmNewVal ) ) + { + pOrderInfo->itmResult = hb_itemPutL( pOrderInfo->itmResult, + hb_cdxDBOIKeyGoto( pArea, pTag, + hb_itemGetNL( pOrderInfo->itmNewVal ), FALSE ) == SUCCESS ); + } + else + pOrderInfo->itmResult = hb_itemPutNL( pOrderInfo->itmResult, hb_cdxDBOIKeyNo( pArea, pTag, FALSE ) ); break; @@ -7181,6 +7851,27 @@ static ERRCODE hb_cdxOrderInfo( CDXAREAP pArea, USHORT uiIndex, LPDBORDERINFO pO hb_cdxDBOIKeyCount( pArea, pTag, FALSE ) ); break; + case DBOI_RELKEYPOS: + if ( pOrderInfo->itmNewVal && HB_IS_NUMERIC( pOrderInfo->itmNewVal ) ) + hb_cdxDBOISetRelKeyPos( pArea, pTag, + hb_itemGetND( pOrderInfo->itmNewVal ) ); + else + pOrderInfo->itmResult = hb_itemPutND( pOrderInfo->itmResult, + hb_cdxDBOIGetRelKeyPos( pArea, pTag ) ); + break; + + case DBOI_FINDREC: + pOrderInfo->itmResult = hb_itemPutL( pOrderInfo->itmResult, + hb_cdxDBOIFindRec( pArea, pTag, + hb_itemGetNL( pOrderInfo->itmNewVal ), FALSE ) ); + break; + + case DBOI_FINDRECCONT: + pOrderInfo->itmResult = hb_itemPutL( pOrderInfo->itmResult, + hb_cdxDBOIFindRec( pArea, pTag, + hb_itemGetNL( pOrderInfo->itmNewVal ), TRUE ) ); + break; + case DBOI_SKIPUNIQUE: pOrderInfo->itmResult = hb_itemPutL( pOrderInfo->itmResult, hb_cdxDBOISkipUnique( pArea, pTag, @@ -7238,7 +7929,7 @@ static ERRCODE hb_cdxOrderInfo( CDXAREAP pArea, USHORT uiIndex, LPDBORDERINFO pO break; case DBOI_NAME: - pOrderInfo->itmResult = hb_itemPutC( pOrderInfo->itmResult, ( pTag ? pTag->szName : "" ) ); + pOrderInfo->itmResult = hb_itemPutC( pOrderInfo->itmResult, pTag ? pTag->szName : "" ); break; case DBOI_NUMBER: @@ -7260,60 +7951,17 @@ static ERRCODE hb_cdxOrderInfo( CDXAREAP pArea, USHORT uiIndex, LPDBORDERINFO pO pOrderInfo->itmResult = hb_itemPutC( pOrderInfo->itmResult, pTag ? pTag->pIndex->szFileName : "" ); break; - case DBOI_BAGEXT: - pOrderInfo->itmResult = hb_itemPutC( pOrderInfo->itmResult, CDX_INDEXEXT ); - break; - - case DBOI_HPLOCKING: - case DBOI_LOCKOFFSET: - { - ULONG ulPos, ulPool; - - hb_dbfLockIdxGetData( pArea->bLockType, &ulPos, &ulPool ); - if ( uiIndex == DBOI_LOCKOFFSET ) - pOrderInfo->itmResult = hb_itemPutNL( pOrderInfo->itmResult, ulPos ); - else - pOrderInfo->itmResult = hb_itemPutL( pOrderInfo->itmResult, ulPool > 0 ); - break; - } - - case DBOI_KEYSINCLUDED: - pOrderInfo->itmResult = hb_itemPutNL( pOrderInfo->itmResult, - pArea->pSort ? pArea->pSort->ulTotKeys : 0 ); - break; - - case DBOI_ORDERCOUNT: - { - LPCDXINDEX pIndex; - char *pszBag = hb_itemGetCLen( pOrderInfo->atomBagName ) > 0 ? - hb_itemGetCPtr( pOrderInfo->atomBagName ) : NULL; - uiTag = 0; - pIndex = pszBag ? hb_cdxFindBag( pArea, pszBag ) : pArea->lpIndexes; - while ( pIndex ) - { - pTag = pIndex->TagList; - while ( pTag ) - { - uiTag++; - pTag = pTag->pNext; - } - pIndex = pszBag ? NULL : pIndex->pNext; - } - pOrderInfo->itmResult = hb_itemPutNI( pOrderInfo->itmResult, uiTag ); - break; - } - case DBOI_FILEHANDLE: - pOrderInfo->itmResult = hb_itemPutNL( pOrderInfo->itmResult, ( pTag ? ( LONG ) pTag->pIndex->hFile : FS_ERROR ) ); + pOrderInfo->itmResult = hb_itemPutNInt( pOrderInfo->itmResult, pTag ? pTag->pIndex->hFile : FS_ERROR ); break; case DBOI_ISCOND: - pOrderInfo->itmResult = hb_itemPutL( pOrderInfo->itmResult, ( pTag ? (pTag->ForExpr != NULL) : FALSE ) ); + pOrderInfo->itmResult = hb_itemPutL( pOrderInfo->itmResult, pTag && pTag->ForExpr != NULL ); break; case DBOI_ISDESC: - pOrderInfo->itmResult = hb_itemPutL( pOrderInfo->itmResult, ( pTag ? !pTag->UsrAscend : FALSE ) ); - if ( pOrderInfo->itmNewVal && HB_IS_LOGICAL( pOrderInfo->itmNewVal ) ) + pOrderInfo->itmResult = hb_itemPutL( pOrderInfo->itmResult, pTag && !pTag->UsrAscend ); + if ( pTag && pOrderInfo->itmNewVal && HB_IS_LOGICAL( pOrderInfo->itmNewVal ) ) { pTag->UsrAscend = ! hb_itemGetL( pOrderInfo->itmNewVal ); pTag->curKeyState &= ~( CDX_CURKEY_RAWPOS | CDX_CURKEY_LOGPOS ); @@ -7322,10 +7970,11 @@ static ERRCODE hb_cdxOrderInfo( CDXAREAP pArea, USHORT uiIndex, LPDBORDERINFO pO case DBOI_UNIQUE: pOrderInfo->itmResult = hb_itemPutL( pOrderInfo->itmResult, ( pTag ? pTag->UniqueKey || pTag->UsrUnique : FALSE ) ); - if ( pOrderInfo->itmNewVal && HB_IS_LOGICAL( pOrderInfo->itmNewVal ) && !pTag->UniqueKey ) + if ( pTag && pOrderInfo->itmNewVal && HB_IS_LOGICAL( pOrderInfo->itmNewVal ) && !pTag->UniqueKey ) { pTag->UsrUnique = hb_itemGetL( pOrderInfo->itmNewVal ); - pTag->curKeyState &= ~( CDX_CURKEY_RAWPOS | CDX_CURKEY_LOGPOS ); + pTag->curKeyState &= ~( CDX_CURKEY_RAWPOS | CDX_CURKEY_LOGPOS | + CDX_CURKEY_RAWCNT | CDX_CURKEY_LOGCNT ); } break; @@ -7342,10 +7991,7 @@ static ERRCODE hb_cdxOrderInfo( CDXAREAP pArea, USHORT uiIndex, LPDBORDERINFO pO break; case DBOI_KEYSIZE: - if ( pTag ) - pOrderInfo->itmResult = hb_itemPutNL( pOrderInfo->itmResult, pTag->uiLen ); - else - pOrderInfo->itmResult = hb_itemPutNL( pOrderInfo->itmResult, 0 ); + pOrderInfo->itmResult = hb_itemPutNI( pOrderInfo->itmResult, pTag ? pTag->uiLen : 0 ); break; case DBOI_KEYVAL: @@ -7361,41 +8007,77 @@ static ERRCODE hb_cdxOrderInfo( CDXAREAP pArea, USHORT uiIndex, LPDBORDERINFO pO hb_cdxIndexUnLockRead( pTag->pIndex ); } if ( pTag->CurKey->rec == pArea->ulRecNo ) - hb_cdxKeyGetItem( pTag->CurKey, pOrderInfo->itmResult, pTag->uiType ); + pOrderInfo->itmResult = hb_cdxKeyGetItem( pTag->CurKey, + pOrderInfo->itmResult, pTag, TRUE ); } break; case DBOI_SCOPETOP: if ( pTag ) - hb_cdxScopeInfo( pArea, 0, pOrderInfo->itmResult ); - else + { + if ( pOrderInfo->itmResult ) + hb_cdxTagGetScope( pTag, 0, pOrderInfo->itmResult ); + if ( pOrderInfo->itmNewVal ) + hb_cdxTagSetScope( pTag, 0, pOrderInfo->itmNewVal ); + } + else if ( pOrderInfo->itmResult ) hb_itemClear( pOrderInfo->itmResult ); break; case DBOI_SCOPEBOTTOM: if ( pTag ) - hb_cdxScopeInfo( pArea, 1, pOrderInfo->itmResult ); - else + { + if ( pOrderInfo->itmResult ) + hb_cdxTagGetScope( pTag, 1, pOrderInfo->itmResult ); + if ( pOrderInfo->itmNewVal ) + hb_cdxTagSetScope( pTag, 1, pOrderInfo->itmNewVal ); + } + else if ( pOrderInfo->itmResult ) + hb_itemClear( pOrderInfo->itmResult ); + break; + + case DBOI_SCOPESET: + if ( pTag ) + { + if ( pOrderInfo->itmNewVal ) + { + hb_cdxTagSetScope( pTag, 0, pOrderInfo->itmNewVal ); + hb_cdxTagSetScope( pTag, 1, pOrderInfo->itmNewVal ); + } + } + if ( pOrderInfo->itmResult ) hb_itemClear( pOrderInfo->itmResult ); break; case DBOI_SCOPETOPCLEAR: if ( pTag ) { - hb_cdxScopeInfo( pArea, 0, pOrderInfo->itmResult ); - hb_cdxTagClearScope( pTag, 0); + if ( pOrderInfo->itmResult ) + hb_cdxTagGetScope( pTag, 0, pOrderInfo->itmResult ); + hb_cdxTagClearScope( pTag, 0 ); } - else + else if ( pOrderInfo->itmResult ) hb_itemClear( pOrderInfo->itmResult ); break; case DBOI_SCOPEBOTTOMCLEAR: if ( pTag ) { - hb_cdxScopeInfo( pArea, 1, pOrderInfo->itmResult ); - hb_cdxTagClearScope( pTag, 1); + if ( pOrderInfo->itmResult ) + hb_cdxTagGetScope( pTag, 1, pOrderInfo->itmResult ); + hb_cdxTagClearScope( pTag, 1 ); } - else + else if ( pOrderInfo->itmResult ) + hb_itemClear( pOrderInfo->itmResult ); + break; + + case DBOI_SCOPECLEAR: + if ( pTag ) + { + hb_cdxTagClearScope( pTag, 0 ); + hb_cdxTagClearScope( pTag, 1 ); + } + if ( pOrderInfo->itmResult ) hb_itemClear( pOrderInfo->itmResult ); break; @@ -7424,9 +8106,9 @@ static ERRCODE hb_cdxOrderInfo( CDXAREAP pArea, USHORT uiIndex, LPDBORDERINFO pO if ( pOrderInfo->itmNewVal && !HB_IS_NIL( pOrderInfo->itmNewVal ) ) pKey = hb_cdxKeyPutItem( NULL, pOrderInfo->itmNewVal, pArea->ulRecNo, pTag, TRUE, TRUE ); else - pKey = hb_cdxKeyEval( NULL, pTag, TRUE ); + pKey = hb_cdxKeyEval( NULL, pTag ); pOrderInfo->itmResult = hb_itemPutL( pOrderInfo->itmResult, - hb_cdxTagKeyAdd( pTag, pKey ) ); + hb_cdxTagKeyAdd( pTag, pKey ) ); hb_cdxIndexUnLockWrite( pTag->pIndex ); hb_cdxKeyFree( pKey ); } @@ -7453,7 +8135,7 @@ static ERRCODE hb_cdxOrderInfo( CDXAREAP pArea, USHORT uiIndex, LPDBORDERINFO pO if ( pOrderInfo->itmNewVal && !HB_IS_NIL( pOrderInfo->itmNewVal ) ) pKey = hb_cdxKeyPutItem( NULL, pOrderInfo->itmNewVal, pArea->ulRecNo, pTag, TRUE, TRUE ); else - pKey = hb_cdxKeyEval( NULL, pTag, TRUE ); + pKey = hb_cdxKeyEval( NULL, pTag ); pOrderInfo->itmResult = hb_itemPutL( pOrderInfo->itmResult, hb_cdxTagKeyDel( pTag, pKey ) ); hb_cdxIndexUnLockWrite( pTag->pIndex ); @@ -7481,26 +8163,7 @@ static ERRCODE hb_cdxClearFilter( CDXAREAP pArea ) } /* ( DBENTRYP_V ) hb_cdxClearLocate : NULL */ - -/* ( DBENTRYP_V ) hb_cdxClearScope */ -static ERRCODE hb_cdxClearScope( CDXAREAP pArea ) -{ - LPCDXTAG pTag; - - HB_TRACE(HB_TR_DEBUG, ("hb_cdxClearScope(%p)", pArea)); - - pTag = hb_cdxGetActiveTag( pArea ); - - if ( pTag ) - { - /* resolve any pending scope relations first */ - if( pArea->lpdbPendingRel && pArea->lpdbPendingRel->isScoped ) - SELF_FORCEREL( ( AREAP ) pArea ); - hb_cdxTagClearScope( pTag, 0); - hb_cdxTagClearScope( pTag, 1); - } - return SUCCESS; -} +/* ( DBENTRYP_V ) hb_cdxClearScope : NULL */ /* ( DBENTRYP_VPLP ) hb_cdxCountScope */ static ERRCODE hb_cdxCountScope( CDXAREAP pArea, void * pPtr, LONG * plRec ) @@ -7515,32 +8178,7 @@ static ERRCODE hb_cdxCountScope( CDXAREAP pArea, void * pPtr, LONG * plRec ) } /* ( DBENTRYP_I ) hb_cdxFilterText : NULL */ - -/* ( DBENTRYP_SI ) hb_cdxScopeInfo */ -static ERRCODE hb_cdxScopeInfo( CDXAREAP pArea, USHORT nScope, PHB_ITEM pItem ) -{ - LPCDXTAG pTag; - - HB_TRACE(HB_TR_DEBUG, ("hb_cdxScopeInfo(%p, %hu, %p)", pArea, nScope, pItem)); - - pTag = hb_cdxGetActiveTag( pArea ); - - hb_itemClear( pItem ); - if ( pTag ) - { - PHB_ITEM *pScope; - - /* resolve any pending scope relations first */ - if( pArea->lpdbPendingRel && pArea->lpdbPendingRel->isScoped ) - SELF_FORCEREL( ( AREAP ) pArea ); - - pScope = ( pTag->UsrAscend ? nScope == 0 : nScope != 0 ) ? - &(pTag->topScope) : &(pTag->bottomScope); - if ( *pScope ) - hb_itemCopy( pItem, *pScope ); - } - return SUCCESS; -} +/* ( DBENTRYP_SI ) hb_cdxScopeInfo : NULL */ /* ( DBENTRYP_VFI ) hb_cdxSetFilter */ static ERRCODE hb_cdxSetFilter( CDXAREAP pArea, LPDBFILTERINFO pFilterInfo ) @@ -7550,103 +8188,9 @@ static ERRCODE hb_cdxSetFilter( CDXAREAP pArea, LPDBFILTERINFO pFilterInfo ) } /* ( DBENTRYP_VLO ) hb_cdxSetLocate : NULL */ - -/* ( DBENTRYP_VOS ) hb_cdxSetScope */ -static ERRCODE hb_cdxSetScope( CDXAREAP pArea, LPDBORDSCOPEINFO sInfo ) -{ - LPCDXTAG pTag; - - HB_TRACE(HB_TR_DEBUG, ("hb_cdxSetScope(%p, %p)", pArea, sInfo)); - - pTag = hb_cdxGetActiveTag( pArea ); - - if ( pTag ) - { - /* resolve any pending scope relations first */ - if( pArea->lpdbPendingRel && pArea->lpdbPendingRel->isScoped ) - SELF_FORCEREL( ( AREAP ) pArea ); - - if ( !sInfo->scopeValue ) - { - hb_cdxTagClearScope( pTag, sInfo->nScope ); - } - else - { - USHORT type; - BOOL fOK, fCB = FALSE; - - type = sInfo->scopeValue->type; - if ( type == HB_IT_BLOCK ) - { - hb_vmPushSymbol( &hb_symEval ); - hb_vmPush( sInfo->scopeValue ); - hb_vmSend( 0 ); - type = hb_stackReturnItem()->type; - fCB = TRUE; - } - - switch ( pTag->uiType ) - { - case 'C' : - fOK = ( type & HB_IT_STRING ); break; - case 'N' : - fOK = ( type & HB_IT_NUMERIC ); break; - case 'D' : - fOK = ( type == HB_IT_DATE ); break; - case 'L' : - fOK = ( type == HB_IT_LOGICAL ); break; - default: - fOK = FALSE; - } - if ( fOK ) - { - PHB_ITEM *pScope; - LPCDXKEY *pScopeKey; - ULONG ulRec; - - if ( pTag->UsrAscend ? sInfo->nScope == 0 : sInfo->nScope != 0 ) - { - pScope = &(pTag->topScope); - pScopeKey = &(pTag->topScopeKey); - ulRec = CDX_IGNORE_REC_NUM; - } - else - { - pScope = &(pTag->bottomScope); - pScopeKey = &(pTag->bottomScopeKey); - ulRec = CDX_MAX_REC_NUM; - } - - if ( *pScope == NULL ) - *pScope = hb_itemNew( NULL ); - hb_itemCopy( *pScope, sInfo->scopeValue ); - *pScopeKey = hb_cdxKeyPutItem( *pScopeKey, - fCB ? hb_stackReturnItem() : sInfo->scopeValue, - ulRec, pTag, TRUE, FALSE ); - pTag->curKeyState &= ~( CDX_CURKEY_RAWCNT | CDX_CURKEY_LOGCNT ); - if ( sInfo->nScope == 0 ) - pTag->curKeyState &= ~( CDX_CURKEY_RAWPOS | CDX_CURKEY_LOGPOS ); - } - else - { - /* TODO: !!! - * RT error: DBFCDX/1051 Scope Type Mismatch - * hb_cdxErrorRT - */ - } - } - } - else - { - /* TODO: !!! - * RT error: hb_cdxSetScope: workarea not indexed - */ - } - - return SUCCESS; -} - +/* ( DBENTRYP_VOS ) hb_cdxSetScope : NULL */ /* ( DBENTRYP_VPL ) hb_cdxSkipScope : NULL */ +/* ( DBENTRYP_B ) hb_cdxLocate : NULL */ /* ( DBENTRYP_P ) hb_cdxCompile : NULL */ /* ( DBENTRYP_I ) hb_cdxError : NULL */ @@ -7660,12 +8204,61 @@ static ERRCODE hb_cdxSetScope( CDXAREAP pArea, LPDBORDSCOPEINFO sInfo ) /* ( DBENTRYP_VP ) hb_cdxCreateMemFile : NULL */ /* ( DBENTRYP_SVPB ) hb_cdxGetValueFile : NULL */ /* ( DBENTRYP_VP ) hb_cdxOpenMemFile : NULL */ -/* ( DBENTRYP_SVP ) hb_cdxPutValueFile : NULL */ +/* ( DBENTRYP_SVPB ) hb_cdxPutValueFile : NULL */ /* ( DBENTRYP_V ) hb_cdxReadDBHeader : NULL */ /* ( DBENTRYP_V ) hb_cdxWriteDBHeader : NULL */ /* ( DBENTRYP_SVP ) hb_cdxWhoCares : NULL */ +/* + * Retrieve (set) information about RDD + * ( DBENTRYP_RSLV ) hb_fptFieldInfo + */ +static ERRCODE hb_cdxRddInfo( LPRDDNODE pRDD, USHORT uiIndex, ULONG ulConnect, PHB_ITEM pItem ) +{ + LPDBFDATA pData; + + HB_TRACE(HB_TR_DEBUG, ("hb_cdxRddInfo(%p, %hu, %lu, %p)", pRDD, uiIndex, ulConnect, pItem)); + + pData = ( LPDBFDATA ) pRDD->lpvCargo; + + switch( uiIndex ) + { + case RDDI_ORDBAGEXT: + case RDDI_ORDEREXT: + case RDDI_ORDSTRUCTEXT: + { + char * szNew = hb_itemGetCPtr( pItem ); + + if( szNew[0] == '.' && szNew[1] ) + szNew = hb_strdup( szNew ); + else + szNew = NULL; + + hb_itemPutC( pItem, pData->szIndexExt[ 0 ] ? pData->szIndexExt : CDX_INDEXEXT ); + if( szNew ) + { + hb_strncpy( pData->szIndexExt, szNew, HB_MAX_FILE_EXT ); + hb_xfree( szNew ); + } + break; + } + + case RDDI_MULTITAG: + case RDDI_SORTRECNO: + case RDDI_STRUCTORD: + case RDDI_MULTIKEY: + hb_itemPutL( pItem, TRUE ); + break; + + default: + return SUPER_RDDINFO( pRDD, uiIndex, ulConnect, pItem ); + + } + + return SUCCESS; +} + /* ######################################################################### */ @@ -7715,7 +8308,7 @@ static BOOL hb_cdxQSort( LPCDXSORTINFO pSort, BYTE * pSrc, BYTE * pBuf, LONG lKe } while ( l1 > 0 && l2 > 0 ) { - if ( hb_cdxQuickSortCompare( pSort, pPtr1, pPtr2 ) < 0 ) + if ( hb_cdxQuickSortCompare( pSort, pPtr1, pPtr2 ) <= 0 ) { memcpy( pDst, pPtr1, iLen ); pPtr1 += iLen; @@ -7744,12 +8337,13 @@ static BOOL hb_cdxQSort( LPCDXSORTINFO pSort, BYTE * pSrc, BYTE * pBuf, LONG lKe static void hb_cdxSortSortPage( LPCDXSORTINFO pSort ) { + ULONG ulSize = pSort->ulKeys * ( pSort->keyLen + 4 ); #ifdef HB_CDX_DBGTIME cdxTimeIdxBld -= hb_cdxGetTime(); #endif - if ( !hb_cdxQSort( pSort, pSort->pKeyPool, &pSort->pKeyPool[ pSort->ulKeys * ( pSort->keyLen + 4 ) ], pSort->ulKeys ) ) + if ( !hb_cdxQSort( pSort, pSort->pKeyPool, &pSort->pKeyPool[ ulSize ], pSort->ulKeys ) ) { - memcpy( pSort->pKeyPool, &pSort->pKeyPool[ pSort->ulKeys * ( pSort->keyLen + 4 ) ], pSort->ulKeys * ( pSort->keyLen + 4 ) ); + memcpy( pSort->pKeyPool, &pSort->pKeyPool[ ulSize ], ulSize ); } #ifdef HB_CDX_DBGTIME cdxTimeIdxBld += hb_cdxGetTime(); @@ -7766,7 +8360,7 @@ static void hb_cdxSortAddNodeKey( LPCDXSORTINFO pSort, int iLevel, BYTE *pKeyVal pPage = pSort->NodeList[ iLevel ]; if ( iLevel == 0 ) { - while ( pKeyVal[ iLen - iTrl - 1 ] == pSort->bTrl && iTrl < iLen ) + while ( iTrl < iLen && pKeyVal[ iLen - iTrl - 1 ] == pSort->bTrl ) { iTrl++; } @@ -7885,7 +8479,7 @@ static void hb_cdxSortWritePage( LPCDXSORTINFO pSort ) pSort->szTempFileName = hb_strdup( ( char * ) szName ); } pSort->pSwapPage[ pSort->ulCurPage ].ulKeys = pSort->ulKeys; - pSort->pSwapPage[ pSort->ulCurPage ].nOffset = hb_fsSeekLarge( pSort->hTempFile, 0, SEEK_END ); + pSort->pSwapPage[ pSort->ulCurPage ].nOffset = hb_fsSeekLarge( pSort->hTempFile, 0, FS_END ); if ( hb_fsWriteLarge( pSort->hTempFile, pSort->pKeyPool, ulSize ) != ulSize ) { hb_errInternal( 9999, "hb_cdxSortWritePage: Write error in temporary file.", "", "" ); @@ -7950,7 +8544,7 @@ static void hb_cdxSortOrderPages( LPCDXSORTINFO pSort ) r = m - 1; } for ( r = n; r > l; r-- ) - pSort->pSortedPages[ r ] = pSort->pSortedPages[ r - 1 ]; + pSort->pSortedPages[ r ] = pSort->pSortedPages[ r - 1 ]; pSort->pSortedPages[ l ] = n; } } @@ -7970,6 +8564,14 @@ static BOOL hb_cdxSortKeyGet( LPCDXSORTINFO pSort, BYTE ** pKeyVal, ULONG *pulRe BYTE *pKey, *pTmp; ULONG ulRec; + /* + * last key was taken from this page - we have to resort it. + * This is done intentionally here to be sure that the key + * value return by this function will not be overwritten by + * next keys in page read from temporary file in function + * hb_cdxSortGetPageKey() - please do not move this part down + * even it seems to be correct + */ hb_cdxSortGetPageKey( pSort, ulPage, &pKey, &ulRec ); l = pSort->ulFirst + 1; @@ -8070,11 +8672,15 @@ static void hb_cdxSortKeyAdd( LPCDXSORTINFO pSort, ULONG ulRec, BYTE * pKeyVal, } pDst = &pSort->pKeyPool[ pSort->ulKeys * ( iLen + 4 ) ]; - memcpy( pDst, pKeyVal, iKeyLen ); if ( iLen > iKeyLen ) { + memcpy( pDst, pKeyVal, iKeyLen ); memset( &pDst[ iKeyLen ], pSort->bTrl, iLen - iKeyLen ); } + else + { + memcpy( pDst, pKeyVal, iLen ); + } HB_PUT_LE_UINT32( &pDst[ iLen ], ulRec ); pSort->ulKeys++; pSort->ulTotKeys++; @@ -8085,21 +8691,19 @@ static LPCDXSORTINFO hb_cdxSortNew( LPCDXTAG pTag, ULONG ulRecCount ) LPCDXSORTINFO pSort; BYTE * pBuf; int iLen = pTag->uiLen; - ULONG ulSize, ulMax; + ULONG ulSize, ulMax, ulMin; if ( ulRecCount == 0 ) - { - return NULL; - } + ulRecCount = 1; pSort = ( LPCDXSORTINFO ) hb_xgrab( sizeof( CDXSORTINFO ) ); memset( pSort, 0, sizeof( CDXSORTINFO ) ); - /* ulMax = ( 1L << 30 ) / ( iLen + 4 ); */ - ulMax = ( 1L << 21 ) / ( iLen + 4 ); + ulMax = ulMin = ( ULONG ) ceil( sqrt( ( double ) ulRecCount ) ); + ulSize = ( 1L << 20 ) / ( iLen + 4 ); + while ( ulMax < ulSize ) + ulMax <<= 1; if ( ulMax > ulRecCount ) - { ulMax = ulRecCount; - } do { @@ -8115,12 +8719,36 @@ static LPCDXSORTINFO hb_cdxSortNew( LPCDXTAG pTag, ULONG ulRecCount ) ulMax >>= 1; } } - while ( ! pBuf ); + while ( ! pBuf && ulMax >= ulMin ); + + if ( ! pBuf ) + { + /* call hb_xgrab() to force out of memory error, + * though in multi process environment this call may return + * with success when other process free some memory + * (also the size of buf is reduced to absolute minimum). + * Sorry but I'm to lazy to implement indexing with smaller + * memory though it's possible - just simply I can even create + * index on-line by key adding like in normal update process. + * The memory necessary to index file is now ~ + * ~ (keySize+4+sizeof(CDXSWAPPAGE)) * sqrt(ulRecCount) * 2 + * so the maximum is for DBF with 2^32 records and keySize 240 ~ + * ~ 2^17 * 268 ~=~ 35 Mb + * this is not a problem for current computers and I do not see + * any way to use DBFs with four billions records and indexes with + * such long (240 bytes) keys on the old ones - they will be simply + * to slow. IMHO it's also better to signal out of memory here and + * force some system upgrades then run process which will have to + * take many hours, Druzus. + */ + ulMax = ulMin; + pBuf = ( BYTE * ) hb_xgrab( ( ulMax << 1 ) * ( iLen + 4 ) ); + } pSort->pTag = pTag; pSort->hTempFile = FS_ERROR; pSort->keyLen = iLen; - pSort->bTrl = pTag->uiType == 'C' ? ' ' : '\0'; + pSort->bTrl = pTag->bTrail; pSort->fUnique = pTag->UniqueKey; pSort->ulMaxKey = ulMax << 1; pSort->ulPgKeys = ulMax; @@ -8172,7 +8800,11 @@ static void hb_cdxSortOut( LPCDXSORTINFO pSort ) pSort->ulPages = pSort->ulCurPage + 1; pSort->ulPgKeys = pSort->ulMaxKey / pSort->ulPages; - /* printf( "\r\npSort->ulPages=%ld\r\n", (long) pSort->ulPages ); fflush(stdout); */ + /* + printf( "\r\npSort->ulMaxKey=%ld, pSort->ulPages=%ld, pSort->ulPgKeys=%ld, size=%ld\r\n", + pSort->ulMaxKey, pSort->ulPages, pSort->ulPgKeys, + pSort->ulMaxKey * ( pSort->keyLen + 4 ) ); fflush(stdout); + */ if ( pSort->ulPages > 1 ) { BYTE * pBuf = pSort->pKeyPool; @@ -8264,8 +8896,6 @@ static void hb_cdxSortOut( LPCDXSORTINFO pSort ) iLevel++; } while ( fNext ); - - hb_cdxSortFree( pSort ); } static void hb_cdxTagEmptyIndex( LPCDXTAG pTag ) @@ -8276,115 +8906,141 @@ static void hb_cdxTagEmptyIndex( LPCDXTAG pTag ) hb_cdxPageLeafInitSpace( pTag->RootPage ); } -static void hb_cdxTagDoIndex( LPCDXTAG pTag ) +static void hb_cdxTagDoIndex( LPCDXTAG pTag, BOOL fReindex ) { - ULONG ulRecNo, ulRecCount; - BOOL bForOk; - LPCDXSORTINFO pSort; - PHB_ITEM pItem; - HB_MACRO_PTR pMacro; - BYTE cTemp[8]; LPCDXAREA pArea = pTag->pIndex->pArea; + LPCDXSORTINFO pSort; + PHB_ITEM pForItem, pWhileItem = NULL, pEvalItem = NULL, pItem = NULL; + ULONG ulRecCount, ulRecNo = pArea->ulRecNo; LONG lStep = 0; - BOOL bDirectRead; - PHB_ITEM pForItem, pWhileItem, pEvalItem; #ifndef HB_CDP_SUPPORT_OFF /* TODO: this hack is not thread safe, hb_cdp_page has to be thread specific */ PHB_CODEPAGE cdpTmp = hb_cdp_page; hb_cdp_page = pArea->cdPage; #endif - if ( ( pTag->OptFlags & CDX_TYPE_STRUCTURE ) || pTag->Custom ) + if ( pArea->lpdbOrdCondInfo ) + { + pEvalItem = pArea->lpdbOrdCondInfo->itmCobEval; + pWhileItem = pArea->lpdbOrdCondInfo->itmCobWhile; + lStep = pArea->lpdbOrdCondInfo->lStep; + } + + if( pTag->Custom || ( pTag->OptFlags & CDX_TYPE_STRUCTURE ) ) + { + ulRecCount = 0; + } + else if( SELF_RECCOUNT( ( AREAP ) pArea, &ulRecCount ) != SUCCESS ) + { + return; + } + + pArea->pSort = pSort = hb_cdxSortNew( pTag, ulRecCount ); + pSort->fReindex = fReindex; + +#if defined( HB_SIXCDX ) + if ( ( pTag->OptFlags & CDX_TYPE_STRUCTURE ) == 0 && pEvalItem ) + { + SELF_GOTO( ( AREAP ) pArea, 0 ); + if ( !hb_cdxEvalCond( pArea, pEvalItem, FALSE ) ) + { + hb_cdxSortFree( pSort ); + pArea->pSort = NULL; + SELF_GOTO( ( AREAP ) pArea, ulRecNo ); + return; + } + } +#endif + if( ulRecCount == 0 ) { hb_cdxTagEmptyIndex( pTag ); } else { - BOOL bSaveDeleted = hb_set.HB_SET_DELETED, fSaveRecDeleted = pArea->fDeleted; - PHB_ITEM pSaveFilter = pArea->dbfi.itmCobExpr; USHORT uiSaveTag = pArea->uiTag; - ULONG ulSaveRecNo = pArea->ulRecNo, ulStartRec = 0, ulNextCount = 0; - BYTE * pSaveRecBuff = pArea->pRecord; - int iRecBuff = 0, iRecBufSize = USHRT_MAX / pArea->uiRecordLen; + ULONG ulStartRec = 0, ulNextCount = 0; + BOOL fDirectRead, fUseFilter = FALSE; + BYTE * pSaveRecBuff = pArea->pRecord, cTemp[8]; + int iRecBuff = 0, iRecBufSize = USHRT_MAX / pArea->uiRecordLen, iRec; - hb_set.HB_SET_DELETED = FALSE; - pArea->dbfi.itmCobExpr = NULL; - - pItem = hb_itemNew( NULL ); - SELF_RECCOUNT( ( AREAP ) pArea, &ulRecCount ); - pArea->pSort = pSort = hb_cdxSortNew( pTag, ulRecCount ); pForItem = pTag->pForItem; - bForOk = TRUE; - pEvalItem = ( pArea->lpdbOrdCondInfo ? pArea->lpdbOrdCondInfo->itmCobEval : NULL); - pWhileItem = ( pArea->lpdbOrdCondInfo ? pArea->lpdbOrdCondInfo->itmCobWhile : NULL); + if ( pTag->nField ) + pItem = hb_itemNew( NULL ); if ( !pArea->lpdbOrdCondInfo || pArea->lpdbOrdCondInfo->fAll ) { pArea->uiTag = 0; } - else if ( pArea->lpdbOrdCondInfo->lRecno ) + else { - ulStartRec = ulRecCount = pArea->lpdbOrdCondInfo->lRecno; - ulNextCount = 1; - } - else if ( pArea->lpdbOrdCondInfo->fRest || pArea->lpdbOrdCondInfo->lNextCount > 0 ) - { - if ( pArea->lpdbOrdCondInfo->lStartRecno ) + if( pArea->lpdbOrdCondInfo->itmRecID ) + ulStartRec = hb_itemGetNL( pArea->lpdbOrdCondInfo->itmRecID ); + if ( ulStartRec ) { - ulStartRec = pArea->lpdbOrdCondInfo->lStartRecno; + ulNextCount = 1; } - else + else if ( pArea->lpdbOrdCondInfo->fRest || pArea->lpdbOrdCondInfo->lNextCount > 0 ) { - ulStartRec = pArea->ulRecNo; + if( pArea->lpdbOrdCondInfo->itmStartRecID ) + ulStartRec = hb_itemGetNL( pArea->lpdbOrdCondInfo->itmStartRecID ); + if( !ulStartRec ) + ulStartRec = ulRecNo; + if( pArea->lpdbOrdCondInfo->lNextCount > 0 ) + ulNextCount = pArea->lpdbOrdCondInfo->lNextCount; } - if ( pArea->lpdbOrdCondInfo->lNextCount > 0 ) + else if( pArea->lpdbOrdCondInfo->fUseFilter ) { - ulNextCount = pArea->lpdbOrdCondInfo->lNextCount; - ulRecCount = ulStartRec + ulNextCount - 1; + fUseFilter = TRUE; + } + else if ( !pArea->lpdbOrdCondInfo->fUseCurrent ) + { + pArea->uiTag = 0; } } - else if ( !pArea->lpdbOrdCondInfo->fUseCurrent ) - { - pArea->uiTag = 0; - } - - bDirectRead = !hb_set.HB_SET_STRICTREAD && !pArea->lpdbRelations && + fDirectRead = !hb_set.HB_SET_STRICTREAD && /* !pArea->lpdbRelations && */ ( !pArea->lpdbOrdCondInfo || pArea->lpdbOrdCondInfo->fAll || - pArea->uiTag == 0 ) && pSort; + ( pArea->uiTag == 0 && !fUseFilter ) ); - if ( bDirectRead ) - { + if ( fDirectRead ) pSort->pRecBuff = (BYTE *) hb_xgrab( pArea->uiRecordLen * iRecBufSize ); - if ( ulStartRec == 0 ) - { - ulStartRec = 1; - } + + if ( ulStartRec == 0 && pArea->uiTag == 0 ) + ulStartRec = 1; + + if ( ulStartRec == 0 ) + { + SELF_GOTOP( ( AREAP ) pArea ); } else { - if ( ulStartRec == 0 ) - { - SELF_GOTOP( ( AREAP ) pArea ); - } - else - { - SELF_GOTO( ( AREAP ) pArea, ulStartRec ); - } - ulStartRec = 1; + SELF_GOTO( ( AREAP ) pArea, ulStartRec ); + if ( fUseFilter ) + SELF_SKIPFILTER( ( AREAP ) pArea, 1 ); } - for ( ulRecNo = ulStartRec; ulRecNo <= ulRecCount; ulRecNo++ ) + ulRecNo = pArea->ulRecNo; + + if ( ulNextCount && ulRecCount >= ulRecNo + ulNextCount ) + ulRecCount = ulRecNo + ulNextCount - 1; + + do { - if ( bDirectRead ) + if ( ulRecNo > ulRecCount ) + pArea->fEof = TRUE; + + if ( pArea->fEof ) + break; + + if ( fDirectRead ) { if ( iRecBuff == 0 || iRecBuff >= iRecBufSize ) { - int iRec; if ( ulRecCount - ulRecNo >= (ULONG) iRecBufSize ) iRec = iRecBufSize; else iRec = ulRecCount - ulRecNo + 1; - + if ( iRec <= 0 ) + break; hb_fsSeekLarge( pArea->hDataFile, ( HB_FOFFSET ) pArea->uiHeaderLen + ( HB_FOFFSET ) ( ulRecNo - 1 ) * @@ -8393,41 +9049,44 @@ static void hb_cdxTagDoIndex( LPCDXTAG pTag ) iRecBuff = 0; } pArea->pRecord = pSort->pRecBuff + iRecBuff * pArea->uiRecordLen; + pArea->fValidBuffer = TRUE; pArea->ulRecNo = ulRecNo; pArea->fDeleted = ( pArea->pRecord[ 0 ] == '*' ); + /* Force relational movement in child WorkAreas */ + if( pArea->lpdbRelations ) + SELF_SYNCCHILDREN( ( AREAP ) pArea ); iRecBuff++; } - else if ( pWhileItem && !hb_cdxEvalCond ( NULL, pWhileItem, FALSE ) ) + +#if !defined( HB_SIXCDX ) + if ( pEvalItem ) + { + if ( lStep >= pArea->lpdbOrdCondInfo->lStep ) + { + lStep = 0; + if ( !hb_cdxEvalCond( pArea, pEvalItem, FALSE ) ) + break; + } + ++lStep; + } +#endif + + if ( pWhileItem && !hb_cdxEvalCond( NULL, pWhileItem, FALSE ) ) break; - if ( pForItem != NULL ) - { - bForOk = hb_cdxEvalCond ( pArea, pForItem, FALSE ); - } - - if ( bForOk ) + if ( pForItem == NULL || hb_cdxEvalCond( pArea, pForItem, FALSE ) ) { double d; if ( pTag->nField ) - { SELF_GETVALUE( ( AREAP ) pArea, pTag->nField, pItem ); - } - else if ( HB_IS_BLOCK( pTag->pKeyItem ) ) - { - hb_itemCopy( pItem, hb_vmEvalBlock( pTag->pKeyItem ) ); - } else - { - pMacro = ( HB_MACRO_PTR ) hb_itemGetPtr( pTag->pKeyItem ); - hb_macroRun( pMacro ); - hb_itemCopy( pItem, hb_stackItemFromTop( -1 ) ); - hb_stackPop(); - } + pItem = hb_vmEvalBlockOrMacro( pTag->pKeyItem ); switch( hb_itemType( pItem ) ) { case HB_IT_STRING: + case HB_IT_STRING | HB_IT_MEMO: hb_cdxSortKeyAdd( pSort, pArea->ulRecNo, ( BYTE * ) pItem->item.asString.value, HB_CDXMAXKEY( pItem->item.asString.length ) ); @@ -8465,55 +9124,70 @@ static void hb_cdxTagDoIndex( LPCDXTAG pTag ) break; } } - if ( pEvalItem ) - { - if ( pArea->lpdbOrdCondInfo->lStep ) - { - lStep ++; - if ( lStep == pArea->lpdbOrdCondInfo->lStep ) - lStep = 0; - } - if ( lStep == 0 ) - { - if ( !hb_cdxEvalCond ( pArea, pEvalItem, FALSE ) ) - break; - } - } + if( ulNextCount > 0 ) { - if ( --ulNextCount == 0 ) + if( --ulNextCount == 0 ) break; } - if ( !bDirectRead ) - { - SELF_SKIP( ( AREAP ) pArea, 1 ); - if ( pArea->fEof ) - break; - } - } - if ( pSort ) - { - hb_cdxSortOut( pSort ); - pArea->pSort = NULL; - } - else - { - hb_cdxTagEmptyIndex( pTag ); - } - hb_itemRelease( pItem ); - if ( bDirectRead ) +#if defined( HB_SIXCDX ) + if ( pEvalItem ) + { + if ( lStep >= pArea->lpdbOrdCondInfo->lStep ) + { + lStep = 0; + if ( !hb_cdxEvalCond( pArea, pEvalItem, FALSE ) ) + break; + } + ++lStep; + } +#endif + + if( fDirectRead ) + ulRecNo++; + else + { + if( SELF_SKIPRAW( ( AREAP ) pArea, 1 ) == FAILURE ) + break; + if( fUseFilter && SELF_SKIPFILTER( ( AREAP ) pArea, 1 ) == FAILURE ) + break; + ulRecNo = pArea->ulRecNo; + } + } while ( TRUE ); + + hb_cdxSortOut( pSort ); + if ( pTag->nField ) + hb_itemRelease( pItem ); + + if ( fDirectRead ) { pArea->pRecord = pSaveRecBuff; - pArea->ulRecNo = ulSaveRecNo; - pArea->fDeleted = fSaveRecDeleted; + SELF_GOTO( ( AREAP ) pArea, ulRecNo ); } - hb_set.HB_SET_DELETED = bSaveDeleted; - pArea->dbfi.itmCobExpr = pSaveFilter; pArea->uiTag = uiSaveTag; - pTag->TagChanged = TRUE; + +#if !defined( HB_SIXCDX ) + if ( pEvalItem && lStep ) + { + /* pArea->fEof = TRUE; */ + hb_cdxEvalCond( pArea, pEvalItem, FALSE ); + } +#endif } - pTag->pIndex->pArea->ulRecNo = 0; + +#if defined( HB_SIXCDX ) + if ( pEvalItem ) + { + SELF_GOTO( ( AREAP ) pArea, 0 ); + pArea->fBof = FALSE; + hb_cdxEvalCond( pArea, pEvalItem, FALSE ); + } +#endif + + hb_cdxSortFree( pSort ); + pArea->pSort = NULL; + #ifndef HB_CDP_SUPPORT_OFF hb_cdp_page = cdpTmp; #endif diff --git a/harbour/source/rdd/dbfcdx/sixcdx0.prg b/harbour/source/rdd/dbfcdx/sixcdx0.prg new file mode 100644 index 0000000000..8a4f791124 --- /dev/null +++ b/harbour/source/rdd/dbfcdx/sixcdx0.prg @@ -0,0 +1,66 @@ +/* + * $Id$ + */ + +/* + * Harbour Project source code: + * DBFCDX RDD (ver.2) + * + * Copyright 1999 Bruno Cantero + * Copyright 2003 Przemyslaw Czerpak + * www - http://www.xharbour.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/). + * + * As a special exception, the Harbour Project gives permission for + * additional uses of the text contained in its release of Harbour. + * + * The exception is that, if you link the Harbour libraries with other + * files to produce an executable, this does not by itself cause the + * resulting executable to be covered by the GNU General Public License. + * Your use of that executable is in no way restricted on account of + * linking the Harbour library code into it. + * + * This exception does not however invalidate any other reasons why + * the executable file might be covered by the GNU General Public License. + * + * This exception applies only to the code released by the Harbour + * Project under the name Harbour. If you copy code from other + * Harbour Project or Free Software Foundation releases into a copy of + * Harbour, as the General Public License permits, the exception does + * not apply to the code that you add in this way. To avoid misleading + * anyone as to the status of such modified files, you must delete + * this exception notice from them. + * + * If you write modifications of your own for Harbour, it is your choice + * whether to permit this exception to apply to your modifications. + * If you do not wish that, delete this exception notice. + * + */ + +#include "rddsys.ch" + +ANNOUNCE SIXCDX + +procedure SIXCDXInit + + REQUEST _DBF + REQUEST _SIXCDX + + rddRegister( "DBF", RDT_FULL ) + rddRegister( "SIXCDX", RDT_FULL ) + +return diff --git a/harbour/source/rdd/dbfcdx/sixcdx1.c b/harbour/source/rdd/dbfcdx/sixcdx1.c new file mode 100644 index 0000000000..d55535fd45 --- /dev/null +++ b/harbour/source/rdd/dbfcdx/sixcdx1.c @@ -0,0 +1,55 @@ +/* + * $Id$ + */ + +/* + * xHarbour Project source code: + * SIXCDX RDD + * + * Copyright 2005 Przemyslaw Czerpak + * www - http://www.xharbour.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/). + * + * As a special exception, the Harbour Project gives permission for + * additional uses of the text contained in its release of Harbour. + * + * The exception is that, if you link the Harbour libraries with other + * files to produce an executable, this does not by itself cause the + * resulting executable to be covered by the GNU General Public License. + * Your use of that executable is in no way restricted on account of + * linking the Harbour library code into it. + * + * This exception does not however invalidate any other reasons why + * the executable file might be covered by the GNU General Public License. + * + * This exception applies only to the code released by the Harbour + * Project under the name Harbour. If you copy code from other + * Harbour Project or Free Software Foundation releases into a copy of + * Harbour, as the General Public License permits, the exception does + * not apply to the code that you add in this way. To avoid misleading + * anyone as to the status of such modified files, you must delete + * this exception notice from them. + * + * If you write modifications of your own for Harbour, it is your choice + * whether to permit this exception to apply to your modifications. + * If you do not wish that, delete this exception notice. + * + */ + +#define HB_SIXCDX + +#include "dbfcdx1.c" diff --git a/harbour/source/rdd/dbfdbt/Makefile b/harbour/source/rdd/dbfdbt/Makefile index 68e1e78fb9..6ead7c8ed6 100644 --- a/harbour/source/rdd/dbfdbt/Makefile +++ b/harbour/source/rdd/dbfdbt/Makefile @@ -10,6 +10,11 @@ C_SOURCES=\ PRG_SOURCES=\ dbfdbt0.prg \ +ifeq ($(HB_MT),MT) + MT_LIBNAME=dbfdbtmt +endif + + LIBNAME=dbfdbt include $(TOP)$(ROOT)config/lib.cf diff --git a/harbour/source/rdd/dbfdbt/dbfdbt1.c b/harbour/source/rdd/dbfdbt/dbfdbt1.c index 4009ef3884..1aeedb18ec 100644 --- a/harbour/source/rdd/dbfdbt/dbfdbt1.c +++ b/harbour/source/rdd/dbfdbt/dbfdbt1.c @@ -112,7 +112,8 @@ static RDDFUNCS dbtTable = ( DBENTRYP_V ) hb_dbtRecall, ( DBENTRYP_ULP ) hb_dbtRecCount, ( DBENTRYP_ISI ) hb_dbtRecInfo, - ( DBENTRYP_I ) hb_dbtRecNo, + ( DBENTRYP_ULP ) hb_dbtRecNo, + ( DBENTRYP_I ) hb_dbtRecId, ( DBENTRYP_S ) hb_dbtSetFieldExtent, @@ -154,7 +155,7 @@ static RDDFUNCS dbtTable = ( DBENTRYP_OI ) hb_dbtOrderListAdd, ( DBENTRYP_V ) hb_dbtOrderListClear, - ( DBENTRYP_VP ) hb_dbtOrderListDelete, + ( DBENTRYP_OI ) hb_dbtOrderListDelete, ( DBENTRYP_OI ) hb_dbtOrderListFocus, ( DBENTRYP_V ) hb_dbtOrderListRebuild, ( DBENTRYP_VOI ) hb_dbtOrderCondition, @@ -175,6 +176,7 @@ static RDDFUNCS dbtTable = ( DBENTRYP_VLO ) hb_dbtSetLocate, ( DBENTRYP_VOS ) hb_dbtSetScope, ( DBENTRYP_VPL ) hb_dbtSkipScope, + ( DBENTRYP_B ) hb_dbtLocate, /* Miscellaneous */ @@ -188,7 +190,7 @@ static RDDFUNCS dbtTable = ( DBENTRYP_VSP ) hb_dbtRawLock, ( DBENTRYP_VL ) hb_dbtLock, - ( DBENTRYP_UL ) hb_dbtUnLock, + ( DBENTRYP_I ) hb_dbtUnLock, /* Memofile functions */ @@ -197,7 +199,7 @@ static RDDFUNCS dbtTable = ( DBENTRYP_VP ) hb_dbtCreateMemFile, ( DBENTRYP_SVPB ) hb_dbtGetValueFile, ( DBENTRYP_VP ) hb_dbtOpenMemFile, - ( DBENTRYP_SVP ) hb_dbtPutValueFile, + ( DBENTRYP_SVPB ) hb_dbtPutValueFile, /* Database file header handling */ @@ -207,9 +209,11 @@ static RDDFUNCS dbtTable = /* non WorkArea functions */ - ( DBENTRYP_I0 ) hb_dbtExit, - ( DBENTRYP_I1 ) hb_dbtDrop, - ( DBENTRYP_I2 ) hb_dbtExists, + ( DBENTRYP_R ) hb_dbtInit, + ( DBENTRYP_R ) hb_dbtExit, + ( DBENTRYP_RVV ) hb_dbtDrop, + ( DBENTRYP_RVV ) hb_dbtExists, + ( DBENTRYP_RSLV ) hb_dbtRddInfo, /* Special and reserved methods */ @@ -245,9 +249,9 @@ HB_INIT_SYMBOLS_BEGIN( dbfdbt1__InitSymbols ) { "DBFDBT_GETFUNCTABLE", HB_FS_PUBLIC, {HB_FUNCNAME( DBFDBT_GETFUNCTABLE )}, NULL } HB_INIT_SYMBOLS_END( dbfdbt1__InitSymbols ) -#if defined(HB_STATIC_STARTUP) +#if defined(HB_PRAGMA_STARTUP) # pragma startup dbfdbt1__InitSymbols -#elif defined(_MSC_VER) +#elif defined(HB_MSC_STARTUP) # if _MSC_VER >= 1010 # pragma data_seg( ".CRT$XIY" ) # pragma comment( linker, "/Merge:.CRT=.data" ) @@ -256,8 +260,6 @@ HB_INIT_SYMBOLS_END( dbfdbt1__InitSymbols ) # endif static HB_$INITSYM hb_vm_auto_dbfdbt1__InitSymbols = dbfdbt1__InitSymbols; # pragma data_seg() -#elif ! defined(__GNUC__) -# pragma startup dbfdbt1__InitSymbols #endif /* @@ -319,23 +321,24 @@ static ULONG hb_dbtGetMemoLen( DBTAREAP pArea, USHORT uiIndex ) { ULONG ulBlock; BYTE pBlock[ DBT_BLOCKSIZE ]; + USHORT uiLen; HB_TRACE(HB_TR_DEBUG, ("hb_dbtGetMemoLen(%p, %hu)", pArea, uiIndex)); ulBlock = hb_dbfGetMemoBlock( ( DBFAREAP ) pArea, uiIndex ); if( ulBlock == 0 ) return 0; - hb_fsSeek( pArea->hMemoFile, ulBlock * DBT_BLOCKSIZE, FS_SET ); + hb_fsSeekLarge( pArea->hMemoFile, ( HB_FOFFSET ) ulBlock * DBT_BLOCKSIZE, FS_SET ); ulBlock = 0; do { uiIndex = 0; - if ( hb_fsRead( pArea->hMemoFile, pBlock, DBT_BLOCKSIZE ) == DBT_BLOCKSIZE ) - { - while( uiIndex < DBT_BLOCKSIZE && pBlock[ uiIndex ] != 0x1A ) - uiIndex++; - ulBlock += uiIndex; - } + uiLen = hb_fsRead( pArea->hMemoFile, pBlock, DBT_BLOCKSIZE ); + if ( uiLen == ( USHORT ) FS_ERROR ) + break; + while( uiIndex < uiLen && pBlock[ uiIndex ] != 0x1A ) + uiIndex++; + ulBlock += uiIndex; } while( uiIndex == DBT_BLOCKSIZE ); return ulBlock; } @@ -356,16 +359,16 @@ static void hb_dbtGetMemo( DBTAREAP pArea, USHORT uiIndex, PHB_ITEM pItem ) if( ulSize > 0 ) { ulBlock = hb_dbfGetMemoBlock( ( DBFAREAP ) pArea, uiIndex ); - hb_fsSeek( pArea->hMemoFile, ulBlock * DBT_BLOCKSIZE, FS_SET ); + hb_fsSeekLarge( pArea->hMemoFile, ( HB_FOFFSET ) ulBlock * DBT_BLOCKSIZE, FS_SET ); hb_fsReadLarge( pArea->hMemoFile, pBuffer, ulSize ); +#ifndef HB_CDP_SUPPORT_OFF + hb_cdpnTranslate( ( char * ) pBuffer, pArea->cdPage, hb_cdp_page, ulSize ); +#endif } else *pBuffer = '\0'; hb_itemPutCPtr( pItem, ( char * ) pBuffer, ulSize ); -#ifndef HB_CDP_SUPPORT_OFF - hb_cdpnTranslate( pItem->item.asString.value, pArea->cdPage, hb_cdp_page, ulSize ); -#endif hb_itemSetCMemo( pItem ); } @@ -375,50 +378,69 @@ static void hb_dbtGetMemo( DBTAREAP pArea, USHORT uiIndex, PHB_ITEM pItem ) static void hb_dbtWriteMemo( DBTAREAP pArea, ULONG ulBlock, PHB_ITEM pItem, ULONG ulLen, ULONG * ulStoredBlock ) { - BYTE pBlock[ DBT_BLOCKSIZE ], pBuff[4]; + BYTE pAddr[4]; BOOL bNewBlock; - ULONG ulNewBlock, ulNextBlock = 0; HB_TRACE(HB_TR_DEBUG, ("hb_dbtWriteMemo(%p, %lu, %p, %lu, %p)", pArea, ulBlock, pItem, ulLen, ulStoredBlock)); - memset( pBlock, 0x1A, DBT_BLOCKSIZE ); bNewBlock = !( ulBlock && ulLen < DBT_BLOCKSIZE - 1 ); if( bNewBlock ) { /* Get next block from header */ hb_fsSeek( pArea->hMemoFile, 0, FS_SET ); - hb_fsRead( pArea->hMemoFile, pBuff, 4 ); - ulNewBlock = HB_GET_LE_UINT32( pBuff ); - ulNextBlock = ulNewBlock * DBT_BLOCKSIZE; - hb_fsSeek( pArea->hMemoFile, ulNextBlock, FS_SET ); + hb_fsRead( pArea->hMemoFile, pAddr, 4 ); + ulBlock = HB_GET_LE_UINT32( pAddr ); + } + * ulStoredBlock = ulBlock; + + hb_fsSeekLarge( pArea->hMemoFile, ( HB_FOFFSET ) ulBlock * DBT_BLOCKSIZE, FS_SET ); +#ifndef HB_CDP_SUPPORT_OFF + if( hb_cdp_page != pArea->cdPage ) + { + BYTE * pBuff = ( BYTE * ) hb_xalloc( ulLen + 1 ); + + if( pBuff ) + { + memcpy( pBuff, pItem->item.asString.value, ulLen ); + pBuff[ ulLen ] = 0x1A; + hb_cdpnTranslate( ( char * ) pBuff, hb_cdp_page, pArea->cdPage, ulLen ); + hb_fsWriteLarge( pArea->hMemoFile, pBuff, ulLen + 1 ); + hb_xfree( pBuff ); + } + else + { + BYTE pBlock[ DBT_BLOCKSIZE ], *pSrc = ( BYTE * ) pItem->item.asString.value; + ULONG ulWritten = 0, ulRest; + + do + { + ulRest = HB_MIN( ulLen - ulWritten, DBT_BLOCKSIZE ); + memcpy( pBlock, pSrc + ulWritten, ulRest ); + memset( pBlock + ulRest, 0x1A, DBT_BLOCKSIZE - ulRest ); + hb_cdpnTranslate( ( char * ) pBlock, hb_cdp_page, pArea->cdPage, ulRest ); + hb_fsWrite( pArea->hMemoFile, pBlock, DBT_BLOCKSIZE ); + ulWritten += DBT_BLOCKSIZE; + } + while ( ulWritten <= ulLen ); + } } else +#endif { - hb_fsSeek( pArea->hMemoFile, ulBlock * DBT_BLOCKSIZE, FS_SET ); - ulNewBlock = ulBlock; + BYTE pBlock[ DBT_BLOCKSIZE ]; + memset( pBlock, 0x1A, DBT_BLOCKSIZE ); + hb_fsWriteLarge( pArea->hMemoFile, ( BYTE * ) pItem->item.asString.value, ulLen ); + hb_fsWrite( pArea->hMemoFile, pBlock, ( DBT_BLOCKSIZE - ( USHORT ) ( ulLen % DBT_BLOCKSIZE ) ) ); } - * ulStoredBlock = ulNewBlock; - -#ifndef HB_CDP_SUPPORT_OFF - hb_cdpnTranslate( pItem->item.asString.value, hb_cdp_page, pArea->cdPage, ulLen ); -#endif - /* Write memo data and eof mark */ - hb_fsWriteLarge( pArea->hMemoFile, ( BYTE * ) pItem->item.asString.value, ulLen ); - hb_fsWrite( pArea->hMemoFile, pBlock, ( DBT_BLOCKSIZE - ( USHORT ) ( ulLen % DBT_BLOCKSIZE ) ) ); pArea->fMemoFlush = TRUE; -#ifndef HB_CDP_SUPPORT_OFF - hb_cdpnTranslate( pItem->item.asString.value, pArea->cdPage, hb_cdp_page, ulLen ); -#endif if( bNewBlock ) { - ulNextBlock += ulLen + 1; - ulNextBlock += ( DBT_BLOCKSIZE - ulNextBlock % DBT_BLOCKSIZE ); - ulNextBlock /= DBT_BLOCKSIZE; - HB_PUT_LE_UINT32( pBuff, ulNextBlock ); + ulBlock += ( ulLen / DBT_BLOCKSIZE ) + 1; + HB_PUT_LE_UINT32( pAddr, ulBlock ); hb_fsSeek( pArea->hMemoFile, 0, FS_SET ); - hb_fsWrite( pArea->hMemoFile, pBuff, 4 ); + hb_fsWrite( pArea->hMemoFile, pAddr, 4 ); pArea->fMemoFlush = TRUE; } } @@ -492,7 +514,33 @@ static ERRCODE hb_dbtInfo( DBTAREAP pArea, USHORT uiIndex, PHB_ITEM pItem ) switch( uiIndex ) { case DBI_MEMOEXT: - hb_itemPutC( pItem, DBT_MEMOEXT ); + if( pArea->fHasMemo && pArea->hMemoFile != FS_ERROR ) + { + PHB_FNAME pFileName; + + pFileName = hb_fsFNameSplit( ( char * ) pArea->szMemoFileName ); + hb_itemPutC( pItem, pFileName->szExtension ); + hb_xfree( pFileName ); + } + else + { + hb_itemClear( pItem ); + return SELF_RDDINFO( SELF_RDDNODE( pArea ), RDDI_MEMOEXT, 0, pItem ); + } + break; + + case DBI_MEMOBLOCKSIZE: + if( pArea->fHasMemo && pArea->hMemoFile != FS_ERROR ) + hb_itemPutNI( pItem, pArea->uiMemoBlockSize ); + else + hb_itemPutNI( pItem, DBT_BLOCKSIZE ); + break; + + case DBI_MEMOTYPE: + if( pArea->fHasMemo && pArea->hMemoFile != FS_ERROR ) + hb_itemPutNI( pItem, pArea->bMemoType ); + else + hb_itemPutNI( pItem, DB_MEMO_DBT ); break; /* case DBI_RDD_VERSION */ @@ -654,7 +702,10 @@ static ERRCODE hb_dbtCreateMemFile( DBTAREAP pArea, LPDBOPENINFO pCreateInfo ) /* Try create */ do { - pArea->hMemoFile = hb_spCreate( pCreateInfo->abName, FC_NORMAL ); + pArea->hMemoFile = hb_fsExtOpen( pCreateInfo->abName, NULL, + FO_READWRITE | FO_EXCLUSIVE | FXO_TRUNCATE | + FXO_DEFAULTS | FXO_SHARELOCK, + NULL, pError ); if( pArea->hMemoFile == FS_ERROR ) { if( !pError ) @@ -711,7 +762,9 @@ static ERRCODE hb_dbtOpenMemFile( DBTAREAP pArea, LPDBOPENINFO pOpenInfo ) /* Try open */ do { - pArea->hMemoFile = hb_spOpen( pOpenInfo->abName, uiFlags ); + pArea->hMemoFile = hb_fsExtOpen( pOpenInfo->abName, NULL, uiFlags | + FXO_DEFAULTS | FXO_SHARELOCK, + NULL, pError ); if( pArea->hMemoFile == FS_ERROR ) { if( !pError ) @@ -738,35 +791,56 @@ static ERRCODE hb_dbtOpenMemFile( DBTAREAP pArea, LPDBOPENINFO pOpenInfo ) return ( pArea->hMemoFile == FS_ERROR ? FAILURE : SUCCESS ); } -/* ( DBENTRYP_SVP ) hb_dbtPutValueFile : NULL */ +/* ( DBENTRYP_SVPB ) hb_dbtPutValueFile : NULL */ /* - * Read the database file header record in the WorkArea. - * ( DBENTRYP_V ) hb_dbtReadDBHeader + * Retrieve (set) information about RDD + * ( DBENTRYP_RSLV ) hb_dbtFieldInfo */ -static ERRCODE hb_dbtReadDBHeader( DBTAREAP pArea ) +static ERRCODE hb_dbtRddInfo( LPRDDNODE pRDD, USHORT uiIndex, ULONG ulConnect, PHB_ITEM pItem ) { - HB_TRACE(HB_TR_DEBUG, ("hb_dbtReadHeader(%p)", pArea)); + HB_TRACE(HB_TR_DEBUG, ("hb_dbtRddInfo(%p, %hu, %lu, %p)", pRDD, uiIndex, ulConnect, pItem)); - if( SUPER_READDBHEADER( ( AREAP ) pArea ) == FAILURE ) - return FAILURE; -// Set in SUPER() now 3/05/2004 -// pArea->fHasMemo = ( pArea->bVersion == 0x83 ); + switch( uiIndex ) + { + case RDDI_MEMOEXT: + { + LPDBFDATA pData = ( LPDBFDATA ) pRDD->lpvCargo; + char *szNew = hb_itemGetCPtr( pItem ); + + if( szNew[0] == '.' && szNew[1] ) + szNew = hb_strdup( szNew ); + else + szNew = NULL; + + hb_itemPutC( pItem, pData->szMemoExt[ 0 ] ? pData->szMemoExt : DBT_MEMOEXT ); + if( szNew ) + { + hb_strncpy( pData->szMemoExt, szNew, HB_MAX_FILE_EXT ); + hb_xfree( szNew ); + } + break; + } + case RDDI_MEMOBLOCKSIZE: + hb_itemPutNI( pItem, DBT_BLOCKSIZE ); + break; + + case RDDI_MEMOTYPE: + hb_itemPutNI( pItem, DB_MEMO_DBT ); + break; + + case RDDI_MEMOGCTYPE: + hb_itemPutNI( pItem, 0 ); + break; + + case RDDI_MEMOREADLOCK: + case RDDI_MEMOREUSE: + hb_itemPutL( pItem, FALSE ); + break; + + default: + return SUPER_RDDINFO( pRDD, uiIndex, ulConnect, pItem ); + } return SUCCESS; } - -/* - * Write the database file header record in the WorkArea. - * ( DBENTRYP_V ) hb_dbtWriteDBHeader - */ -static ERRCODE hb_dbtWriteDBHeader( DBTAREAP pArea ) -{ - HB_TRACE(HB_TR_DEBUG, ("hb_dbtWriteDBHeader(%p)", pArea)); - - if ( pArea->fHasMemo && pArea->bVersion != 0x30 && pArea->bVersion != 0x31 ) - { - pArea->bVersion = 0x83; - } - return SUPER_WRITEDBHEADER( ( AREAP ) pArea ); -} diff --git a/harbour/source/rdd/dbffpt/Makefile b/harbour/source/rdd/dbffpt/Makefile index ec5012384e..a12a0f0d05 100644 --- a/harbour/source/rdd/dbffpt/Makefile +++ b/harbour/source/rdd/dbffpt/Makefile @@ -10,6 +10,10 @@ C_SOURCES=\ PRG_SOURCES=\ dbffpt0.prg \ +ifeq ($(HB_MT),MT) + MT_LIBNAME=dbffptmt +endif + LIBNAME=dbffpt include $(TOP)$(ROOT)config/lib.cf diff --git a/harbour/source/rdd/dbffpt/dbffpt0.prg b/harbour/source/rdd/dbffpt/dbffpt0.prg index 578f2c4d18..135e50d632 100644 --- a/harbour/source/rdd/dbffpt/dbffpt0.prg +++ b/harbour/source/rdd/dbffpt/dbffpt0.prg @@ -56,9 +56,14 @@ ANNOUNCE DBFFPT procedure DBFFPTInit + REQUEST _DBF REQUEST _DBFFPT rddRegister( "DBF", RDT_FULL ) rddRegister( "DBFFPT", RDT_FULL ) return + +/* to satisfy old code which has: REQUEST DBFDBT */ +proc DBFDBT +return diff --git a/harbour/source/rdd/dbffpt/dbffpt1.c b/harbour/source/rdd/dbffpt/dbffpt1.c index 797c330e45..8759d307cd 100644 --- a/harbour/source/rdd/dbffpt/dbffpt1.c +++ b/harbour/source/rdd/dbffpt/dbffpt1.c @@ -54,12 +54,11 @@ * If you do not wish that, delete this exception notice. * */ -#if defined( HB_FPT_NO_READLOCK ) && !defined( HB_FPT_USE_READLOCK ) - #define HB_FPT_USE_READLOCK -#endif -#ifndef HB_FPT_USE_READLOCK - #define HB_FPT_SAFE +#if defined( HB_FPT_NO_READLOCK ) +# undef HB_MEMO_SAFELOCK +#else +/*# define HB_MEMO_SAFELOCK */ #endif #include "hbapi.h" @@ -67,8 +66,10 @@ #include "hbapierr.h" #include "hbapilng.h" #include "hbset.h" +#include "hbvm.h" #include "hbdate.h" #include "hbrddfpt.h" +#include "hbsxfunc.h" #ifndef HB_CDP_SUPPORT_OFF # include "hbapicdp.h" @@ -121,7 +122,8 @@ static RDDFUNCS fptTable = ( DBENTRYP_V ) hb_fptRecall, ( DBENTRYP_ULP ) hb_fptRecCount, ( DBENTRYP_ISI ) hb_fptRecInfo, - ( DBENTRYP_I ) hb_fptRecNo, + ( DBENTRYP_ULP ) hb_fptRecNo, + ( DBENTRYP_I ) hb_fptRecId, ( DBENTRYP_S ) hb_fptSetFieldExtent, @@ -163,7 +165,7 @@ static RDDFUNCS fptTable = ( DBENTRYP_OI ) hb_fptOrderListAdd, ( DBENTRYP_V ) hb_fptOrderListClear, - ( DBENTRYP_VP ) hb_fptOrderListDelete, + ( DBENTRYP_OI ) hb_fptOrderListDelete, ( DBENTRYP_OI ) hb_fptOrderListFocus, ( DBENTRYP_V ) hb_fptOrderListRebuild, ( DBENTRYP_VOI ) hb_fptOrderCondition, @@ -184,6 +186,7 @@ static RDDFUNCS fptTable = ( DBENTRYP_VLO ) hb_fptSetLocate, ( DBENTRYP_VOS ) hb_fptSetScope, ( DBENTRYP_VPL ) hb_fptSkipScope, + ( DBENTRYP_B ) hb_fptLocate, /* Miscellaneous */ @@ -197,7 +200,7 @@ static RDDFUNCS fptTable = ( DBENTRYP_VSP ) hb_fptRawLock, ( DBENTRYP_VL ) hb_fptLock, - ( DBENTRYP_UL ) hb_fptUnLock, + ( DBENTRYP_I ) hb_fptUnLock, /* Memofile functions */ @@ -206,7 +209,7 @@ static RDDFUNCS fptTable = ( DBENTRYP_VP ) hb_fptCreateMemFile, ( DBENTRYP_SVPB ) hb_fptGetValueFile, ( DBENTRYP_VP ) hb_fptOpenMemFile, - ( DBENTRYP_SVP ) hb_fptPutValueFile, + ( DBENTRYP_SVPB ) hb_fptPutValueFile, /* Database file header handling */ @@ -216,16 +219,17 @@ static RDDFUNCS fptTable = /* non WorkArea functions */ - ( DBENTRYP_I0 ) hb_fptExit, - ( DBENTRYP_I1 ) hb_fptDrop, - ( DBENTRYP_I2 ) hb_fptExists, + ( DBENTRYP_R ) hb_fptInit, + ( DBENTRYP_R ) hb_fptExit, + ( DBENTRYP_RVV ) hb_fptDrop, + ( DBENTRYP_RVV ) hb_fptExists, + ( DBENTRYP_RSLV ) hb_fptRddInfo, /* Special and reserved methods */ ( DBENTRYP_SVP ) hb_fptWhoCares }; - HB_FUNC( _DBFFPT ) {;} HB_FUNC( DBFFPT_GETFUNCTABLE ) @@ -254,9 +258,9 @@ HB_INIT_SYMBOLS_BEGIN( dbffpt1__InitSymbols ) { "DBFFPT_GETFUNCTABLE", HB_FS_PUBLIC, {HB_FUNCNAME( DBFFPT_GETFUNCTABLE )}, NULL } HB_INIT_SYMBOLS_END( dbffpt1__InitSymbols ) -#if defined(HB_STATIC_STARTUP) +#if defined(HB_PRAGMA_STARTUP) # pragma startup dbffpt1__InitSymbols -#elif defined(_MSC_VER) +#elif defined(HB_MSC_STARTUP) # if _MSC_VER >= 1010 # pragma data_seg( ".CRT$XIY" ) # pragma comment( linker, "/Merge:.CRT=.data" ) @@ -265,66 +269,53 @@ HB_INIT_SYMBOLS_END( dbffpt1__InitSymbols ) # endif static HB_$INITSYM hb_vm_auto_dbffpt1__InitSymbols = dbffpt1__InitSymbols; # pragma data_seg() -#elif ! defined(__GNUC__) -# pragma startup dbffpt1__InitSymbols #endif - -static ERRCODE hb_fptIsDbLocked( FPTAREAP pArea, BOOL *bLocked ) -{ - HB_ITEM recItm = HB_ITEM_NIL, resultItm = HB_ITEM_NIL; - - if ( pArea->fShared && !pArea->fFLocked && !pArea->fRecordChanged ) - { - if ( SELF_RECINFO( ( AREAP ) pArea, &recItm, DBRI_LOCKED, &resultItm ) == FAILURE ) - return FAILURE; - *bLocked = hb_itemGetL( &resultItm ); - } - else - *bLocked = TRUE; - - return SUCCESS; -} -#if defined( HB_FPT_USE_READLOCK ) -/* - * Read Lock for Memo - */ -static BOOL hb_fptReadLock( FPTAREAP pArea, ULONG uiIndex, ULONG *pulOffset ) -{ - BOOL fRet= TRUE ; -#ifndef HB_FPT_NO_READLOCK - if ( pArea->fShared && !pArea->fFLocked ) // and we are not open EXCLUSIVE or FILELOCKED - { - *pulOffset = pArea->uiMemoBlockSize * hb_dbfGetMemoBlock( (DBFAREAP) pArea, uiIndex - 1 ) ; - if ( *pulOffset ) // There is something in the memo so lock it - { - do - { - fRet = hb_fsLock( pArea->hMemoFile, *pulOffset, pArea->uiMemoBlockSize, - FL_LOCK | FLX_SHARED | FLX_WAIT ); - } while ( !fRet ); - } - } - else -#endif - { - *pulOffset = 0 ; - } - return fRet ; -} - /* - * Read UnLock for Memo + * generate Run-Time error */ -static BOOL hb_fptReadUnLock( FPTAREAP pArea, ULONG ulOffset ) +static ERRCODE hb_memoErrorRT( FPTAREAP pArea, USHORT uiGenCode, USHORT uiSubCode, char * szFileName, USHORT uiOsCode, USHORT uiFlags ) { - if ( ulOffset ) + ERRCODE errCode = FAILURE; + + if( hb_vmRequestQuery() == 0 ) { - hb_fsLock( pArea->hMemoFile, ulOffset, pArea->uiMemoBlockSize, FL_UNLOCK ); + PHB_ITEM pError = hb_errNew(); + + if( uiGenCode == 0 ) + uiGenCode = hb_dbfGetEGcode( uiSubCode ); + if( uiOsCode == 0 && uiSubCode != EDBF_DATATYPE && uiSubCode != EDBF_DATAWIDTH ) + uiOsCode = hb_fsError(); + + hb_errPutGenCode( pError, uiGenCode ); + hb_errPutSubCode( pError, uiSubCode ); + if( uiOsCode ) + hb_errPutOsCode( pError, uiOsCode ); + hb_errPutDescription( pError, hb_langDGetErrorDesc( uiGenCode ) ); + if( szFileName ) + hb_errPutFileName( pError, szFileName ); + if( uiFlags ) + hb_errPutFlags( pError, uiFlags ); + errCode = SELF_ERROR( ( AREAP ) pArea, pError ); + hb_errRelease( pError ); } - return TRUE ; + return errCode; +} + + +static char * hb_memoDefaultFileExt( int iType ) +{ + switch( iType ) + { + case DB_MEMO_DBT: + return DBT_MEMOEXT; + case DB_MEMO_FPT: + return FPT_MEMOEXT; + case DB_MEMO_SMT: + return SMT_MEMOEXT; + } + return NULL; } -#endif /* * Exclusive lock memo file. @@ -570,18 +561,23 @@ static ERRCODE hb_fptWriteGCitems( FPTAREAP pArea, LPMEMOGCTABLE pGCtable, USHOR { if ( pGCtable->pGCitems[i].fChanged ) { - HB_PUT_BE_UINT32( fptBlock.type, FPTIT_FLEX_UNUSED ); - HB_PUT_BE_UINT32( fptBlock.size, pArea->uiMemoBlockSize * - pGCtable->pGCitems[i].ulSize - sizeof( FPTBLOCK ) ); - hb_fsSeek( pArea->hMemoFile, pGCtable->pGCitems[i].ulOffset * - pArea->uiMemoBlockSize, FS_SET ); - if ( hb_fsWrite( pArea->hMemoFile, ( BYTE * ) &fptBlock, - sizeof( FPTBLOCK ) ) != sizeof( FPTBLOCK ) ) + if( pArea->uiMemoVersion == DB_MEMOVER_FLEX || + pArea->uiMemoVersion == DB_MEMOVER_CLIP ) { - errCode = EDBF_WRITE; + HB_PUT_BE_UINT32( fptBlock.type, FPTIT_FLEX_UNUSED ); + HB_PUT_BE_UINT32( fptBlock.size, pArea->uiMemoBlockSize * + pGCtable->pGCitems[i].ulSize - sizeof( FPTBLOCK ) ); + hb_fsSeekLarge( pArea->hMemoFile, + ( HB_FOFFSET ) pGCtable->pGCitems[i].ulOffset * + ( HB_FOFFSET ) pArea->uiMemoBlockSize, FS_SET ); + if ( hb_fsWrite( pArea->hMemoFile, ( BYTE * ) &fptBlock, + sizeof( FPTBLOCK ) ) != sizeof( FPTBLOCK ) ) + { + errCode = EDBF_WRITE; + } + pArea->fMemoFlush = TRUE; } pGCtable->pGCitems[i].fChanged = FALSE; - pArea->fMemoFlush = TRUE; } } return errCode; @@ -591,30 +587,38 @@ static ERRCODE hb_fptWriteGCitems( FPTAREAP pArea, LPMEMOGCTABLE pGCtable, USHOR * Add new block to GC free memo blocks list. */ static ERRCODE hb_fptGCfreeBlock( FPTAREAP pArea, LPMEMOGCTABLE pGCtable, - ULONG ulOffset, ULONG ulByteSize ) + ULONG ulOffset, ULONG ulByteSize, BOOL fRaw ) { ERRCODE errCode = SUCCESS; ULONG ulSize; - if ( ulByteSize == 0 ) + if( pArea->bMemoType == DB_MEMO_DBT ) { - FPTBLOCK fptBlock; - - hb_fsSeek( pArea->hMemoFile, ulOffset * pArea->uiMemoBlockSize, FS_SET ); - if( hb_fsRead( pArea->hMemoFile, ( BYTE * ) &fptBlock, - sizeof( FPTBLOCK ) ) == sizeof( FPTBLOCK ) ) - { - ulByteSize = HB_GET_BE_UINT32( fptBlock.size ) + sizeof( FPTBLOCK ); - } + return SUCCESS; } - else + else if( pArea->bMemoType == DB_MEMO_FPT && !fRaw ) { - ulByteSize += sizeof( FPTBLOCK ); + if( ulByteSize == 0 ) + { + FPTBLOCK fptBlock; + + hb_fsSeekLarge( pArea->hMemoFile, ( HB_FOFFSET ) ulOffset * + ( HB_FOFFSET ) pArea->uiMemoBlockSize, FS_SET ); + if( hb_fsRead( pArea->hMemoFile, ( BYTE * ) &fptBlock, + sizeof( FPTBLOCK ) ) == sizeof( FPTBLOCK ) ) + { + ulByteSize = HB_GET_BE_UINT32( fptBlock.size ) + sizeof( FPTBLOCK ); + } + } + else + { + ulByteSize += sizeof( FPTBLOCK ); + } } ulSize = ( ulByteSize + pArea->uiMemoBlockSize - 1 ) / pArea->uiMemoBlockSize; - if ( ulByteSize == 0 ) + if( ulSize == 0 ) { return EDBF_CORRUPT; } @@ -692,14 +696,34 @@ static ERRCODE hb_fptGCfreeBlock( FPTAREAP pArea, LPMEMOGCTABLE pGCtable, * Get free memo block from GC free memo blocks list or allocate new one. */ static ERRCODE hb_fptGCgetFreeBlock( FPTAREAP pArea, LPMEMOGCTABLE pGCtable, - ULONG * ulOffset, ULONG ulByteSize ) + ULONG * ulOffset, ULONG ulByteSize, + BOOL fRaw ) { BOOL fAlloc = FALSE; ULONG ulSize; int i; - ulSize = ( ulByteSize + sizeof( FPTBLOCK ) + pArea->uiMemoBlockSize - 1 ) / - pArea->uiMemoBlockSize; + + if( pArea->bMemoType == DB_MEMO_SMT || fRaw ) + { + ulSize = ( ulByteSize + pArea->uiMemoBlockSize - 1 ) / + pArea->uiMemoBlockSize; + } + else if( pArea->bMemoType == DB_MEMO_FPT ) + { + ulSize = ( ulByteSize + sizeof( FPTBLOCK ) + pArea->uiMemoBlockSize - 1 ) / + pArea->uiMemoBlockSize; + } + else if( pArea->bMemoType == DB_MEMO_DBT ) + { + ulSize = ( ulByteSize + pArea->uiMemoBlockSize ) / + pArea->uiMemoBlockSize; + } + else + { + ulSize = ( ulByteSize + pArea->uiMemoBlockSize - 1 ) / + pArea->uiMemoBlockSize; + } for( i = 0; i < pGCtable->usItems; i++ ) { @@ -771,12 +795,16 @@ static ERRCODE hb_fptReadGCdata( FPTAREAP pArea, LPMEMOGCTABLE pGCtable ) hb_fsSeek( pArea->hMemoFile, 0, FS_SET ); if ( hb_fsRead( pArea->hMemoFile, ( BYTE * ) &pGCtable->fptHeader, sizeof( FPTHEADER ) ) >= 512 ) { - pGCtable->ulNextBlock = HB_GET_BE_UINT32( pGCtable->fptHeader.nextBlock ); + if( pArea->bMemoType == DB_MEMO_SMT || pArea->bMemoType == DB_MEMO_DBT ) + pGCtable->ulNextBlock = HB_GET_LE_UINT32( pGCtable->fptHeader.nextBlock ); + else + pGCtable->ulNextBlock = HB_GET_BE_UINT32( pGCtable->fptHeader.nextBlock ); + pGCtable->ulPrevBlock = pGCtable->ulNextBlock; - if ( pArea->bMemoType == MEMO_FPT_SIX || - pArea->bMemoType == MEMO_FPT_SIXHB ) + if ( pArea->uiMemoVersion == DB_MEMOVER_SIX || + pArea->bMemoType == DB_MEMO_SMT ) { - pGCtable->bType = MEMO_FPT_SIX; + pGCtable->bType = DB_MEMOVER_SIX; pGCtable->usMaxItem = MAX_SIXFREEBLOCKS; pGCtable->usItems = HB_GET_LE_UINT16( pGCtable->fptHeader.nGCitems ); if ( pGCtable->usItems > pGCtable->usMaxItem ) @@ -793,14 +821,14 @@ static ERRCODE hb_fptReadGCdata( FPTAREAP pArea, LPMEMOGCTABLE pGCtable ) pGCtable->pGCitems[i].fChanged = FALSE; } } - else if ( pArea->bMemoType == MEMO_FPT_FLEX || - pArea->bMemoType == MEMO_FPT_HB || - pArea->bMemoType == MEMO_FPT_CLIP ) + else if( pArea->bMemoType == DB_MEMO_FPT && + ( pArea->uiMemoVersion == DB_MEMOVER_FLEX || + pArea->uiMemoVersion == DB_MEMOVER_CLIP ) ) { FPTBLOCK fptBlock; BYTE *bPageBuf; - pGCtable->bType = MEMO_FPT_FLEX; + pGCtable->bType = DB_MEMOVER_FLEX; pGCtable->usMaxItem = MAX_FLEXFREEBLOCKS; pGCtable->ulRevPage = HB_GET_LE_UINT32( pGCtable->fptHeader.flexRev ); pGCtable->ulDirPage = HB_GET_LE_UINT32( pGCtable->fptHeader.flexDir ); @@ -861,7 +889,7 @@ static ERRCODE hb_fptWriteGCdata( FPTAREAP pArea, LPMEMOGCTABLE pGCtable ) if ( pGCtable->bChanged > 0 ) { - if ( pGCtable->bType == MEMO_FPT_SIX ) + if ( pGCtable->bType == DB_MEMOVER_SIX ) { USHORT usItems = HB_MIN( pGCtable->usItems, pGCtable->usMaxItem ); HB_PUT_LE_UINT16( pGCtable->fptHeader.nGCitems, usItems ); @@ -875,7 +903,7 @@ static ERRCODE hb_fptWriteGCdata( FPTAREAP pArea, LPMEMOGCTABLE pGCtable ) pGCtable->pGCitems[i].ulOffset ); } } - else if ( pGCtable->bType == MEMO_FPT_FLEX ) + else if ( pGCtable->bType == DB_MEMOVER_FLEX ) { ulHdrSize = sizeof( FPTHEADER ); pGCtable->ulCounter++; @@ -903,12 +931,12 @@ static ERRCODE hb_fptWriteGCdata( FPTAREAP pArea, LPMEMOGCTABLE pGCtable ) { pGCtable->ulSize = FLEXGCPAGE_SIZE; errCode = hb_fptGCgetFreeBlock( pArea, pGCtable, - &pGCtable->ulDirPage, pGCtable->ulSize ); + &pGCtable->ulDirPage, pGCtable->ulSize, FALSE ); if ( errCode == SUCCESS ) { pGCtable->ulDirPage *= pArea->uiMemoBlockSize; errCode = hb_fptGCgetFreeBlock( pArea, pGCtable, - &pGCtable->ulRevPage, pGCtable->ulSize ); + &pGCtable->ulRevPage, pGCtable->ulSize, FALSE ); pGCtable->ulRevPage *= pArea->uiMemoBlockSize; } pGCtable->bChanged |= 2; @@ -971,16 +999,21 @@ static ERRCODE hb_fptWriteGCdata( FPTAREAP pArea, LPMEMOGCTABLE pGCtable ) } if ( errCode == SUCCESS ) { - HB_PUT_BE_UINT32( pGCtable->fptHeader.nextBlock, pGCtable->ulNextBlock ); + if( pArea->bMemoType == DB_MEMO_SMT || pArea->bMemoType == DB_MEMO_DBT ) + HB_PUT_LE_UINT32( pGCtable->fptHeader.nextBlock, pGCtable->ulNextBlock ); + else + HB_PUT_BE_UINT32( pGCtable->fptHeader.nextBlock, pGCtable->ulNextBlock ); hb_fsSeek( pArea->hMemoFile, 0, FS_SET ); - if ( hb_fsWrite( pArea->hMemoFile, ( BYTE * ) &pGCtable->fptHeader, ( USHORT )ulHdrSize ) != ( USHORT ) ulHdrSize ) + if( hb_fsWrite( pArea->hMemoFile, ( BYTE * ) &pGCtable->fptHeader, ( USHORT )ulHdrSize ) != ( USHORT ) ulHdrSize ) { errCode = EDBF_WRITE; } - else + else if( pGCtable->ulNextBlock < pGCtable->ulPrevBlock ) { /* trunc file */ - hb_fsSeek( pArea->hMemoFile, pGCtable->ulNextBlock * pArea->uiMemoBlockSize, FS_SET ); + hb_fsSeekLarge( pArea->hMemoFile, + ( HB_FOFFSET ) pGCtable->ulNextBlock * + ( HB_FOFFSET ) pArea->uiMemoBlockSize, FS_SET ); hb_fsWrite( pArea->hMemoFile, NULL, 0 ); } } @@ -995,23 +1028,45 @@ static ERRCODE hb_fptWriteGCdata( FPTAREAP pArea, LPMEMOGCTABLE pGCtable ) */ static ULONG hb_fptGetMemoLen( FPTAREAP pArea, USHORT uiIndex ) { - ULONG ulBlock; + ULONG ulBlock, ulSize, ulType; FPTBLOCK fptBlock; HB_TRACE(HB_TR_DEBUG, ("hb_fptGetMemoLen(%p, %hu)", pArea, uiIndex)); - ulBlock = hb_dbfGetMemoBlock( (DBFAREAP) pArea, uiIndex ); + if( hb_dbfGetMemoData( ( DBFAREAP ) pArea, uiIndex, &ulBlock, &ulSize, + &ulType ) == SUCCESS ) + { + if( ulBlock != 0 ) + { + if( ulSize == 0 && ( pArea->bMemoType == DB_MEMO_DBT || + pArea->bMemoType == DB_MEMO_FPT ) ) + { + hb_fsSeekLarge( pArea->hMemoFile, ( HB_FOFFSET ) ulBlock * + ( HB_FOFFSET ) pArea->uiMemoBlockSize, FS_SET ); + if( pArea->bMemoType == DB_MEMO_DBT ) + { + BYTE pBlock[ DBT_DEFBLOCKSIZE ]; + int iLen, i; - if( ulBlock == 0 ) - return 0; - - hb_fsSeek( pArea->hMemoFile, ulBlock * pArea->uiMemoBlockSize, FS_SET ); - - if( hb_fsRead( pArea->hMemoFile, ( BYTE * ) &fptBlock, - sizeof( FPTBLOCK ) ) != sizeof( FPTBLOCK ) ) - return 0; - - return HB_GET_BE_UINT32( fptBlock.size ); + do + { + iLen = hb_fsRead( pArea->hMemoFile, pBlock, DBT_DEFBLOCKSIZE ); + if( iLen <= 0 ) + break; + i = 0; + while( i < iLen && pBlock[ i ] != 0x1A ) + i++; + ulSize += i; + } while( i == DBT_DEFBLOCKSIZE ); + } + else if( hb_fsRead( pArea->hMemoFile, ( BYTE * ) &fptBlock, + sizeof( FPTBLOCK ) ) == sizeof( FPTBLOCK ) ) + ulSize = HB_GET_BE_UINT32( fptBlock.size ); + } + return ulSize; + } + } + return 0; } /* @@ -1019,72 +1074,655 @@ static ULONG hb_fptGetMemoLen( FPTAREAP pArea, USHORT uiIndex ) */ static char * hb_fptGetMemoType( FPTAREAP pArea, USHORT uiIndex ) { - ULONG ulBlock, ulType; + ULONG ulBlock, ulSize, ulType; FPTBLOCK fptBlock; HB_TRACE(HB_TR_DEBUG, ("hb_fptGetMemoLen(%p, %hu)", pArea, uiIndex)); - ulBlock = hb_dbfGetMemoBlock( (DBFAREAP) pArea, uiIndex ); - - if( ulBlock == 0 ) - return "C"; - - hb_fsSeek( pArea->hMemoFile, ulBlock * pArea->uiMemoBlockSize, FS_SET ); - - if( hb_fsRead( pArea->hMemoFile, ( BYTE * ) &fptBlock, - sizeof( FPTBLOCK ) ) != sizeof( FPTBLOCK ) ) - return "U"; - - ulType = HB_GET_BE_UINT32( fptBlock.type ); - - switch ( ulType ) + if( hb_dbfGetMemoData( ( DBFAREAP ) pArea, uiIndex, &ulBlock, &ulSize, + &ulType ) == SUCCESS ) { - case FPTIT_SIX_LNUM: - case FPTIT_SIX_DNUM: - return "N"; - case FPTIT_SIX_LDATE: - return "D"; - case FPTIT_SIX_LOG: - return "L"; - case FPTIT_SIX_CHAR: - return "M"; - case FPTIT_SIX_ARRAY: - return "A"; -// case FPTIT_SIX_BLOCK: -// case FPTIT_SIX_VREF: -// case FPTIT_SIX_MREF: + if( ulBlock != 0 ) + { + if( ulType == 0 && pArea->bMemoType == DB_MEMO_FPT ) + { + hb_fsSeekLarge( pArea->hMemoFile, ( HB_FOFFSET ) ulBlock * + ( HB_FOFFSET ) pArea->uiMemoBlockSize, FS_SET ); + if( hb_fsRead( pArea->hMemoFile, ( BYTE * ) &fptBlock, + sizeof( FPTBLOCK ) ) != sizeof( FPTBLOCK ) ) + return "U"; + ulType = HB_GET_BE_UINT32( fptBlock.type ); + } + } - case FPTIT_FLEX_ARRAY: - case FPTIT_FLEX_VOARR: - return "A"; - case FPTIT_FLEX_OBJECT: - case FPTIT_FLEX_VOOBJ: - return "O"; - case FPTIT_FLEX_NIL: - return "U"; - case FPTIT_FLEX_TRUE: - case FPTIT_FLEX_FALSE: - return "L"; - case FPTIT_FLEX_LDATE: - return "D"; - case FPTIT_FLEX_CHAR: - case FPTIT_FLEX_UCHAR: - case FPTIT_FLEX_SHORT: - case FPTIT_FLEX_USHORT: - case FPTIT_FLEX_LONG: - case FPTIT_FLEX_ULONG: - case FPTIT_FLEX_DOUBLE: - case FPTIT_FLEX_LDOUBLE: - return "N"; - case FPTIT_TEXT: + if( ulType == 0 ) return "M"; - case FPTIT_PICT: - case FPTIT_FLEX_COMPCH: - return "C"; + + if( pArea->bMemoType == DB_MEMO_FPT ) + { + switch ( ulType ) + { + case FPTIT_SIX_LNUM: + case FPTIT_SIX_DNUM: + return "N"; + case FPTIT_SIX_LDATE: + return "D"; + case FPTIT_SIX_LOG: + return "L"; + case FPTIT_SIX_CHAR: + return "M"; + case FPTIT_SIX_ARRAY: + return "A"; +// case FPTIT_SIX_BLOCK: +// case FPTIT_SIX_VREF: +// case FPTIT_SIX_MREF: + + case FPTIT_FLEX_ARRAY: + case FPTIT_FLEX_VOARR: + return "A"; + case FPTIT_FLEX_OBJECT: + case FPTIT_FLEX_VOOBJ: + return "O"; + case FPTIT_FLEX_NIL: + return "U"; + case FPTIT_FLEX_TRUE: + case FPTIT_FLEX_FALSE: + return "L"; + case FPTIT_FLEX_LDATE: + return "D"; + case FPTIT_FLEX_CHAR: + case FPTIT_FLEX_UCHAR: + case FPTIT_FLEX_SHORT: + case FPTIT_FLEX_USHORT: + case FPTIT_FLEX_LONG: + case FPTIT_FLEX_ULONG: + case FPTIT_FLEX_DOUBLE: + case FPTIT_FLEX_LDOUBLE: + return "N"; + case FPTIT_TEXT: + return "M"; + case FPTIT_PICT: + case FPTIT_FLEX_COMPRCH: + return "C"; + } + return "U"; + } + else if( pArea->bMemoType == DB_MEMO_SMT ) + { + switch ( ulType ) + { + case SMT_IT_NIL: + return "U"; + case SMT_IT_CHAR: + return "M"; + case SMT_IT_INT: + case SMT_IT_DOUBLE: + return "N"; + case SMT_IT_DATE: + return "D"; + case SMT_IT_LOGICAL: + return "L"; + case SMT_IT_ARRAY: + return "A"; + } + return "U"; + } + return "M"; } + return "U"; } +/* + * Calculate the size of SMT memo item + */ +static ULONG hb_fptCountSMTItemLength( FPTAREAP pArea, PHB_ITEM pItem, + ULONG * pulArrayCount ) +{ + ULONG ulLen, i, ulSize; + USHORT usType; + + usType = hb_itemType( pItem ); + switch( usType ) + { + case HB_IT_ARRAY: // HB_IT_OBJECT = HB_IT_ARRAY + (*pulArrayCount)++; + ulSize = 3; + ulLen = hb_arrayLen( pItem ); + if( ulLen > 0xFFFF ) + ulLen = 0xFFFF; + for( i = 1 ; i <= ulLen ; i++ ) + { + ulSize += hb_fptCountSMTItemLength( pArea, hb_arrayGetItemPtr( pItem, i ), pulArrayCount ); + } + break; + case HB_IT_MEMO: + case HB_IT_STRING: + ulSize = 3 + HB_MIN( pItem->item.asString.length, 0xFFFF ); + break; + case HB_IT_LOGICAL: + ulSize = 2; + break; + case HB_IT_DATE: + ulSize = 5; + break; + case HB_IT_INTEGER: + case HB_IT_LONG: + { + HB_LONG iVal; + iVal = hb_itemGetNInt( pItem ); + if ( HB_LIM_INT32( iVal ) ) + { + ulSize = 5; + break; + } + } + case HB_IT_DOUBLE: + ulSize = 11; + break; + case HB_IT_NIL: + default: + ulSize = 1; + } + return ulSize; +} + +/* + * Calculate the size of SMT memo data + */ +static ERRCODE hb_fptCountSMTDataLength( FPTAREAP pArea, ULONG * ulLen ) +{ + USHORT i, uiSize; + BYTE buffer[ 2 ]; + + if( hb_fsRead( pArea->hMemoFile, buffer, 1 ) != 1 ) + return EDBF_READ; + + *ulLen += 1; + switch( buffer[ 0 ] ) + { + case SMT_IT_ARRAY: + if( hb_fsRead( pArea->hMemoFile, buffer, 2 ) != 2 ) + return EDBF_READ; + + uiSize = HB_GET_LE_UINT16( buffer ); + for( i = 0; i < uiSize; i++ ) + { + ERRCODE errCode = hb_fptCountSMTDataLength( pArea, ulLen ); + if( errCode != SUCCESS ) + return errCode; + } + break; + + case SMT_IT_CHAR: + if( hb_fsRead( pArea->hMemoFile, buffer, 2 ) != 2 ) + return EDBF_READ; + uiSize = HB_GET_LE_UINT16( buffer ); + *ulLen += uiSize; + hb_fsSeek( pArea->hMemoFile, uiSize, FS_RELATIVE ); + break; + + case SMT_IT_INT: + case SMT_IT_DATE: + *ulLen += 4; + hb_fsSeek( pArea->hMemoFile, 4, FS_RELATIVE ); + break; + + case SMT_IT_DOUBLE: + *ulLen += 10; + hb_fsSeek( pArea->hMemoFile, 10, FS_RELATIVE ); + break; + + case SMT_IT_LOGICAL: + *ulLen += 1; + hb_fsSeek( pArea->hMemoFile, 1, FS_RELATIVE ); + break; + + case SMT_IT_NIL: + break; + + default: + return EDBF_CORRUPT; + } + + return SUCCESS; +} + +/* + * Write VM item as SMT memos. + */ +static ULONG hb_fptStoreSMTItem( FPTAREAP pArea, PHB_ITEM pItem, BYTE ** bBufPtr ) +{ + ULONG ulLen, i, ulSize = 0; + HB_LONG iVal; + double dVal; + int iWidth, iDec; + + switch( hb_itemType( pItem ) ) + { + case HB_IT_ARRAY: + *(*bBufPtr)++ = SMT_IT_ARRAY; + ulLen = hb_arrayLen( pItem ); + if( ulLen > 0xFFFF ) + ulLen = 0xFFFF; + HB_PUT_LE_UINT16( *bBufPtr, ulLen ); + *bBufPtr += 2; + for( i = 1 ; i <= ulLen ; i++ ) + { + ulSize += hb_fptStoreSMTItem( pArea, hb_arrayGetItemPtr( pItem, i ), + bBufPtr ); + } + break; + + case HB_IT_STRING: + case HB_IT_MEMO: + *(*bBufPtr)++ = SMT_IT_CHAR; + ulLen = HB_MIN( pItem->item.asString.length, 0xFFFF ); + HB_PUT_LE_UINT16( *bBufPtr, ulLen ); + *bBufPtr += 2; + if ( ulLen > 0 ) + { + memcpy( *bBufPtr, pItem->item.asString.value, ulLen ); +#ifndef HB_CDP_SUPPORT_OFF + hb_cdpnTranslate( ( char *) *bBufPtr, hb_cdp_page, pArea->cdPage, ulLen ); +#endif + *bBufPtr += ulLen; + } + break; + + case HB_IT_INTEGER: + case HB_IT_LONG: + iVal = hb_itemGetNInt( pItem ); + if( HB_LIM_INT32( iVal ) ) + { + *(*bBufPtr)++ = SMT_IT_INT; + HB_PUT_LE_UINT32( *bBufPtr, iVal ); + *bBufPtr += 4; + break; + } + case HB_IT_DOUBLE: + dVal = hb_itemGetND( pItem ); + hb_itemGetNLen( pItem, &iWidth, &iDec ); + if( iDec ) + iWidth += iDec + 1; + *(*bBufPtr)++ = SMT_IT_DOUBLE; + *(*bBufPtr)++ = ( BYTE ) iWidth; + *(*bBufPtr)++ = ( BYTE ) iDec; + HB_PUT_LE_DOUBLE( *bBufPtr, dVal ); + *bBufPtr += 8; + break; + + case HB_IT_DATE: + *(*bBufPtr)++ = SMT_IT_DATE; + HB_PUT_LE_UINT32( *bBufPtr, pItem->item.asDate.value ); + *bBufPtr += 4; + break; + + case HB_IT_LOGICAL: + *(*bBufPtr)++ = SMT_IT_LOGICAL; + *(*bBufPtr)++ = pItem->item.asLogical.value ? 1 : 0; + break; + + case HB_IT_NIL: + default: + *(*bBufPtr)++ = SMT_IT_NIL; + break; + } + return ulSize; +} + +/* + * Read SMT item from file + */ +static ERRCODE hb_fptReadRawSMTItem( FPTAREAP pArea, PHB_ITEM pItem ) +{ + ULONG ulLen, i; + BYTE buffer[ 10 ], *pBuffer; + int iWidth, iDec; + + if( hb_fsRead( pArea->hMemoFile, buffer, 1 ) != 1 ) + return EDBF_READ; + + switch( buffer[ 0 ] ) + { + case SMT_IT_ARRAY: + if( hb_fsRead( pArea->hMemoFile, buffer, 2 ) != 2 ) + return EDBF_READ; + + ulLen = HB_GET_LE_UINT16( buffer ); + hb_arrayNew( pItem, ulLen ); + for( i = 1 ; i <= ulLen ; i++ ) + { + ERRCODE errCode = hb_fptReadRawSMTItem( pArea, hb_arrayGetItemPtr( pItem, i ) ); + if ( errCode != SUCCESS ) + return errCode; + } + break; + + case SMT_IT_CHAR: + if( hb_fsRead( pArea->hMemoFile, buffer, 2 ) != 2 ) + return EDBF_READ; + ulLen = HB_GET_LE_UINT16( buffer ); + pBuffer = ( BYTE * ) hb_xgrab( ulLen + 1 ); + if( hb_fsRead( pArea->hMemoFile, pBuffer, ulLen ) != ( USHORT ) ulLen ) + { + hb_xfree( pBuffer ); + return EDBF_READ; + } +#ifndef HB_CDP_SUPPORT_OFF + hb_cdpnTranslate( ( char *) pBuffer, pArea->cdPage, hb_cdp_page, ulLen ); +#endif + hb_itemPutCPtr( pItem, ( char *) pBuffer, ulLen ); + break; + + case SMT_IT_INT: + if( hb_fsRead( pArea->hMemoFile, buffer, 4 ) != 4 ) + return EDBF_READ; + hb_itemPutNInt( pItem, ( LONG ) HB_GET_LE_UINT32( buffer ) ); + break; + + case SMT_IT_DOUBLE: + if( hb_fsRead( pArea->hMemoFile, buffer, 10 ) != 10 ) + return EDBF_READ; + iWidth = buffer[ 0 ]; + iDec = buffer[ 1 ]; + if( iDec ) + iWidth -= iDec + 1; + hb_itemPutNDLen( pItem, HB_GET_LE_DOUBLE( &buffer[ 2 ] ), iWidth, iDec ); + break; + + case SMT_IT_DATE: + if( hb_fsRead( pArea->hMemoFile, buffer, 4 ) != 4 ) + return EDBF_READ; + hb_itemPutDL( pItem, ( LONG ) HB_GET_LE_UINT32( buffer ) ); + break; + + case SMT_IT_LOGICAL: + if( hb_fsRead( pArea->hMemoFile, buffer, 1 ) != 1 ) + return EDBF_READ; + hb_itemPutL( pItem, buffer[ 0 ] != 0 ); + break; + + case SMT_IT_NIL: + hb_itemClear( pItem ); + break; + + default: + hb_itemClear( pItem ); + return EDBF_CORRUPT; + } + + return SUCCESS; +} + +/* + * Read SMT item from memory buffer. + */ +static ERRCODE hb_fptReadSMTItem( FPTAREAP pArea, BYTE ** pbMemoBuf, BYTE * bBufEnd, PHB_ITEM pItem ) +{ + ULONG ulLen, i; + ERRCODE errCode = SUCCESS; + int iWidth, iDec; + + if( bBufEnd - (*pbMemoBuf) >= 1 ) + { + switch ( *(*pbMemoBuf)++ ) + { + case SMT_IT_ARRAY: + if( bBufEnd - (*pbMemoBuf) < 2 ) + { + errCode = EDBF_CORRUPT; + break; + } + ulLen = HB_GET_LE_UINT16( *pbMemoBuf ); + *pbMemoBuf += 2; + if( bBufEnd - (*pbMemoBuf) < ( LONG ) ulLen ) + { + errCode = EDBF_CORRUPT; + break; + } + hb_arrayNew( pItem, ulLen ); + for ( i = 1 ; i <= ulLen ; i++ ) + { + errCode = hb_fptReadSMTItem( pArea, pbMemoBuf, bBufEnd, + hb_arrayGetItemPtr( pItem, i ) ); + if ( errCode != SUCCESS ) + break; + } + break; + + case SMT_IT_CHAR: + if( bBufEnd - (*pbMemoBuf) < 2 ) + { + errCode = EDBF_CORRUPT; + break; + } + ulLen = HB_GET_LE_UINT16( *pbMemoBuf ); + *pbMemoBuf += 2; + if( bBufEnd - (*pbMemoBuf) < ( LONG ) ulLen ) + { + errCode = EDBF_CORRUPT; + } + else + { +#ifndef HB_CDP_SUPPORT_OFF + hb_cdpnTranslate( ( char *) (*pbMemoBuf), pArea->cdPage, hb_cdp_page, ulLen ); +#endif + hb_itemPutCL( pItem, ( char *) (*pbMemoBuf), ulLen ); + *pbMemoBuf += ulLen; + } + break; + + case SMT_IT_INT: + if( bBufEnd - (*pbMemoBuf) < 4 ) + { + errCode = EDBF_CORRUPT; + break; + } + hb_itemPutNInt( pItem, ( LONG ) HB_GET_LE_UINT32( *pbMemoBuf ) ); + *pbMemoBuf += 4; + break; + + case SMT_IT_DOUBLE: + if( bBufEnd - (*pbMemoBuf) < 10 ) + { + errCode = EDBF_CORRUPT; + break; + } + iWidth = *(*pbMemoBuf)++; + iDec = *(*pbMemoBuf)++; + if( iDec ) + iWidth -= iDec + 1; + hb_itemPutNDLen( pItem, HB_GET_LE_DOUBLE( *pbMemoBuf ), iWidth, iDec ); + *pbMemoBuf += 8; + break; + + case SMT_IT_DATE: + if( bBufEnd - (*pbMemoBuf) < 4 ) + { + errCode = EDBF_CORRUPT; + break; + } + hb_itemPutDL( pItem, ( LONG ) HB_GET_LE_UINT32( *pbMemoBuf ) ); + *pbMemoBuf += 4; + break; + + case SMT_IT_LOGICAL: + if( bBufEnd - (*pbMemoBuf) < 1 ) + { + errCode = EDBF_CORRUPT; + break; + } + hb_itemPutL( pItem, *(*pbMemoBuf)++ != 0 ); + break; + + case SMT_IT_NIL: + hb_itemClear( pItem ); + break; + + default: + hb_itemClear( pItem ); + errCode = EDBF_CORRUPT; + break; + } + } + else + { + errCode = EDBF_CORRUPT; + } + + return errCode; +} + +/* + * Calculate the size of SIX memo item + */ +static ULONG hb_fptCountSixItemLength( FPTAREAP pArea, PHB_ITEM pItem, + ULONG * pulArrayCount ) +{ + ULONG ulLen, i, ulSize; + USHORT usType; + + usType = hb_itemType( pItem ); + switch ( usType ) + { + case HB_IT_ARRAY: // HB_IT_OBJECT = HB_IT_ARRAY + (*pulArrayCount)++; + ulSize = SIX_ITEM_BUFSIZE; + ulLen = hb_arrayLen( pItem ); + if ( pArea->uiMemoVersion == DB_MEMOVER_SIX ) + { + /* only 2 bytes (SHORT) for SIX compatibility */ + ulLen = HB_MIN( ulLen, 0xFFFF ); + } + for ( i = 1 ; i <= ulLen ; i++ ) + { + ulSize += hb_fptCountSixItemLength( pArea, hb_arrayGetItemPtr( pItem, i ), pulArrayCount ); + } + break; + case HB_IT_MEMO: + case HB_IT_STRING: + ulSize = SIX_ITEM_BUFSIZE; + ulLen = pItem->item.asString.length; + if ( pArea->uiMemoVersion == DB_MEMOVER_SIX ) + { + /* only 2 bytes (SHORT) for SIX compatibility */ + ulLen = HB_MIN( ulLen, 0xFFFF ); + } + ulSize += ulLen; + break; + case HB_IT_INTEGER: + case HB_IT_LONG: + case HB_IT_DOUBLE: + case HB_IT_DATE: + case HB_IT_LOGICAL: + default: + ulSize = SIX_ITEM_BUFSIZE; + } + return ulSize; +} + +/* + * Write fpt vartype as SIX memos. + */ +static ULONG hb_fptStoreSixItem( FPTAREAP pArea, PHB_ITEM pItem, BYTE ** bBufPtr ) +{ + USHORT usType; + ULONG ulLen, i, ulSize; + HB_LONG iVal; + int iWidth, iDec; + PHB_ITEM pTmpItem; + + memset( *bBufPtr, '\0', SIX_ITEM_BUFSIZE ); + usType = hb_itemType( pItem ); + ulSize = SIX_ITEM_BUFSIZE; + switch ( usType ) + { + case HB_IT_ARRAY: // HB_IT_OBJECT = HB_IT_ARRAY + HB_PUT_LE_UINT16( &(*bBufPtr)[0], FPTIT_SIX_ARRAY ); + ulLen = hb_arrayLen( pItem ); + if ( pArea->uiMemoVersion == DB_MEMOVER_SIX ) + { + /* only 2 bytes (SHORT) for SIX compatibility */ + ulLen = HB_MIN( ulLen, 0xFFFF ); + } + HB_PUT_LE_UINT32( &(*bBufPtr)[2], ulLen ); + *bBufPtr += SIX_ITEM_BUFSIZE; + for ( i = 1 ; i <= ulLen ; i++ ) + { + pTmpItem = hb_arrayGetItemPtr( pItem, i ); + ulSize += hb_fptStoreSixItem( pArea, pTmpItem, bBufPtr ); + } + break; + + case HB_IT_INTEGER: + case HB_IT_LONG: + iVal = hb_itemGetNInt( pItem ); + hb_itemGetNLen( pItem, &iWidth, &iDec ); + if ( HB_LIM_INT32( iVal ) ) + { + HB_PUT_LE_UINT16( &(*bBufPtr)[0], FPTIT_SIX_LNUM ); + HB_PUT_LE_UINT16( &(*bBufPtr)[2], iWidth ); + HB_PUT_LE_UINT32( &(*bBufPtr)[6], iVal ); + *bBufPtr += SIX_ITEM_BUFSIZE; + } + else + { + HB_PUT_LE_UINT16( &(*bBufPtr)[0], FPTIT_SIX_DNUM ); + HB_PUT_LE_UINT16( &(*bBufPtr)[2], iWidth ); + HB_PUT_LE_UINT16( &(*bBufPtr)[4], iDec ); + HB_PUT_LE_DOUBLE( &(*bBufPtr)[6], ( double ) iVal ); + *bBufPtr += SIX_ITEM_BUFSIZE; + } + break; + + case HB_IT_DOUBLE: + HB_PUT_LE_UINT16( &(*bBufPtr)[0], FPTIT_SIX_DNUM ); + HB_PUT_LE_UINT16( &(*bBufPtr)[2], pItem->item.asDouble.length ); + HB_PUT_LE_UINT16( &(*bBufPtr)[4], pItem->item.asDouble.decimal ); + HB_PUT_LE_DOUBLE( &(*bBufPtr)[6], pItem->item.asDouble.value ); + *bBufPtr += SIX_ITEM_BUFSIZE; + break; + + case HB_IT_DATE: + HB_PUT_LE_UINT16( &(*bBufPtr)[0], FPTIT_SIX_LDATE ); + HB_PUT_LE_UINT32( &(*bBufPtr)[6], pItem->item.asDate.value ); + *bBufPtr += SIX_ITEM_BUFSIZE; + break; + + case HB_IT_LOGICAL: + HB_PUT_LE_UINT16( &(*bBufPtr)[0], FPTIT_SIX_LOG ); + (*bBufPtr)[6] = pItem->item.asLogical.value ? 1 : 0; + *bBufPtr += SIX_ITEM_BUFSIZE; + break; + + case HB_IT_STRING: + case HB_IT_MEMO: + HB_PUT_LE_UINT16( &(*bBufPtr)[0], FPTIT_SIX_CHAR ); + ulLen = pItem->item.asString.length; + if ( pArea->uiMemoVersion == DB_MEMOVER_SIX ) + { + /* only 2 bytes (SHORT) for SIX compatibility */ + ulLen = HB_MIN( ulLen, 0xFFFF ); + } + HB_PUT_LE_UINT32( &(*bBufPtr)[2], ulLen ); + *bBufPtr += SIX_ITEM_BUFSIZE; + if ( ulLen > 0 ) + { + memcpy( *bBufPtr, pItem->item.asString.value, ulLen ); +#ifndef HB_CDP_SUPPORT_OFF + hb_cdpnTranslate( ( char *) *bBufPtr, hb_cdp_page, pArea->cdPage, ulLen ); +#endif + *bBufPtr += ulLen; + } + break; + default: + *bBufPtr += SIX_ITEM_BUFSIZE; + break; + } + return ulSize; +} + /* * Read SIX item from memo. */ @@ -1092,7 +1730,6 @@ static ERRCODE hb_fptReadSixItem( FPTAREAP pArea, BYTE ** pbMemoBuf, BYTE * bBuf { USHORT usType; ULONG ulLen, i; - PHB_ITEM pNewItem; ERRCODE errCode = SUCCESS; ulLen = SIX_ITEM_BUFSIZE; @@ -1121,17 +1758,17 @@ static ERRCODE hb_fptReadSixItem( FPTAREAP pArea, BYTE ** pbMemoBuf, BYTE * bBuf case FPTIT_SIX_CHAR: ulLen = HB_GET_LE_UINT32( &(*pbMemoBuf)[2] ); - if ( pArea->bMemoType == MEMO_FPT_SIX ) + if ( pArea->uiMemoVersion == DB_MEMOVER_SIX ) { ulLen &= 0xFFFF; /* only 2 bytes (SHORT) for SIX compatibility */ } (*pbMemoBuf) += SIX_ITEM_BUFSIZE; if ( bBufEnd - (*pbMemoBuf) >= ( LONG ) ulLen ) { - hb_itemPutCL( pItem, ( char *) (*pbMemoBuf), ulLen ); #ifndef HB_CDP_SUPPORT_OFF - hb_cdpnTranslate( pItem->item.asString.value, pArea->cdPage, hb_cdp_page, ulLen ); + hb_cdpnTranslate( ( char *) (*pbMemoBuf), pArea->cdPage, hb_cdp_page, ulLen ); #endif + hb_itemPutCL( pItem, ( char *) (*pbMemoBuf), ulLen ); } else { @@ -1145,27 +1782,26 @@ static ERRCODE hb_fptReadSixItem( FPTAREAP pArea, BYTE ** pbMemoBuf, BYTE * bBuf case FPTIT_SIX_ARRAY: ulLen = HB_GET_LE_UINT32( &(*pbMemoBuf)[2] ); - if ( pArea->bMemoType == MEMO_FPT_SIX ) + if ( pArea->uiMemoVersion == DB_MEMOVER_SIX ) { ulLen &= 0xFFFF; /* only 2 bytes (SHORT) for SIX compatibility */ } (*pbMemoBuf) += SIX_ITEM_BUFSIZE; hb_arrayNew( pItem, ulLen ); - pNewItem = hb_itemNew( NULL ); for ( i = 1 ; i <= ulLen ; i++ ) { - errCode = hb_fptReadSixItem( pArea, pbMemoBuf, bBufEnd, pNewItem ); + errCode = hb_fptReadSixItem( pArea, pbMemoBuf, bBufEnd, + hb_arrayGetItemPtr( pItem, i ) ); if ( errCode != SUCCESS ) { break; } - hb_itemArrayPut( pItem, i, pNewItem ); - hb_itemClear( pNewItem ); } - hb_itemRelease( pNewItem ); ulLen = 0; break; + default: + errCode = EDBF_CORRUPT; hb_itemClear( pItem ); break; } @@ -1179,6 +1815,141 @@ static ERRCODE hb_fptReadSixItem( FPTAREAP pArea, BYTE ** pbMemoBuf, BYTE * bBuf return errCode; } +/* + * Calculate the size of FLEX memo item + */ +static ULONG hb_fptCountFlexItemLength( FPTAREAP pArea, PHB_ITEM pItem, + ULONG * pulArrayCount ) +{ + ULONG ulLen, i, ulSize = 1; + USHORT usType; + HB_LONG iVal; + + usType = hb_itemType( pItem ); + switch ( usType ) + { + case HB_IT_ARRAY: + (*pulArrayCount)++; + ulSize += 2; + ulLen = hb_arrayLen( pItem ) & 0xFFFF; + for ( i = 1 ; i <= ulLen ; i++ ) + { + ulSize += hb_fptCountFlexItemLength( pArea, hb_arrayGetItemPtr( pItem, i ), pulArrayCount ); + } + break; + case HB_IT_MEMO: + case HB_IT_STRING: + ulLen = pItem->item.asString.length; + /* only 2 bytes (SHORT) for SIX compatibility */ + ulLen = HB_MIN( ulLen, 0xFFFF ); + ulSize += ulLen + 2; + break; + case HB_IT_DATE: + ulSize += 4; + break; + case HB_IT_INTEGER: + case HB_IT_LONG: + iVal = hb_itemGetNInt( pItem ); + ulSize += ( HB_LIM_INT8( iVal ) ? 2 : + ( HB_LIM_INT16( iVal ) ? 3 : + ( HB_LIM_INT32( iVal ) ? 6 : 10 ) ) ); + break; + case HB_IT_DOUBLE: + ulSize += 10; + break; + } + return ulSize; +} + +/* + * Store in buffer fpt vartype as FLEX memos. + */ +static void hb_fptStoreFlexItem( FPTAREAP pArea, PHB_ITEM pItem, BYTE ** bBufPtr ) +{ + ULONG ulLen, i; + USHORT usType; + HB_LONG iVal; + + usType = hb_itemType( pItem ); + switch ( usType ) + { + case HB_IT_ARRAY: + ulLen = hb_arrayLen( pItem ) & 0xFFFF; + *(*bBufPtr)++ = FPTIT_FLEXAR_ARAY; + HB_PUT_LE_UINT16( *bBufPtr, ( USHORT ) ulLen ); + *bBufPtr += 2; + for ( i = 1 ; i <= ulLen ; i++ ) + { + hb_fptStoreFlexItem( pArea, hb_arrayGetItemPtr( pItem, i ), bBufPtr ); + } + break; + case HB_IT_MEMO: + case HB_IT_STRING: + *(*bBufPtr)++ = FPTIT_FLEXAR_STR; + ulLen = pItem->item.asString.length & 0xFFFF; + HB_PUT_LE_UINT16( *bBufPtr, ( USHORT ) ulLen ); + *bBufPtr += 2; + memcpy( *bBufPtr, pItem->item.asString.value, ulLen ); +#ifndef HB_CDP_SUPPORT_OFF + hb_cdpnTranslate( ( char *) *bBufPtr, hb_cdp_page, pArea->cdPage, ulLen ); +#endif + *bBufPtr += ulLen; + break; + case HB_IT_DATE: + *(*bBufPtr)++ = FPTIT_FLEXAR_DATE; + HB_PUT_LE_UINT32( *bBufPtr, pItem->item.asDate.value ); + *bBufPtr += 4; + break; + case HB_IT_INTEGER: + case HB_IT_LONG: + iVal = hb_itemGetNInt( pItem ); + if ( HB_LIM_INT8( iVal ) ) + { + *(*bBufPtr)++ = FPTIT_FLEXAR_CHAR; + *(*bBufPtr)++ = (BYTE) iVal; + *(*bBufPtr)++ = '\0'; + } + else if ( HB_LIM_INT16( iVal ) ) + { + *(*bBufPtr)++ = FPTIT_FLEXAR_SHORT; + HB_PUT_LE_UINT16( *bBufPtr, iVal ); + *bBufPtr += 2; + *(*bBufPtr)++ = '\0'; + } + else if ( HB_LIM_INT32( iVal ) ) + { + *(*bBufPtr)++ = FPTIT_FLEXAR_LONG; + HB_PUT_LE_UINT32( *bBufPtr, iVal ); + *bBufPtr += 4; + *(*bBufPtr)++ = '\0'; + *(*bBufPtr)++ = '\0'; + } + else + { + *(*bBufPtr)++ = FPTIT_FLEXAR_DBL; + *(*bBufPtr)++ = 20; + *(*bBufPtr)++ = '\0'; + HB_PUT_LE_DOUBLE( *bBufPtr, (double) iVal ); + *bBufPtr += 8; + } + break; + case HB_IT_DOUBLE: + *(*bBufPtr)++ = FPTIT_FLEXAR_DBL; + *(*bBufPtr)++ = (BYTE) pItem->item.asDouble.length; + *(*bBufPtr)++ = (BYTE) pItem->item.asDouble.decimal; + HB_PUT_LE_DOUBLE( *bBufPtr, pItem->item.asDouble.value ); + *bBufPtr += 8; + break; + case HB_IT_LOGICAL: + *(*bBufPtr)++ = pItem->item.asLogical.value ? + FPTIT_FLEXAR_TRUE : FPTIT_FLEXAR_FALSE; + break; + case HB_IT_NIL: + default: + *(*bBufPtr)++ = FPTIT_FLEXAR_NIL; + } +} + /* * Read FLEX item from memo. */ @@ -1186,7 +1957,6 @@ static ERRCODE hb_fptReadFlexItem( FPTAREAP pArea, BYTE ** pbMemoBuf, BYTE * bBu { BYTE usType; ULONG ulLen, i; - PHB_ITEM pNewItem; ERRCODE errCode = SUCCESS; if ( bRoot ) @@ -1348,11 +2118,11 @@ static ERRCODE hb_fptReadFlexItem( FPTAREAP pArea, BYTE ** pbMemoBuf, BYTE * bBu *pbMemoBuf += 2; if ( bBufEnd - (*pbMemoBuf) >= ( LONG ) ulLen ) { +#ifndef HB_CDP_SUPPORT_OFF + hb_cdpnTranslate( ( char *) *pbMemoBuf, pArea->cdPage, hb_cdp_page, ulLen ); +#endif hb_itemPutCL( pItem, ( char *) *pbMemoBuf, ulLen ); *pbMemoBuf += ulLen; -#ifndef HB_CDP_SUPPORT_OFF - hb_cdpnTranslate( pItem->item.asString.value, pArea->cdPage, hb_cdp_page, ulLen ); -#endif } else { @@ -1373,18 +2143,15 @@ static ERRCODE hb_fptReadFlexItem( FPTAREAP pArea, BYTE ** pbMemoBuf, BYTE * bBu if ( bBufEnd - (*pbMemoBuf) >= ( LONG ) ulLen ) { hb_arrayNew( pItem, ulLen ); - pNewItem = hb_itemNew( NULL ); for ( i = 1 ; i <= ulLen ; i++ ) { - errCode = hb_fptReadFlexItem( pArea, pbMemoBuf, bBufEnd, pNewItem, FALSE ); + errCode = hb_fptReadFlexItem( pArea, pbMemoBuf, bBufEnd, + hb_arrayGetItemPtr( pItem, i ), FALSE ); if ( errCode != SUCCESS ) { break; } - hb_itemArrayPut( pItem, i, pNewItem ); - hb_itemClear( pNewItem ); } - hb_itemRelease( pNewItem ); } else { @@ -1397,50 +2164,244 @@ static ERRCODE hb_fptReadFlexItem( FPTAREAP pArea, BYTE ** pbMemoBuf, BYTE * bBu } break; default: + errCode = EDBF_CORRUPT; hb_itemClear( pItem ); break; } return errCode; } -/* - * Read fpt vartype memos. - */ -static ERRCODE hb_fptGetMemo( FPTAREAP pArea, USHORT uiIndex, PHB_ITEM pItem ) +static ERRCODE hb_fptExportToFile( FPTAREAP pArea, FHANDLE hFile, ULONG ulSize ) { ERRCODE errCode = SUCCESS; - ULONG ulBlock, ulSize, ulType; - BYTE * pBuffer, * bMemoBuf; - FPTBLOCK fptBlock; - HB_TRACE(HB_TR_DEBUG, ("hb_fptGetMemo(%p, %hu, %p)", pArea, uiIndex, pItem)); - - ulBlock = hb_dbfGetMemoBlock( (DBFAREAP) pArea, uiIndex ); - - if( ulBlock > 0 ) + if( ulSize ) { - hb_fsSeek( pArea->hMemoFile, ulBlock * pArea->uiMemoBlockSize, FS_SET ); + ULONG ulWritten = 0, ulRead, ulBufSize; + BYTE * bBuffer; - if( hb_fsRead( pArea->hMemoFile, ( BYTE * ) &fptBlock, - sizeof( FPTBLOCK ) ) != sizeof( FPTBLOCK ) ) + ulBufSize = HB_MIN( ( 1 << 16 ), ulSize ); + bBuffer = ( BYTE * ) hb_xgrab( ulBufSize ); + + while( errCode == SUCCESS && ulWritten < ulSize ) { - ulSize = 0; + ulRead = hb_fsReadLarge( pArea->hMemoFile, bBuffer, + HB_MIN( ulBufSize, ulSize - ulWritten ) ); + if( ulRead <= 0 ) + errCode = EDBF_READ; + else if( hb_fsWriteLarge( hFile, bBuffer, ulRead ) != ulRead ) + errCode = EDBF_WRITE; + else + ulWritten += ulRead; } - else + hb_xfree( bBuffer ); + } + + return errCode; +} + +static ERRCODE hb_fptReadRawBlock( FPTAREAP pArea, BYTE * bBuffer, FHANDLE hFile, + ULONG ulBlock, ULONG ulSize ) +{ + ERRCODE errCode = SUCCESS; + + if( ulBlock == 0 ) + return EDBF_CORRUPT; + + hb_fsSeekLarge( pArea->hMemoFile, ( HB_FOFFSET ) ulBlock * + ( HB_FOFFSET ) pArea->uiMemoBlockSize, FS_SET ); + + if( hFile != FS_ERROR ) + { + errCode = hb_fptExportToFile( pArea, hFile, ulSize ); + } + else + { + if( hb_fsReadLarge( pArea->hMemoFile, bBuffer, ulSize ) != ulSize ) + errCode = EDBF_READ; + } + + return errCode; +} + +extern ERRCODE hb_fptReadBlobBlock( FPTAREAP pArea, PHB_ITEM pItem, FHANDLE hFile, + ULONG ulBlock, USHORT uiMode ) +{ + ULONG ulSize; + BYTE buffer[ 4 ]; + + if( ulBlock == 0 ) + return EDBF_CORRUPT; + + /* TODO: uiMode => BLOB_IMPORT_COMPRESS, BLOB_IMPORT_ENCRYPT */ + HB_SYMBOL_UNUSED( uiMode ); + + hb_fsSeekLarge( pArea->hMemoFile, ( HB_FOFFSET ) ulBlock * + ( HB_FOFFSET ) pArea->uiMemoBlockSize, FS_SET ); + + if( hb_fsReadLarge( pArea->hMemoFile, buffer, 4 ) != 4 ) + return EDBF_READ; + + ulSize = HB_GET_LE_UINT32( buffer ); + if( hFile != FS_ERROR ) + return hb_fptExportToFile( pArea, hFile, ulSize ); + + if( ulSize == 0 ) + hb_itemPutC( pItem, "" ); + else + { + BYTE * bBuffer = ( BYTE * ) hb_xalloc( ulSize + 1 ); + + if( !bBuffer ) { - ulSize = HB_GET_BE_UINT32( fptBlock.size ); + /* in most cases this means that file is corrupted */ + return EDBF_CORRUPT; + } + if( hb_fsReadLarge( pArea->hMemoFile, bBuffer, ulSize ) != ulSize ) + { + hb_xfree( bBuffer ); + return EDBF_READ; + } + hb_itemPutCPtr( pItem, ( char * ) bBuffer, ulSize ); + } + return SUCCESS; +} + +extern ERRCODE hb_fptReadSMTBlock( FPTAREAP pArea, PHB_ITEM pItem, ULONG ulBlock, ULONG ulSize ) +{ + if( ulBlock == 0 ) + return EDBF_CORRUPT; + + hb_fsSeekLarge( pArea->hMemoFile, ( HB_FOFFSET ) ulBlock * + ( HB_FOFFSET ) pArea->uiMemoBlockSize, FS_SET ); + + if( ulSize == 0 ) + { + return hb_fptReadRawSMTItem( pArea, pItem ); + } + else + { + ERRCODE errCode; + BYTE * bBuffer = ( BYTE * ) hb_xalloc( ulSize ), * bMemoBuf; + + if( !bBuffer ) + { + /* in most cases this means that file is corrupted */ + return EDBF_CORRUPT; } - ulType = HB_GET_BE_UINT32( fptBlock.type ); - pBuffer = ( BYTE * ) hb_xgrab( HB_MAX( ulSize + 1, 8 ) ); - memset( pBuffer, '\0', 8); - if ( hb_fsReadLarge( pArea->hMemoFile, pBuffer, ulSize ) != ulSize ) + if( hb_fsReadLarge( pArea->hMemoFile, bBuffer, ulSize ) != ulSize ) { errCode = EDBF_READ; } else { - switch ( ulType ) + bMemoBuf = bBuffer; + errCode = hb_fptReadSMTItem( pArea, &bMemoBuf, bMemoBuf + ulSize, pItem ); + } + hb_xfree( bBuffer ); + return errCode; + } +} + +/* + * Read fpt vartype memos. + */ +static ERRCODE hb_fptGetMemo( FPTAREAP pArea, USHORT uiIndex, PHB_ITEM pItem, FHANDLE hFile ) +{ + ERRCODE errCode; + ULONG ulBlock, ulSize, ulBufSize, ulType; + BYTE * pBuffer, * bMemoBuf; + FPTBLOCK fptBlock; + + HB_TRACE(HB_TR_DEBUG, ("hb_fptGetMemo(%p, %hu, %p, %p)", pArea, uiIndex, pItem)); + + errCode = hb_dbfGetMemoData( ( DBFAREAP ) pArea, uiIndex, + &ulBlock, &ulSize, &ulType ); + if( errCode != SUCCESS ) + return errCode; + + if( ulBlock > 0 ) + { + if( pArea->bMemoType == DB_MEMO_FPT ) + { + hb_fsSeekLarge( pArea->hMemoFile, ( HB_FOFFSET ) ulBlock * + ( HB_FOFFSET ) pArea->uiMemoBlockSize, FS_SET ); + if( hb_fsRead( pArea->hMemoFile, ( BYTE * ) &fptBlock, + sizeof( FPTBLOCK ) ) != sizeof( FPTBLOCK ) ) + { + return EDBF_READ; + } + ulType = HB_GET_BE_UINT32( fptBlock.type ); + ulSize = HB_GET_BE_UINT32( fptBlock.size ); + ulBufSize = HB_MAX( ulSize + 1, 8 ); + } + else + { + if( pArea->bMemoType == DB_MEMO_DBT ) + { + ulSize = hb_fptGetMemoLen( pArea, uiIndex ); + ulType = FPTIT_BINARY; + } + hb_fsSeekLarge( pArea->hMemoFile, ( HB_FOFFSET ) ulBlock * + ( HB_FOFFSET ) pArea->uiMemoBlockSize, FS_SET ); + ulBufSize = ulSize + 1; + } + + if( hFile != FS_ERROR ) + { + return hb_fptExportToFile( pArea, hFile, ulSize ); + } + + pBuffer = ( BYTE * ) hb_xalloc( ulBufSize ); + if( !pBuffer ) + { + /* in most cases this means that file is corrupted */ + return EDBF_CORRUPT; + } + if( pArea->bMemoType == DB_MEMO_FPT ) + memset( pBuffer, '\0', 8 ); + + if ( ulSize != 0 && hb_fsReadLarge( pArea->hMemoFile, pBuffer, ulSize ) != ulSize ) + { + errCode = EDBF_READ; + } + else if( pArea->bMemoType == DB_MEMO_DBT ) + { +#ifndef HB_CDP_SUPPORT_OFF + hb_cdpnTranslate( ( char *) pBuffer, pArea->cdPage, hb_cdp_page, ulSize ); +#endif + pBuffer[ ulSize ] = '\0'; + hb_itemPutCPtr( pItem, ( char * ) pBuffer, ulSize ); + hb_itemSetCMemo( pItem ); + pBuffer = NULL; + } + else if( pArea->bMemoType == DB_MEMO_SMT ) + { + if( ulType == SMT_IT_CHAR ) + { +#ifndef HB_CDP_SUPPORT_OFF + hb_cdpnTranslate( ( char *) pBuffer, pArea->cdPage, hb_cdp_page, ulSize ); +#endif + pBuffer[ ulSize ] = '\0'; + hb_itemPutCPtr( pItem, ( char * ) pBuffer, ulSize ); + hb_itemSetCMemo( pItem ); + pBuffer = NULL; + } + else if( !ulSize || pBuffer[ 0 ] != ( BYTE ) ulType ) + { + errCode = EDBF_CORRUPT; + hb_itemClear( pItem ); + } + else + { + bMemoBuf = pBuffer; + errCode = hb_fptReadSMTItem( pArea, &bMemoBuf, bMemoBuf + ulSize, pItem ); + } + } + else + { + switch( ulType ) { case FPTIT_SIX_LNUM: case FPTIT_SIX_DNUM: @@ -1509,9 +2470,9 @@ static ERRCODE hb_fptGetMemo( FPTAREAP pArea, USHORT uiIndex, PHB_ITEM pItem ) hb_itemClear( pItem ); break; } - if ( pBuffer ) - hb_xfree(pBuffer); } + if ( pBuffer ) + hb_xfree(pBuffer); } else { @@ -1521,296 +2482,25 @@ static ERRCODE hb_fptGetMemo( FPTAREAP pArea, USHORT uiIndex, PHB_ITEM pItem ) return errCode; } -/* - * Calculate the size of SIX memo item - */ -static ULONG hb_fptCountSixItemLength( FPTAREAP pArea, PHB_ITEM pItem ) -{ - ULONG ulLen, i, ulSize; - USHORT usType; - - usType = hb_itemType( pItem ); - switch ( usType ) - { - case HB_IT_ARRAY: // HB_IT_OBJECT = HB_IT_ARRAY - ulSize = SIX_ITEM_BUFSIZE; - ulLen = hb_arrayLen( pItem ); - if ( pArea->bMemoType == MEMO_FPT_SIX ) - { - ulLen &= 0xFFFF; /* only 2 bytes (SHORT) for SIX compatibility */ - } - for ( i = 1 ; i <= ulLen ; i++ ) - { - ulSize += hb_fptCountSixItemLength( pArea, hb_arrayGetItemPtr( pItem, i ) ); - } - break; - case HB_IT_MEMO: - case HB_IT_STRING: - ulSize = SIX_ITEM_BUFSIZE; - ulLen = pItem->item.asString.length; - if ( pArea->bMemoType == MEMO_FPT_SIX ) - { - ulLen &= 0xFFFF; /* only 2 bytes (SHORT) for SIX compatibility */ - } - ulSize += ulLen; - break; - case HB_IT_INTEGER: - case HB_IT_LONG: - case HB_IT_DOUBLE: - case HB_IT_DATE: - case HB_IT_LOGICAL: - default: - ulSize = SIX_ITEM_BUFSIZE; - } - return ulSize; -} - -/* - * Write fpt vartype as SIX memos. - */ -static ULONG hb_fptStoreSixItem( FPTAREAP pArea, PHB_ITEM pItem, BYTE ** bBufPtr ) -{ - USHORT usType; - ULONG ulLen, i, ulSize; - HB_LONG iVal; - int iWidth, iDec; - PHB_ITEM pTmpItem; - - memset( *bBufPtr, '\0', SIX_ITEM_BUFSIZE ); - usType = hb_itemType( pItem ); - ulSize = SIX_ITEM_BUFSIZE; - switch ( usType ) - { - case HB_IT_ARRAY: // HB_IT_OBJECT = HB_IT_ARRAY - HB_PUT_LE_UINT16( &(*bBufPtr)[0], FPTIT_SIX_ARRAY ); - ulLen = hb_arrayLen( pItem ); - if ( pArea->bMemoType == MEMO_FPT_SIX ) - { - ulLen &= 0xFFFF; /* only 2 bytes (SHORT) for SIX compatibility */ - } - HB_PUT_LE_UINT32( &(*bBufPtr)[2], ulLen ); - *bBufPtr += SIX_ITEM_BUFSIZE; - for ( i = 1 ; i <= ulLen ; i++ ) - { - pTmpItem = hb_arrayGetItemPtr( pItem, i ); - ulSize += hb_fptStoreSixItem( pArea, pTmpItem, bBufPtr ); - } - break; - - case HB_IT_INTEGER: - case HB_IT_LONG: - iVal = hb_itemGetNInt( pItem ); - hb_itemGetNLen( pItem, &iWidth, &iDec ); - if ( HB_LIM_INT32( iVal ) ) - { - HB_PUT_LE_UINT16( &(*bBufPtr)[0], FPTIT_SIX_LNUM ); - HB_PUT_LE_UINT16( &(*bBufPtr)[2], iWidth ); - HB_PUT_LE_UINT32( &(*bBufPtr)[6], iVal ); - *bBufPtr += SIX_ITEM_BUFSIZE; - } - else - { - HB_PUT_LE_UINT16( &(*bBufPtr)[0], FPTIT_SIX_DNUM ); - HB_PUT_LE_UINT16( &(*bBufPtr)[2], iWidth ); - HB_PUT_LE_UINT16( &(*bBufPtr)[4], iDec ); - HB_PUT_LE_DOUBLE( &(*bBufPtr)[6], ( double ) iVal ); - *bBufPtr += SIX_ITEM_BUFSIZE; - } - break; - - case HB_IT_DOUBLE: - HB_PUT_LE_UINT16( &(*bBufPtr)[0], FPTIT_SIX_DNUM ); - HB_PUT_LE_UINT16( &(*bBufPtr)[2], pItem->item.asDouble.length ); - HB_PUT_LE_UINT16( &(*bBufPtr)[4], pItem->item.asDouble.decimal ); - HB_PUT_LE_DOUBLE( &(*bBufPtr)[6], pItem->item.asDouble.value ); - *bBufPtr += SIX_ITEM_BUFSIZE; - break; - - case HB_IT_DATE: - HB_PUT_LE_UINT16( &(*bBufPtr)[0], FPTIT_SIX_LDATE ); - HB_PUT_LE_UINT32( &(*bBufPtr)[6], pItem->item.asDate.value ); - *bBufPtr += SIX_ITEM_BUFSIZE; - break; - - case HB_IT_LOGICAL: - HB_PUT_LE_UINT16( &(*bBufPtr)[0], FPTIT_SIX_LOG ); - (*bBufPtr)[6] = pItem->item.asLogical.value ? 1 : 0; - *bBufPtr += SIX_ITEM_BUFSIZE; - break; - - case HB_IT_STRING: - case HB_IT_MEMO: - HB_PUT_LE_UINT16( &(*bBufPtr)[0], FPTIT_SIX_CHAR ); - ulLen = pItem->item.asString.length; - if ( pArea->bMemoType == MEMO_FPT_SIX ) - { - ulLen &= 0xFFFF; /* only 2 bytes (SHORT) for SIX compatibility */ - } - HB_PUT_LE_UINT32( &(*bBufPtr)[2], ulLen ); - *bBufPtr += SIX_ITEM_BUFSIZE; - if ( ulLen > 0 ) - { - memcpy( *bBufPtr, pItem->item.asString.value, ulLen ); -#ifndef HB_CDP_SUPPORT_OFF - hb_cdpnTranslate( ( char *) *bBufPtr, hb_cdp_page, pArea->cdPage, ulLen ); -#endif - *bBufPtr += ulLen; - } - break; - default: - *bBufPtr += SIX_ITEM_BUFSIZE; - break; - } - return ulSize; -} - -/* - * Calculate the size of FLEX memo item - */ -static ULONG hb_fptCountFlexItemLength( FPTAREAP pArea, PHB_ITEM pItem ) -{ - ULONG ulLen, i, ulSize = 1; - USHORT usType; - HB_LONG iVal; - - usType = hb_itemType( pItem ); - switch ( usType ) - { - case HB_IT_ARRAY: - ulSize += 2; - ulLen = hb_arrayLen( pItem ) & 0xFFFF; - for ( i = 1 ; i <= ulLen ; i++ ) - { - ulSize += hb_fptCountFlexItemLength( pArea, hb_arrayGetItemPtr( pItem, i ) ); - } - break; - case HB_IT_MEMO: - case HB_IT_STRING: - ulLen = pItem->item.asString.length & 0xFFFF; - ulSize += ulLen + 2; - break; - case HB_IT_DATE: - ulSize += 4; - break; - case HB_IT_INTEGER: - case HB_IT_LONG: - iVal = hb_itemGetNInt( pItem ); - ulSize += ( HB_LIM_INT8( iVal ) ? 2 : - ( HB_LIM_INT16( iVal ) ? 3 : - ( HB_LIM_INT32( iVal ) ? 6 : 10 ) ) ); - break; - case HB_IT_DOUBLE: - ulSize += 10; - break; - } - return ulSize; -} - -/* - * Store in buffer fpt vartype as FLEX memos. - */ -static void hb_fptStoreFlexItem( FPTAREAP pArea, PHB_ITEM pItem, BYTE ** bBufPtr ) -{ - ULONG ulLen, i; - USHORT usType; - HB_LONG iVal; - - usType = hb_itemType( pItem ); - switch ( usType ) - { - case HB_IT_ARRAY: - ulLen = hb_arrayLen( pItem ) & 0xFFFF; - *(*bBufPtr)++ = FPTIT_FLEXAR_ARAY; - HB_PUT_LE_UINT16( *bBufPtr, ( USHORT ) ulLen ); - *bBufPtr += 2; - for ( i = 1 ; i <= ulLen ; i++ ) - { - hb_fptStoreFlexItem( pArea, hb_arrayGetItemPtr( pItem, i ), bBufPtr ); - } - break; - case HB_IT_MEMO: - case HB_IT_STRING: - *(*bBufPtr)++ = FPTIT_FLEXAR_STR; - ulLen = pItem->item.asString.length & 0xFFFF; - HB_PUT_LE_UINT16( *bBufPtr, ( USHORT ) ulLen ); - *bBufPtr += 2; - memcpy( *bBufPtr, pItem->item.asString.value, ulLen ); -#ifndef HB_CDP_SUPPORT_OFF - hb_cdpnTranslate( ( char *) *bBufPtr, hb_cdp_page, pArea->cdPage, ulLen ); -#endif - *bBufPtr += ulLen; - break; - case HB_IT_DATE: - *(*bBufPtr)++ = FPTIT_FLEXAR_DATE; - HB_PUT_LE_UINT32( *bBufPtr, pItem->item.asDate.value ); - *bBufPtr += 4; - break; - case HB_IT_INTEGER: - case HB_IT_LONG: - iVal = hb_itemGetNInt( pItem ); - if ( HB_LIM_INT8( iVal ) ) - { - *(*bBufPtr)++ = FPTIT_FLEXAR_CHAR; - *(*bBufPtr)++ = (BYTE) iVal; - *(*bBufPtr)++ = '\0'; - } - else if ( HB_LIM_INT16( iVal ) ) - { - *(*bBufPtr)++ = FPTIT_FLEXAR_SHORT; - HB_PUT_LE_UINT16( *bBufPtr, iVal ); - *bBufPtr += 2; - *(*bBufPtr)++ = '\0'; - } - else if ( HB_LIM_INT32( iVal ) ) - { - *(*bBufPtr)++ = FPTIT_FLEXAR_LONG; - HB_PUT_LE_UINT32( *bBufPtr, iVal ); - *bBufPtr += 4; - *(*bBufPtr)++ = '\0'; - *(*bBufPtr)++ = '\0'; - } - else - { - *(*bBufPtr)++ = FPTIT_FLEXAR_DBL; - *(*bBufPtr)++ = 20; - *(*bBufPtr)++ = '\0'; - HB_PUT_LE_DOUBLE( *bBufPtr, (double) iVal ); - *bBufPtr += 8; - } - break; - case HB_IT_DOUBLE: - *(*bBufPtr)++ = FPTIT_FLEXAR_DBL; - *(*bBufPtr)++ = (BYTE) pItem->item.asDouble.length; - *(*bBufPtr)++ = (BYTE) pItem->item.asDouble.decimal; - HB_PUT_LE_DOUBLE( *bBufPtr, pItem->item.asDouble.value ); - *bBufPtr += 8; - break; - case HB_IT_LOGICAL: - *(*bBufPtr)++ = pItem->item.asLogical.value ? - FPTIT_FLEXAR_TRUE : FPTIT_FLEXAR_FALSE; - break; - case HB_IT_NIL: - default: - *(*bBufPtr)++ = FPTIT_FLEXAR_NIL; - } -} - /* * Write memo data. */ -static ERRCODE hb_fptWriteMemo( FPTAREAP pArea, ULONG ulBlock, BYTE *bBufPtr, +static ERRCODE hb_fptWriteMemo( FPTAREAP pArea, ULONG ulBlock, ULONG ulSize, + BYTE *bBufPtr, FHANDLE hFile, ULONG ulType, ULONG ulLen, ULONG * ulStoredBlock ) { MEMOGCTABLE fptGCtable; ERRCODE errCode; BOOL bWrite; - HB_TRACE(HB_TR_DEBUG, ("hb_fptWriteMemo(%p, %lu, %p, %hu, %lu, %p)", - pArea, ulBlock, bBufPtr, ulType, ulLen, ulStoredBlock)); + HB_TRACE(HB_TR_DEBUG, ("hb_fptWriteMemo(%p, %lu, %lu, %p, %p, %hu, %lu, %p)", + pArea, ulBlock, ulSize, bBufPtr, hFile, ulType, ulLen, ulStoredBlock)); - bWrite = ( ulLen != 0 || ( ulType != FPTIT_TEXT && ulType != FPTIT_BINARY ) ); + bWrite = ( ulLen != 0 || ( pArea->bMemoType == DB_MEMO_FPT && + ulType != FPTIT_TEXT && ulType != FPTIT_BINARY && + ulType != FPTIT_DUMMY ) ); - if ( ulBlock == 0 && !bWrite ) + if( ulBlock == 0 && !bWrite ) { * ulStoredBlock = 0; return SUCCESS; @@ -1818,15 +2508,16 @@ static ERRCODE hb_fptWriteMemo( FPTAREAP pArea, ULONG ulBlock, BYTE *bBufPtr, hb_fptInitGCdata( &fptGCtable ); errCode = hb_fptReadGCdata( pArea, &fptGCtable ); - if ( errCode != SUCCESS ) + if( errCode != SUCCESS ) { return errCode; } - if ( ulBlock > 0 ) + if( ulBlock > 0 ) { - errCode = hb_fptGCfreeBlock( pArea, &fptGCtable, ulBlock, 0 ); - if ( errCode != SUCCESS ) + errCode = hb_fptGCfreeBlock( pArea, &fptGCtable, ulBlock, ulSize, + ulType == FPTIT_DUMMY ); + if( errCode != SUCCESS ) { hb_fptDestroyGCdata( &fptGCtable ); return errCode; @@ -1836,39 +2527,74 @@ static ERRCODE hb_fptWriteMemo( FPTAREAP pArea, ULONG ulBlock, BYTE *bBufPtr, /* Write memo header and data */ if( bWrite ) { - FPTBLOCK fptBlock; - - errCode = hb_fptGCgetFreeBlock( pArea, &fptGCtable, ulStoredBlock, ulLen ); - if ( errCode != SUCCESS ) + errCode = hb_fptGCgetFreeBlock( pArea, &fptGCtable, ulStoredBlock, ulLen, + ulType == FPTIT_DUMMY ); + if( errCode != SUCCESS ) { hb_fptDestroyGCdata( &fptGCtable ); return errCode; } - HB_PUT_BE_UINT32( fptBlock.type, ulType ); - HB_PUT_BE_UINT32( fptBlock.size, ulLen ); - hb_fsSeek( pArea->hMemoFile, *ulStoredBlock * pArea->uiMemoBlockSize, FS_SET ); - hb_fsWrite( pArea->hMemoFile, ( BYTE * ) &fptBlock, sizeof( FPTBLOCK ) ); + hb_fsSeekLarge( pArea->hMemoFile, ( HB_FOFFSET ) *ulStoredBlock * + ( HB_FOFFSET ) pArea->uiMemoBlockSize, FS_SET ); - if ( ulLen > 0 ) + if( pArea->bMemoType == DB_MEMO_FPT ) { - if ( hb_fsWriteLarge( pArea->hMemoFile, bBufPtr, ulLen ) != ulLen ) + FPTBLOCK fptBlock; + HB_PUT_BE_UINT32( fptBlock.type, ulType ); + HB_PUT_BE_UINT32( fptBlock.size, ulLen ); + if( hb_fsWrite( pArea->hMemoFile, ( BYTE * ) &fptBlock, + sizeof( FPTBLOCK ) ) != sizeof( FPTBLOCK ) ) + errCode = EDBF_WRITE; + } + + if( errCode == SUCCESS && ulLen > 0 ) + { + /* TODO: uiMode => BLOB_IMPORT_COMPRESS, BLOB_IMPORT_ENCRYPT */ + if( hFile != FS_ERROR ) + { + ULONG ulWritten = 0, ulRead, ulBufSize = HB_MIN( ( 1 << 16 ), ulLen ); + BYTE * bBuffer = ( BYTE * ) hb_xgrab( ulBufSize ); + + do + { + ulRead = hb_fsReadLarge( hFile, bBuffer, + HB_MIN( ulBufSize, ulLen - ulWritten ) ); + if( ulRead <= 0 ) + errCode = EDBF_READ; + else if( hb_fsWriteLarge( pArea->hMemoFile, bBuffer, + ulRead ) != ulRead ) + errCode = EDBF_WRITE; + else + ulWritten += ulRead; + } + while( errCode == SUCCESS && ulWritten < ulLen ); + + hb_xfree(bBuffer); + } + else if( hb_fsWriteLarge( pArea->hMemoFile, bBufPtr, ulLen ) != ulLen ) { errCode = EDBF_WRITE; } } /* if written block is smaller then block size we should write at last block byte 0xAF to be FLEX compatible */ - if ( errCode == SUCCESS && - pArea->bMemoType != MEMO_FPT_SIX && - pArea->bMemoType != MEMO_FPT_SIXHB && - ( ulLen + sizeof( FPTBLOCK ) ) % pArea->uiMemoBlockSize != 0 ) + if( errCode == SUCCESS ) { - ULONG ulBlocks = ( ulLen + sizeof( FPTBLOCK ) + pArea->uiMemoBlockSize - 1 ) / - pArea->uiMemoBlockSize; - hb_fsSeek( pArea->hMemoFile, ( *ulStoredBlock + ulBlocks ) * - pArea->uiMemoBlockSize - 1, FS_SET ); - hb_fsWrite( pArea->hMemoFile, ( BYTE * ) "\xAF", 1 ); + if( pArea->bMemoType == DB_MEMO_DBT ) + { + hb_fsWrite( pArea->hMemoFile, ( BYTE * ) "\x1A\x1A", 2 ); + } + else if( pArea->uiMemoVersion == DB_MEMOVER_FLEX && + ( ulLen + sizeof( FPTBLOCK ) ) % pArea->uiMemoBlockSize != 0 ) + { + ULONG ulBlocks = ( ulLen + sizeof( FPTBLOCK ) + pArea->uiMemoBlockSize - 1 ) / + pArea->uiMemoBlockSize; + hb_fsSeekLarge( pArea->hMemoFile, + ( HB_FOFFSET ) ( *ulStoredBlock + ulBlocks ) * + ( HB_FOFFSET ) pArea->uiMemoBlockSize - 1, FS_SET ); + hb_fsWrite( pArea->hMemoFile, ( BYTE * ) "\xAF", 1 ); + } } pArea->fMemoFlush = TRUE; } @@ -1891,7 +2617,7 @@ static ERRCODE hb_fptWriteMemo( FPTAREAP pArea, ULONG ulBlock, BYTE *bBufPtr, */ static ERRCODE hb_fptPutMemo( FPTAREAP pArea, USHORT uiIndex, PHB_ITEM pItem ) { - ULONG ulLen, ulBlock, ulType; + ULONG ulSize, ulBlock, ulType, ulOldSize, ulOldType, ulArrayCount = 0; BYTE itmBuffer[FLEX_ITEM_BUFSIZE]; BYTE *bBufPtr = NULL, *bBufAlloc = NULL; ERRCODE errCode; @@ -1899,61 +2625,77 @@ static ERRCODE hb_fptPutMemo( FPTAREAP pArea, USHORT uiIndex, PHB_ITEM pItem ) HB_TRACE(HB_TR_DEBUG, ("hb_fptPutMemo(%p, %hu, %p)", pArea, uiIndex, pItem)); - if ( HB_IS_STRING( pItem ) ) + if( HB_IS_STRING( pItem ) ) { ulType = FPTIT_TEXT; - ulLen = pItem->item.asString.length; + ulSize = pItem->item.asString.length; bBufPtr = ( BYTE *) pItem->item.asString.value; #ifndef HB_CDP_SUPPORT_OFF - if ( pArea->cdPage != hb_cdp_page ) + if( ulSize > 0 && pArea->cdPage != hb_cdp_page ) { - bBufAlloc = ( BYTE * ) hb_xgrab( ulLen ); - memcpy( bBufAlloc, bBufPtr, ulLen ); - hb_cdpnTranslate( ( char *) bBufAlloc, hb_cdp_page, pArea->cdPage, ulLen ); + bBufAlloc = ( BYTE * ) hb_xgrab( ulSize ); + memcpy( bBufAlloc, bBufPtr, ulSize ); + hb_cdpnTranslate( ( char *) bBufAlloc, hb_cdp_page, pArea->cdPage, ulSize ); bBufPtr = bBufAlloc; } + if( pArea->bMemoType == DB_MEMO_SMT ) + { + ulType = SMT_IT_CHAR; + } #endif } - else if ( pArea->bMemoType == MEMO_FPT_SIX || - pArea->bMemoType == MEMO_FPT_SIXHB ) + else if( pArea->bMemoType == DB_MEMO_DBT ) + { + return EDBF_DATATYPE; + } + else if( pArea->bMemoType == DB_MEMO_SMT ) + { + ulSize = hb_fptCountSMTItemLength( pArea, pItem, &ulArrayCount ); + if( ulSize == 0 ) + return EDBF_DATATYPE; + bBufPtr = bBufAlloc = ( BYTE * ) hb_xgrab( ulSize ); + hb_fptStoreSMTItem( pArea, pItem, &bBufPtr ); + ulType = ( ULONG ) bBufAlloc[ 0 ]; + bBufPtr = bBufAlloc; + } + else if( pArea->uiMemoVersion == DB_MEMOVER_SIX ) { ulType = hb_itemType( pItem ); - ulLen = hb_fptCountSixItemLength( pArea, pItem ); - if ( ulLen > 0 ) + ulSize = hb_fptCountSixItemLength( pArea, pItem, &ulArrayCount ); + if ( ulSize > 0 ) { - bBufPtr = bBufAlloc = ( BYTE * ) hb_xgrab( ulLen ); + bBufPtr = bBufAlloc = ( BYTE * ) hb_xgrab( ulSize ); hb_fptStoreSixItem( pArea, pItem, &bBufPtr ); ulType = ( ULONG ) HB_GET_LE_UINT16( bBufAlloc ); bBufPtr = bBufAlloc; } } - else if ( pArea->bMemoType == MEMO_FPT_FLEX || - pArea->bMemoType == MEMO_FPT_HB ) + else if ( pArea->uiMemoVersion == DB_MEMOVER_FLEX ) { ulType = hb_itemType( pItem ); switch ( ulType ) { case HB_IT_ARRAY: ulType = FPTIT_FLEX_ARRAY; - ulLen = hb_fptCountFlexItemLength( pArea, pItem ) - 1; - if ( ulLen > 0 ) + ulSize = hb_fptCountFlexItemLength( pArea, pItem, &ulArrayCount ) - 1; + if( ulSize > 0 ) { - bBufPtr = bBufAlloc = (BYTE *) hb_xgrab( ulLen + 1 ); + bBufPtr = bBufAlloc = (BYTE *) hb_xgrab( ulSize + 1 ); hb_fptStoreFlexItem( pArea, pItem, &bBufPtr ); bBufPtr = bBufAlloc + 1; /* FLEX doesn't store the first byte of array ID */ } break; case HB_IT_NIL: ulType = FPTIT_FLEX_NIL; - ulLen = 0; + ulSize = 0; break; case HB_IT_LOGICAL: ulType = pItem->item.asLogical.value ? FPTIT_FLEX_TRUE : FPTIT_FLEX_FALSE; - ulLen = 0; + ulSize = 0; break; case HB_IT_DATE: ulType = FPTIT_FLEX_LDATE; - ulLen = 4; + ulSize = 4; HB_PUT_LE_UINT32( itmBuffer, pItem->item.asDate.value ); bBufPtr = itmBuffer; break; @@ -1963,21 +2705,21 @@ static ERRCODE hb_fptPutMemo( FPTAREAP pArea, USHORT uiIndex, PHB_ITEM pItem ) if ( HB_LIM_INT8( iVal ) ) { ulType = FPTIT_FLEX_CHAR; - ulLen = 1; + ulSize = 1; *itmBuffer = ( BYTE ) iVal; bBufPtr = itmBuffer; } else if ( HB_LIM_INT16( iVal ) ) { ulType = FPTIT_FLEX_SHORT; - ulLen = 2; + ulSize = 2; HB_PUT_LE_UINT16( itmBuffer, iVal ); bBufPtr = itmBuffer; } else if ( HB_LIM_INT32( iVal ) ) { ulType = FPTIT_FLEX_LONG; - ulLen = 4; + ulSize = 4; HB_PUT_LE_UINT32( itmBuffer, iVal ); bBufPtr = itmBuffer; } @@ -1985,43 +2727,528 @@ static ERRCODE hb_fptPutMemo( FPTAREAP pArea, USHORT uiIndex, PHB_ITEM pItem ) { double d = (double) iVal; ulType = FPTIT_FLEX_DOUBLE; - ulLen = 8; + ulSize = 8; HB_PUT_LE_DOUBLE( itmBuffer, d ); bBufPtr = itmBuffer; } break; case HB_IT_DOUBLE: ulType = FPTIT_FLEX_DOUBLE; - ulLen = 8; + ulSize = 8; HB_PUT_LE_DOUBLE( itmBuffer, pItem->item.asDouble.value ); bBufPtr = itmBuffer; break; default: ulType = FPTIT_BINARY; - ulLen = 0; + ulSize = 0; break; } } else { - ulType = FPTIT_BINARY; - ulLen = 0; + return EDBF_DATATYPE; } - ulBlock = hb_dbfGetMemoBlock( (DBFAREAP) pArea, uiIndex ); + errCode = hb_dbfGetMemoData( (DBFAREAP) pArea, uiIndex, + &ulBlock, &ulOldSize, &ulOldType ); + if( errCode == SUCCESS ) + errCode = hb_fptWriteMemo( pArea, ulBlock, ulOldSize, bBufPtr, FS_ERROR, + ulType, ulSize, &ulBlock ); - errCode = hb_fptWriteMemo( pArea, ulBlock, bBufPtr, ulType, ulLen, &ulBlock ); - - if ( bBufAlloc != NULL ) + if( bBufAlloc != NULL ) { hb_xfree( bBufAlloc ); } - hb_dbfPutMemoBlock( (DBFAREAP) pArea, uiIndex, ulBlock ); + if( errCode == SUCCESS ) + hb_dbfSetMemoData( (DBFAREAP) pArea, uiIndex, ulBlock, ulSize, ulType ); return errCode; } +#ifdef HB_MEMO_SAFELOCK +/* + * Check if memo field has any data + */ +static BOOL hb_fptHasMemoData( FPTAREAP pArea, USHORT uiIndex ) +{ + if( --uiIndex < pArea->uiFieldCount ) + { + LPFIELD pField = pArea->lpFields + uiIndex; + + if( pField->uiType == HB_IT_ANY ) + { + BYTE * pFieldBuf = pArea->pRecord + pArea->pFieldOffset[ uiIndex ]; + + if( pField->uiLen >= 6 ) + { + USHORT uiType = HB_GET_LE_INT16( pFieldBuf + pField->uiLen - 2 ); + + switch( uiType ) + { + case HB_VF_ARRAY: + case HB_VF_BLOB: + case HB_VF_BLOBCOMPRESS: + case HB_VF_BLOBENCRYPT: + return TRUE; + case HB_VF_CHAR: + return pField->uiLen - 2 < uiType; + case HB_VF_DNUM: + return pField->uiLen <= 12; + } + } + } + else if( pField->uiType == HB_IT_MEMO ) + { + BYTE * pFieldBuf = pArea->pRecord + pArea->pFieldOffset[ uiIndex ]; + USHORT uiLen = pField->uiLen; + + if( uiLen == 4 ) + return HB_GET_LE_UINT32( pFieldBuf ) != 0; + if( uiLen == 10 ) + { + if( pArea->bMemoType == DB_MEMO_SMT ) + return HB_GET_LE_UINT32( ( ( LPSMTFIELD ) pFieldBuf )->block ) != 0; + do + { + if( *pFieldBuf >= '1' && *pFieldBuf <= '9' ) + return TRUE; + ++pFieldBuf; + } + while( --uiLen ); + } + } + } + return FALSE; +} +#endif + +static ERRCODE hb_fptLockForRead( FPTAREAP pArea, USHORT uiIndex, BOOL *fUnLock ) +{ + ERRCODE uiError; + BOOL fLocked; + + *fUnLock = FALSE; +#ifdef HB_MEMO_SAFELOCK + if( pArea->lpdbPendingRel ) + { + uiError = SELF_FORCEREL( ( AREAP ) pArea ); + if( uiError != SUCCESS ) + return uiError; + } + + if( ( uiIndex > 0 && pArea->lpFields[ uiIndex - 1 ].uiType == HB_IT_ANY && + pArea->lpFields[ uiIndex - 1 ].uiLen < 6 ) || + !pArea->fPositioned || !pArea->fShared || + pArea->fFLocked || pArea->fRecordChanged ) + { + fLocked = TRUE; + } + else + { + HB_ITEM recItm = HB_ITEM_NIL, resultItm = HB_ITEM_NIL; + uiError = SELF_RECINFO( ( AREAP ) pArea, &recItm, DBRI_LOCKED, &resultItm ); + if( uiError != SUCCESS ) + return uiError; + fLocked = hb_itemGetL( &resultItm ); + } + + if( !fLocked ) + { + if( !pArea->fValidBuffer || uiIndex == 0 || + hb_fptHasMemoData( pArea, uiIndex ) ) + { + if( !hb_fptFileLockSh( pArea, TRUE ) ) + return FAILURE; + + *fUnLock = TRUE; + pArea->fValidBuffer = FALSE; + } + } +#else + HB_SYMBOL_UNUSED( uiIndex ); +#endif + /* update any pending relations and reread record if necessary */ + uiError = SELF_DELETED( ( AREAP ) pArea, &fLocked ); + + return uiError; +} + +static ERRCODE hb_fptGetVarField( FPTAREAP pArea, USHORT uiIndex, PHB_ITEM pItem, FHANDLE hFile ) +{ + LPFIELD pField; + ERRCODE uiError; + BYTE * pFieldBuf; + BOOL fUnLock = FALSE; + + HB_TRACE(HB_TR_DEBUG, ("hb_fptGetVarField(%p, %hu, %p, %p)", pArea, uiIndex, pItem, hFile)); + + pField = pArea->lpFields + uiIndex - 1; + + if( pField->uiType == HB_IT_ANY ) + { + USHORT uiType; + + uiError = hb_fptLockForRead( pArea, uiIndex, &fUnLock ); + if( uiError != SUCCESS ) + return uiError; + + pFieldBuf = pArea->pRecord + pArea->pFieldOffset[ uiIndex - 1 ]; + if( pField->uiLen >= 6 ) + uiType = HB_GET_LE_INT16( pFieldBuf + pField->uiLen - 2 ); + else + uiType = 0; + + if( pField->uiLen == 3 || uiType == HB_VF_DATE ) + hb_itemPutDL( pItem, hb_sxPtoD( ( char * ) pFieldBuf ) ); + else if( pField->uiLen == 4 || uiType == HB_VF_INT ) + hb_itemPutNIntLen( pItem, ( HB_LONG ) HB_GET_LE_INT32( pFieldBuf ), 10 ); + else if( pField->uiLen == 2 ) + hb_itemPutNIntLen( pItem, ( int ) HB_GET_LE_INT16( pFieldBuf ), 10 ); + else if( pField->uiLen == 1 ) + hb_itemPutNILen( pItem, ( signed char ) pFieldBuf[ 0 ], 4 ); + else if( pField->uiLen >= 6 ) + { + ULONG ulBlock = HB_GET_LE_UINT32( pFieldBuf + pField->uiLen - 6 ); + + if( uiType <= HB_VF_CHAR ) /* 64000 max string size */ + { + char * pString = ( char * ) hb_xgrab( uiType + 1 ), * pBuf; + + pBuf = pString; + if( uiType <= pField->uiLen - 2 ) + memcpy( pString, pFieldBuf, uiType ); + else + { + ULONG ulSize = uiType; + + if( pField->uiLen > 6 ) + { + USHORT uiVLen = pField->uiLen - 6; + memcpy( pBuf, pFieldBuf, uiVLen ); + ulSize -= uiVLen; + pBuf += uiVLen; + } + uiError = hb_fptReadRawBlock( pArea, ( BYTE * ) pBuf, FS_ERROR, ulBlock, ulSize ); + } + if( uiError == SUCCESS ) + { + pString[ uiType ] = '\0'; +#ifndef HB_CDP_SUPPORT_OFF + hb_cdpnTranslate( pString, pArea->cdPage, hb_cdp_page, uiType ); +#endif + if( hFile != FS_ERROR ) + { + if( hb_fsWrite( hFile, ( BYTE * ) pString, uiType ) != uiType ) + uiError = EDBF_WRITE; + hb_xfree( pString ); + } + else + { + hb_itemPutCPtr( pItem, pString, uiType ); + } + } + else + hb_xfree( pString ); + } + else if( uiType == HB_VF_LOG ) + { + if( hFile != FS_ERROR ) + uiError = EDBF_DATATYPE; + else + hb_itemPutL( pItem, pFieldBuf[ 0 ] != 0 ); + } + else if( uiType == HB_VF_DNUM ) /* n>12 VFIELD else MEMO (bLen[1],bDec[1],dVal[8]) */ + { + if( hFile != FS_ERROR ) + uiError = EDBF_DATATYPE; + else + { + BYTE pBuffer[ 11 ]; + int iWidth, iDec; + + /* should be <= 11 - it's SIX bug but I replicated it for + compatibility */ + if( pField->uiLen <= 12 ) + { + uiError = hb_fptReadRawBlock( pArea, pBuffer, FS_ERROR, ulBlock, 11 ); + if( uiError == SUCCESS ) + { + if( pBuffer[ 0 ] == SMT_IT_DOUBLE ) + pFieldBuf = pBuffer + 1; + else + uiError = EDBF_CORRUPT; + } + } + if( uiError == SUCCESS ) + { + iWidth = *pFieldBuf++; + iDec = *pFieldBuf++; + if( iDec ) + iWidth += iDec + 1; + hb_itemPutNDLen( pItem, HB_GET_LE_DOUBLE( pFieldBuf ), iWidth, iDec ); + } + } + } + else if( uiType == HB_VF_ARRAY ) /* MEMO only as SMT ARRAY */ + { + if( hFile != FS_ERROR ) + uiError = EDBF_DATATYPE; + else + uiError = hb_fptReadSMTBlock( pArea, pItem, ulBlock, 0 ); + } + else if( uiType == HB_VF_BLOB ) + uiError = hb_fptReadBlobBlock( pArea, pItem, hFile, ulBlock, 0 ); + else if( uiType == HB_VF_BLOBCOMPRESS ) + uiError = hb_fptReadBlobBlock( pArea, pItem, hFile, ulBlock, BLOB_IMPORT_COMPRESS ); + else if( uiType == HB_VF_BLOBENCRYPT ) + uiError = hb_fptReadBlobBlock( pArea, pItem, hFile, ulBlock, BLOB_IMPORT_ENCRYPT ); + else + uiError = EDBF_DATATYPE; + } + } + else if( pField->uiType == HB_IT_MEMO ) + { + uiError = hb_fptLockForRead( pArea, uiIndex, &fUnLock ); + if( uiError != SUCCESS ) + return uiError; + + uiError = hb_fptGetMemo( pArea, uiIndex - 1, pItem, hFile ); + } + else if( hFile == FS_ERROR ) + { + return SUPER_GETVALUE( ( AREAP ) pArea, uiIndex, pItem ); + } + else + { + return FAILURE; + } + + if( fUnLock ) + hb_fptFileUnLock( pArea ); + + return uiError; +} + +static ERRCODE hb_fptPutVarField( FPTAREAP pArea, USHORT uiIndex, PHB_ITEM pItem ) +{ + LPFIELD pField; + + HB_TRACE(HB_TR_DEBUG, ("hb_fptPutVarField(%p, %hu, %p)", pArea, uiIndex, pItem)); + + pField = pArea->lpFields + uiIndex - 1; + + if( pField->uiType == HB_IT_ANY || pField->uiType == HB_IT_MEMO ) + { + BYTE * pFieldBuf = pArea->pRecord + pArea->pFieldOffset[ uiIndex - 1 ]; + ERRCODE uiError; + BOOL bDeleted; + + /* update any pending relations and reread record if necessary */ + uiError = SELF_DELETED( ( AREAP ) pArea, &bDeleted ); + if( uiError != SUCCESS ) + return uiError; + + if( !pArea->fPositioned ) + return SUCCESS; + + /* Buffer is hot? */ + if( !pArea->fRecordChanged ) + { + uiError = SELF_GOHOT( ( AREAP ) pArea ); + if ( uiError != SUCCESS ) + return uiError; + } + + if( pField->uiType == HB_IT_MEMO ) + { + if( !hb_fptFileLockEx( pArea, TRUE ) ) + return EDBF_LOCK; + uiError = hb_fptPutMemo( pArea, uiIndex -1, pItem ); +#if defined( HB_MEMO_SAFELOCK ) + if( uiError == SUCCESS ) + { + /* Force writer record to eliminate race condition */ + SELF_GOCOLD( ( AREAP ) pArea ); + } +#endif + hb_fptFileUnLock( pArea ); + } + else if( pField->uiLen == 3 ) + { + if( ! HB_IS_DATE( pItem ) ) + { + return EDBF_DATATYPE; + } + hb_sxDtoP( ( char * ) pFieldBuf, hb_itemGetDL( pItem ) ); + } + else if( pField->uiLen == 4 ) + { + HB_LONG lVal; + + if( ! HB_IS_NUMBER( pItem ) ) + return EDBF_DATATYPE; + lVal = hb_itemGetNInt( pItem ); + if( HB_IS_DOUBLE( pItem ) ? + ! HB_DBL_LIM_INT32( pItem->item.asDouble.value ) : + ! HB_LIM_INT32( lVal ) ) + { + return EDBF_DATAWIDTH; + } + HB_PUT_LE_UINT32( pFieldBuf, ( UINT32 ) lVal ); + } + else if( pField->uiLen < 6 ) + { + return EDBF_DATATYPE; + } + else + { + BYTE buffer[ 11 ], *pBlock, *pAlloc = NULL; + ULONG ulOldBlock = 0, ulOldSize = 0, ulNewSize = 0; + USHORT uiType = HB_GET_LE_INT16( pFieldBuf + pField->uiLen - 2 ); + + if( ( uiType <= HB_VF_CHAR && uiType > pField->uiLen - 2 ) || + ( uiType == HB_VF_DNUM && pField->uiLen <= 12 ) || + uiType == HB_VF_ARRAY || uiType == HB_VF_BLOB || + uiType == HB_VF_BLOBCOMPRESS || uiType == HB_VF_BLOBENCRYPT ) + { + ulOldBlock = HB_GET_LE_UINT32( pFieldBuf + pField->uiLen - 6 ); + if( ulOldBlock ) + { + if( uiType <= HB_VF_CHAR ) + ulOldSize = uiType - ( pField->uiLen - 6 ); + else if( uiType == HB_VF_DNUM ) + ulOldSize = 11; + else if( uiType == HB_VF_ARRAY ) + { + hb_fsSeekLarge( pArea->hMemoFile, ( HB_FOFFSET ) ulOldBlock * + ( HB_FOFFSET ) pArea->uiMemoBlockSize, FS_SET ); + if( hb_fptCountSMTDataLength( pArea, &ulOldSize ) != SUCCESS ) + ulOldSize = 0; + } + } + } + + if( HB_IS_DATE( pItem ) ) + { + hb_sxDtoP( ( char * ) pFieldBuf, hb_itemGetDL( pItem ) ); + uiType = HB_VF_DATE; + } + else if( HB_IS_LOGICAL( pItem ) ) + { + pFieldBuf[ 0 ] = hb_itemGetL( pItem ) ? 1 : 0; + uiType = HB_VF_LOG; + } + else if( HB_IS_NIL( pItem ) ) + { + uiType = 0; + } + else if( HB_IS_NUMBER( pItem ) ) + { + HB_LONG lVal; + lVal = hb_itemGetNInt( pItem ); + + if( !HB_IS_DOUBLE( pItem ) && HB_LIM_INT32( lVal ) ) + { + HB_PUT_LE_UINT32( pFieldBuf, ( UINT32 ) lVal ); + uiType = HB_VF_INT; + } + else + { + double dVal = hb_itemGetND( pItem ); + int iWidth, iDec; + + hb_itemGetNLen( pItem, &iWidth, &iDec ); + if( iDec ) + iWidth += iDec + 1; + buffer[ 0 ] = SMT_IT_DOUBLE; + buffer[ 1 ] = ( BYTE ) iWidth; + buffer[ 2 ] = ( BYTE ) iDec; + HB_PUT_LE_DOUBLE( &buffer[ 3 ], dVal ); + uiType = HB_VF_DNUM; + if( pField->uiLen > 12 ) + memcpy( pFieldBuf, buffer + 1, 10 ); + else + { + pBlock = buffer; + ulNewSize = 11; + } + } + } + else if( HB_IS_STRING( pItem ) ) + { + uiType = HB_MIN( pItem->item.asString.length, HB_VF_CHAR ); + + pAlloc = ( BYTE * ) hb_xgrab( uiType + 1 ); + memcpy( pAlloc, pItem->item.asString.value, uiType ); +#ifndef HB_CDP_SUPPORT_OFF + hb_cdpnTranslate( ( char * ) pAlloc, hb_cdp_page, pArea->cdPage, uiType ); +#endif + if( uiType <= pField->uiLen - 2 ) + { + memcpy( pFieldBuf, pAlloc, uiType ); + } + else + { + pBlock = pAlloc; + ulNewSize = uiType; + if( pField->uiLen > 6 ) + { + memcpy( pFieldBuf, pBlock, pField->uiLen - 6 ); + ulNewSize -= pField->uiLen - 6; + pBlock += pField->uiLen - 6; + } + } + } + else if( HB_IS_ARRAY( pItem ) ) + { + ULONG ulArrayCount = 0; + ulNewSize = hb_fptCountSMTItemLength( pArea, pItem, &ulArrayCount ); + pBlock = pAlloc = ( BYTE * ) hb_xgrab( ulNewSize ); + hb_fptStoreSMTItem( pArea, pItem, &pBlock ); + pBlock = pAlloc; + uiType = HB_VF_ARRAY; + } + else + { + return EDBF_DATATYPE; + } + + HB_PUT_LE_UINT16( pFieldBuf + pField->uiLen - 2, uiType ); + if( ulNewSize ) + HB_PUT_LE_UINT32( pFieldBuf + pField->uiLen - 6, 0 ); + if( ulOldBlock != 0 || ulNewSize != 0 ) + { + if( !hb_fptFileLockEx( pArea, TRUE ) ) + { + uiError = EDBF_LOCK; + } + else + { + uiError = hb_fptWriteMemo( pArea, ulOldBlock, ulOldSize, + pBlock, FS_ERROR, + FPTIT_DUMMY, ulNewSize, &ulOldBlock ); + if( uiError == SUCCESS ) + { + if( ulNewSize ) + HB_PUT_LE_UINT32( pFieldBuf + pField->uiLen - 6, ulOldBlock ); +#if defined( HB_MEMO_SAFELOCK ) + /* Force writer record to eliminate race condition */ + SELF_GOCOLD( ( AREAP ) pArea ); +#endif + } + hb_fptFileUnLock( pArea ); + } + } + if( pAlloc ) + hb_xfree( pAlloc ); + } + + return uiError; + } + return SUPER_PUTVALUE( ( AREAP ) pArea, uiIndex, pItem ); +} + /* FPT METHODS */ @@ -2069,48 +3296,17 @@ static ERRCODE hb_fptGetVarLen( FPTAREAP pArea, USHORT uiIndex, ULONG * pLength pArea->lpFields[ uiIndex - 1 ].uiType == HB_IT_MEMO ) { ERRCODE uiError; - BOOL bLocked, bDeleted; -#if defined( HB_FPT_USE_READLOCK ) - ULONG ulOffset; -#endif + BOOL fUnLock; - if ( hb_fptIsDbLocked( pArea, &bLocked ) == FAILURE ) - return FAILURE; - -#if defined( HB_FPT_USE_READLOCK ) - if ( SELF_DELETED( ( AREAP ) pArea, &bDeleted ) == FAILURE ) - return FAILURE; - - if ( bLocked || hb_fptReadLock( pArea, uiIndex, &ulOffset ) ) -#else - if ( bLocked || hb_fptFileLockSh( pArea, TRUE ) ) -#endif - { -#ifdef HB_FPT_SAFE - /* Force read record? */ - if ( !bLocked ) - pArea->fValidBuffer = FALSE; - - /* update any pending relations and reread record if necessary */ - uiError = SELF_DELETED( ( AREAP ) pArea, &bDeleted ); - if ( uiError == SUCCESS ) -#endif - *pLength = hb_fptGetMemoLen( pArea, uiIndex - 1 ); - - if ( !bLocked ) - { -#if defined( HB_FPT_USE_READLOCK ) - hb_fptReadUnLock( pArea, ulOffset ) ; -#else - hb_fptFileUnLock( pArea ); -#endif - } - } + uiError = hb_fptLockForRead( pArea, uiIndex, &fUnLock ); + if( uiError == SUCCESS ) + *pLength = hb_fptGetMemoLen( pArea, uiIndex - 1 ); else - { *pLength = 0; - uiError = FAILURE; - } + + if( fUnLock ) + hb_fptFileUnLock( pArea ); + return uiError; } @@ -2123,72 +3319,22 @@ static ERRCODE hb_fptGetVarLen( FPTAREAP pArea, USHORT uiIndex, ULONG * pLength */ static ERRCODE hb_fptGetValue( FPTAREAP pArea, USHORT uiIndex, PHB_ITEM pItem ) { + ERRCODE uiError; HB_TRACE(HB_TR_DEBUG, ("hb_fptGetValue(%p, %hu, %p)", pArea, uiIndex, pItem)); - if( pArea->fHasMemo && pArea->hMemoFile != FS_ERROR && - pArea->lpFields[ uiIndex - 1 ].uiType == HB_IT_MEMO ) + if( !uiIndex || uiIndex > pArea->uiFieldCount ) + return FAILURE; + + uiError = hb_fptGetVarField( pArea, uiIndex, pItem, FS_ERROR ); + + if( uiError != SUCCESS ) { - ERRCODE uiError; - BOOL bLocked, bDeleted; -#if defined( HB_FPT_USE_READLOCK ) - ULONG ulOffset; -#endif - - if ( hb_fptIsDbLocked( pArea, &bLocked ) == FAILURE ) + if( uiError == FAILURE ) return FAILURE; - -#if defined( HB_FPT_USE_READLOCK ) - if ( SELF_DELETED( ( AREAP ) pArea, &bDeleted ) == FAILURE ) - return FAILURE; - - if ( bLocked || hb_fptReadLock( pArea, uiIndex, &ulOffset ) ) -#else - if ( bLocked || hb_fptFileLockSh( pArea, TRUE ) ) -#endif - { -#ifdef HB_FPT_SAFE - /* Force read record? */ - if ( !bLocked ) - pArea->fValidBuffer = FALSE; - /* update any pending relations and reread record if necessary */ - uiError = SELF_DELETED( ( AREAP ) pArea, &bDeleted ); - - if ( uiError == SUCCESS ) -#endif - uiError = hb_fptGetMemo( pArea, uiIndex - 1, pItem ); - - if ( !bLocked ) - { -#if defined( HB_FPT_USE_READLOCK ) - hb_fptReadUnLock( pArea, ulOffset ) ; -#else - hb_fptFileUnLock( pArea ); -#endif - } - } - else - { - uiError = EDBF_LOCK; - } - - if ( uiError != SUCCESS ) - { - PHB_ITEM pError = hb_errNew(); - ERRCODE uiErrorG = hb_dbfGetEGcode( uiError ); - - hb_errPutGenCode( pError, uiErrorG ); - hb_errPutDescription( pError, hb_langDGetErrorDesc( uiErrorG ) ); - hb_errPutSubCode( pError, uiError ); - hb_errPutFlags( pError, EF_CANDEFAULT ); - SELF_ERROR( ( AREAP ) pArea, pError ); - hb_itemRelease( pError ); - return FAILURE; - } - return SUCCESS; + hb_memoErrorRT( pArea, 0, uiError, pArea->szMemoFileName, 0, 0 ); } - else - return SUPER_GETVALUE( ( AREAP ) pArea, uiIndex, pItem ); + return SUCCESS; } /* @@ -2197,61 +3343,23 @@ static ERRCODE hb_fptGetValue( FPTAREAP pArea, USHORT uiIndex, PHB_ITEM pItem ) */ static ERRCODE hb_fptPutValue( FPTAREAP pArea, USHORT uiIndex, PHB_ITEM pItem ) { - BOOL bDeleted; ERRCODE uiError; HB_TRACE(HB_TR_DEBUG, ("hb_fptPutValue(%p, %hu, %p)", pArea, uiIndex, pItem)); - if( pArea->fHasMemo && pArea->hMemoFile != FS_ERROR && - pArea->lpFields[ uiIndex - 1 ].uiType == HB_IT_MEMO ) + if( !uiIndex || uiIndex > pArea->uiFieldCount ) + return FAILURE; + + uiError = hb_fptPutVarField( pArea, uiIndex, pItem ); + if( uiError != SUCCESS ) { - /* update any pending relations and reread record if necessary */ - if( SELF_DELETED( ( AREAP ) pArea, &bDeleted ) == FAILURE ) + if( uiError == FAILURE ) return FAILURE; - - if( !pArea->fPositioned ) - return SUCCESS; - - /* Buffer is hot? */ - if( !pArea->fRecordChanged && SELF_GOHOT( ( AREAP ) pArea ) == FAILURE ) - return FAILURE; - - if( hb_fptFileLockEx( pArea, TRUE ) ) - { - uiError = hb_fptPutMemo( pArea, uiIndex -1, pItem ); -#if defined( HB_FPT_SAFE ) - if( uiError == SUCCESS ) - /* Force writer record to eliminate race condition */ - if ( SELF_GOCOLD( ( AREAP ) pArea ) == FAILURE ) - return FAILURE; -#endif - hb_fptFileUnLock( pArea ); - } - else - { - uiError = EDBF_LOCK; - } - - if( uiError != SUCCESS ) - { - PHB_ITEM pError; - ERRCODE uiErrorG = hb_dbfGetEGcode( uiError ); - - pError = hb_errNew(); - hb_errPutGenCode( pError, uiErrorG ); - hb_errPutDescription( pError, hb_langDGetErrorDesc( uiErrorG ) ); - hb_errPutSubCode( pError, uiError ); - hb_errPutFlags( pError, EF_CANDEFAULT ); - SELF_ERROR( ( AREAP ) pArea, pError ); - hb_itemRelease( pError ); - return FAILURE; - } - return SUCCESS; + hb_memoErrorRT( pArea, 0, uiError, pArea->szMemoFileName, 0, EF_CANDEFAULT ); } - return SUPER_PUTVALUE( ( AREAP ) pArea, uiIndex, pItem); + return SUCCESS; } - /* ( DBENTRYP_V ) hb_fptCloseMemFile : NULL */ /* @@ -2262,26 +3370,87 @@ static ERRCODE hb_fptCreateMemFile( FPTAREAP pArea, LPDBOPENINFO pCreateInfo ) { FPTHEADER fptHeader; ULONG ulNextBlock, ulSize, ulLen; - BOOL bRetry; - PHB_ITEM pError; HB_TRACE(HB_TR_DEBUG, ("hb_fptCreateMemFile(%p, %p)", pArea, pCreateInfo)); if( pCreateInfo ) { - pError = NULL; + PHB_ITEM pError = NULL, pItem = NULL; + BOOL bRetry; + + if( !pArea->bMemoType ) + { + pItem = hb_itemPutNI( pItem, 0 ); + if( SELF_INFO( ( AREAP ) pArea, DBI_MEMOTYPE, pItem ) != SUCCESS ) + { + hb_itemRelease( pItem ); + return FAILURE; + } + pArea->bMemoType = hb_itemGetNI( pItem ); +/* + if( !pArea->bMemoType ) + { + pArea->bMemoType = DB_MEMO_FPT; + pArea->uiMemoVersion = DB_MEMOVER_FLEX; + } +*/ + if( pArea->bMemoType != DB_MEMO_DBT && + pArea->bMemoType != DB_MEMO_FPT && + pArea->bMemoType != DB_MEMO_SMT ) + { + hb_memoErrorRT( pArea, EG_CREATE, EDBF_MEMOTYPE, + ( char * ) pCreateInfo->abName, 0, 0 ); + return FAILURE; + } + } + if( !pArea->uiMemoVersion ) + { + if( pArea->bMemoType == DB_MEMO_SMT ) + pArea->uiMemoVersion = DB_MEMOVER_SIX; + else if( pArea->bMemoType == DB_MEMO_FPT ) + { + pItem = hb_itemPutNI( pItem, 0 ); + if( SELF_INFO( ( AREAP ) pArea, DBI_MEMOVERSION, pItem ) != SUCCESS ) + { + hb_itemRelease( pItem ); + return FAILURE; + } + pArea->uiMemoVersion = hb_itemGetNI( pItem ); + } + else + pArea->uiMemoVersion = DB_MEMOVER_STD; + } + if( !pArea->uiMemoBlockSize ) + { + pItem = hb_itemPutNI( pItem, 0 ); + if( SELF_INFO( ( AREAP ) pArea, DBI_MEMOBLOCKSIZE, pItem ) != SUCCESS ) + { + hb_itemRelease( pItem ); + return FAILURE; + } + pArea->uiMemoBlockSize = hb_itemGetNI( pItem ); + } + if( pItem ) + { + hb_itemRelease( pItem ); + } + /* Try create */ do { - pArea->hMemoFile = hb_spCreate( pCreateInfo->abName, FC_NORMAL ); + pArea->hMemoFile = hb_fsExtOpen( pCreateInfo->abName, NULL, + FO_READWRITE | FO_EXCLUSIVE | FXO_TRUNCATE | + FXO_DEFAULTS | FXO_SHARELOCK, + NULL, pError ); if( pArea->hMemoFile == FS_ERROR ) { if( !pError ) { pError = hb_errNew(); hb_errPutGenCode( pError, EG_CREATE ); - hb_errPutSubCode( pError, EDBF_CREATE_DBF ); + hb_errPutSubCode( pError, EDBF_CREATE_MEMO ); hb_errPutDescription( pError, hb_langDGetErrorDesc( EG_CREATE ) ); + hb_errPutOsCode( pError, hb_fsError() ); hb_errPutFileName( pError, ( char * ) pCreateInfo->abName ); hb_errPutFlags( pError, EF_CANRETRY ); } @@ -2300,32 +3469,37 @@ static ERRCODE hb_fptCreateMemFile( FPTAREAP pArea, LPDBOPENINFO pCreateInfo ) hb_fsSeek( pArea->hMemoFile, 0, FS_SET ); memset( &fptHeader, 0, sizeof( FPTHEADER ) ); - pArea->uiMemoBlockSize = ( hb_set.HB_SET_MBLOCKSIZE > 0 && - hb_set.HB_SET_MBLOCKSIZE < 0xFFFF ) ? - hb_set.HB_SET_MBLOCKSIZE : FPT_DEFBLOCKSIZE; - pArea->bMemoType = MEMO_FPT_HB; - //pArea->bMemoType = MEMO_FPT_SIX; - - ulNextBlock = ( sizeof( FPTHEADER ) + pArea->uiMemoBlockSize - 1 ) / pArea->uiMemoBlockSize; - HB_PUT_BE_UINT32( fptHeader.nextBlock, ulNextBlock ); - HB_PUT_BE_UINT16( fptHeader.blockSize, pArea->uiMemoBlockSize ); - if ( pArea->bMemoType == MEMO_FPT_SIX || - pArea->bMemoType == MEMO_FPT_SIXHB ) + ulSize = 512; + if ( pArea->uiMemoVersion == DB_MEMOVER_SIX ) { strcpy( ( char *) fptHeader.signature1, "SIxMemo" ); - ulSize = 512; } else { strcpy( ( char *) fptHeader.signature1, "Harbour" ); - strcpy( ( char *) fptHeader.signature2, "FlexFile3\003" ); - ulSize = sizeof( FPTHEADER ); + if( pArea->uiMemoVersion == DB_MEMOVER_FLEX || + pArea->uiMemoVersion == DB_MEMOVER_CLIP ) + { + strcpy( ( char *) fptHeader.signature2, "FlexFile3\003" ); + ulSize = sizeof( FPTHEADER ); + } + } + ulNextBlock = ( ulSize + pArea->uiMemoBlockSize - 1 ) / pArea->uiMemoBlockSize; + if( pArea->bMemoType == DB_MEMO_SMT || pArea->bMemoType == DB_MEMO_DBT ) + { + HB_PUT_LE_UINT32( fptHeader.nextBlock, ulNextBlock ); + HB_PUT_LE_UINT32( fptHeader.blockSize, pArea->uiMemoBlockSize ); + } + else + { + HB_PUT_BE_UINT32( fptHeader.nextBlock, ulNextBlock ); + HB_PUT_BE_UINT32( fptHeader.blockSize, pArea->uiMemoBlockSize ); } if( hb_fsWrite( pArea->hMemoFile, ( BYTE * ) &fptHeader, ( USHORT) ulSize ) != ( USHORT ) ulSize ) return FAILURE; - memset( &fptHeader, 0, sizeof( FPTHEADER ) ); ulLen = ulNextBlock * pArea->uiMemoBlockSize - ulSize; + memset( &fptHeader, 0, sizeof( FPTHEADER ) ); while ( ulLen > 0 ) { ulSize = HB_MIN( ulLen, sizeof( FPTHEADER ) ); @@ -2340,7 +3514,57 @@ static ERRCODE hb_fptCreateMemFile( FPTAREAP pArea, LPDBOPENINFO pCreateInfo ) } -/* ( DBENTRYP_SVPB ) hb_fptGetValueFile : NULL */ +/* + * BLOB2FILE - retrieve memo contents into file + * ( DBENTRYP_SVPB ) hb_fptGetValueFile + */ +static ERRCODE hb_fptGetValueFile( FPTAREAP pArea, USHORT uiIndex, BYTE * szFile, USHORT uiMode ) +{ + HB_TRACE(HB_TR_DEBUG, ("hb_fptGetValueFile(%p, %hu, %s, %hu)", pArea, uiIndex, szFile, uiMode)); + + if( !uiIndex || uiIndex > pArea->uiFieldCount ) + return FAILURE; + + if( pArea->fHasMemo && pArea->hMemoFile != FS_ERROR && + ( pArea->lpFields[ uiIndex - 1 ].uiType == HB_IT_MEMO || + pArea->lpFields[ uiIndex - 1 ].uiType == HB_IT_ANY ) ) + { + USHORT uiError; + FHANDLE hFile; + + hFile = hb_fsExtOpen( szFile, NULL, FO_WRITE | FO_EXCLUSIVE | + FXO_DEFAULTS | FXO_SHARELOCK | + ( uiMode == FILEGET_APPEND ? + FXO_APPEND : FXO_TRUNCATE ), + NULL, NULL ); + + if( hFile == FS_ERROR ) + { + uiError = uiMode != FILEGET_APPEND ? EDBF_CREATE : EDBF_OPEN_DBF; + } + else + { + hb_fsSeekLarge( hFile, 0, FS_END ); + uiError = hb_fptGetVarField( pArea, uiIndex, NULL, hFile ); + hb_fsClose( hFile ); + } + + /* Exit if any error */ + if( uiError != SUCCESS ) + { + if( uiError != FAILURE ) + { + hb_memoErrorRT( pArea, 0, uiError, + uiError == EDBF_OPEN_DBF || uiError == EDBF_CREATE || + uiError == EDBF_WRITE ? ( char * ) szFile : + pArea->szMemoFileName, 0, 0 ); + } + return FAILURE; + } + return SUCCESS; + } + return SUPER_GETVALUEFILE( ( AREAP ) pArea, uiIndex, szFile, uiMode ); +} /* * Open a memo file in the specified WorkArea. @@ -2350,11 +3574,19 @@ static ERRCODE hb_fptOpenMemFile( FPTAREAP pArea, LPDBOPENINFO pOpenInfo ) { USHORT uiFlags; BOOL bRetry; - FPTHEADER fptHeader; PHB_ITEM pError; HB_TRACE(HB_TR_DEBUG, ("hb_fptOpenMemFile(%p, %p)", pArea, pOpenInfo)); + if( pArea->bMemoType != DB_MEMO_DBT && + pArea->bMemoType != DB_MEMO_FPT && + pArea->bMemoType != DB_MEMO_SMT ) + { + hb_memoErrorRT( pArea, EG_OPEN, EDBF_MEMOTYPE, + ( char * ) pOpenInfo->abName, 0, 0 ); + return FAILURE; + } + uiFlags = (pOpenInfo->fReadonly ? FO_READ : FO_READWRITE) | (pOpenInfo->fShared ? FO_DENYNONE : FO_EXCLUSIVE); pError = NULL; @@ -2362,15 +3594,18 @@ static ERRCODE hb_fptOpenMemFile( FPTAREAP pArea, LPDBOPENINFO pOpenInfo ) /* Try open */ do { - pArea->hMemoFile = hb_spOpen( pOpenInfo->abName, uiFlags ); + pArea->hMemoFile = hb_fsExtOpen( pOpenInfo->abName, NULL, uiFlags | + FXO_DEFAULTS | FXO_SHARELOCK, + NULL, pError ); if( pArea->hMemoFile == FS_ERROR ) { if( !pError ) { pError = hb_errNew(); hb_errPutGenCode( pError, EG_OPEN ); - hb_errPutSubCode( pError, EDBF_OPEN_DBF ); + hb_errPutSubCode( pError, EDBF_OPEN_MEMO ); hb_errPutDescription( pError, hb_langDGetErrorDesc( EG_OPEN ) ); + hb_errPutOsCode( pError, hb_fsError() ); hb_errPutFileName( pError, ( char * ) pOpenInfo->abName ); hb_errPutFlags( pError, EF_CANRETRY | EF_CANDEFAULT ); } @@ -2386,93 +3621,140 @@ static ERRCODE hb_fptOpenMemFile( FPTAREAP pArea, LPDBOPENINFO pOpenInfo ) if( pArea->hMemoFile == FS_ERROR ) return FAILURE; - pArea->uiMemoBlockSize = 0; - memset( &fptHeader, 0, sizeof( FPTHEADER ) ); - if( hb_fptFileLockSh( pArea, TRUE ) ) + if( pArea->bMemoType == DB_MEMO_DBT ) { - hb_fsSeek( pArea->hMemoFile, 0, FS_SET ); - if ( hb_fsRead( pArea->hMemoFile, ( BYTE * ) &fptHeader, sizeof( FPTHEADER ) ) >= 512 ) + pArea->uiMemoBlockSize = DBT_DEFBLOCKSIZE; + } + else + { + FPTHEADER fptHeader; + memset( &fptHeader, 0, sizeof( FPTHEADER ) ); + if( hb_fptFileLockSh( pArea, TRUE ) ) { - pArea->uiMemoBlockSize = HB_GET_BE_UINT16( fptHeader.blockSize ); - pArea->bMemoType = 0; - /* Check for compatibility with Harbour memo headers */ - if ( memcmp( fptHeader.signature1, "Harbour", 7 ) == 0 ) + hb_fsSeek( pArea->hMemoFile, 0, FS_SET ); + if( hb_fsRead( pArea->hMemoFile, ( BYTE * ) &fptHeader, sizeof( FPTHEADER ) ) >= 512 ) { - /* hack for detecting old harbour FPT files without FLEX support */ - if ( HB_GET_BE_UINT32( fptHeader.signature2 ) == FPTIT_TEXT ) - pArea->bMemoType = MEMO_FPT_SIXHB; + pArea->uiMemoVersion = DB_MEMOVER_STD; + if( pArea->bMemoType == DB_MEMO_SMT ) + pArea->uiMemoBlockSize = ( USHORT ) HB_GET_LE_UINT32( fptHeader.blockSize ); else - pArea->bMemoType = MEMO_FPT_HB; - } - /* Check for compatibility with SIX memo headers */ - else if ( memcmp( fptHeader.signature1, "SIxMemo", 7 ) == 0 ) - { - pArea->bMemoType = MEMO_FPT_SIX; - } - /* Check for compatibility with CLIP (www.itk.ru) memo headers */ - else if( memcmp( fptHeader.signature1, "Made by CLIP", 12 ) == 0 ) - { - pArea->bMemoType = MEMO_FPT_CLIP; - } - /* Check for compatibility with Clipper 5.3/FlexFile3 malformed memo headers */ - if ( pArea->bMemoType != MEMO_FPT_SIX && - memcmp( fptHeader.signature2, "FlexFile3\003", 10) == 0 ) - { - pArea->bMemoType = MEMO_FPT_FLEX; - if ( pArea->uiMemoBlockSize == 0 ) - pArea->uiMemoBlockSize = HB_GET_LE_UINT16( fptHeader.flexSize ); + pArea->uiMemoBlockSize = ( USHORT ) HB_GET_BE_UINT32( fptHeader.blockSize ); + /* Check for compatibility with SIX memo headers */ + if( memcmp( fptHeader.signature1, "SIxMemo", 7 ) == 0 ) + { + pArea->uiMemoVersion = DB_MEMOVER_SIX; + } + /* Check for compatibility with CLIP (www.itk.ru) memo headers */ + else if( memcmp( fptHeader.signature1, "Made by CLIP", 12 ) == 0 ) + { + pArea->uiMemoVersion = DB_MEMOVER_CLIP; + } + /* Check for compatibility with Clipper 5.3/FlexFile3 malformed memo headers */ + if( pArea->uiMemoVersion != DB_MEMOVER_SIX && + memcmp( fptHeader.signature2, "FlexFile3\003", 10) == 0 ) + { + pArea->uiMemoVersion = DB_MEMOVER_FLEX; + if ( pArea->uiMemoBlockSize == 0 ) + pArea->uiMemoBlockSize = HB_GET_LE_UINT16( fptHeader.flexSize ); + } } + hb_fptFileUnLock( pArea ); } - hb_fptFileUnLock( pArea ); } - if ( pArea->uiMemoBlockSize == 0 ) + if( pArea->uiMemoBlockSize == 0 ) { - pError = hb_errNew(); - hb_errPutGenCode( pError, EG_CORRUPTION ); - hb_errPutSubCode( pError, EDBF_CORRUPT ); - hb_errPutDescription( pError, hb_langDGetErrorDesc( EG_CORRUPTION ) ); - hb_errPutFileName( pError, (char *) pOpenInfo->abName ); - SELF_ERROR( ( AREAP ) pArea, pError ); - hb_itemRelease( pError ); + hb_memoErrorRT( pArea, EG_CORRUPTION, EDBF_CORRUPT, + ( char * ) pOpenInfo->abName, 0, 0 ); return FAILURE; } return SUCCESS; } -/* ( DBENTRYP_SVP ) hb_fptPutValueFile : NULL */ - /* - * Read the database file header record in the WorkArea. - * ( DBENTRYP_V ) hb_fptReadDBHeader + * FILE2BLOB - store file contents in MEMO + * ( DBENTRYP_SVPB ) hb_fptPutValueFile */ -static ERRCODE hb_fptReadDBHeader( FPTAREAP pArea ) +static ERRCODE hb_fptPutValueFile( FPTAREAP pArea, USHORT uiIndex, BYTE * szFile, USHORT uiMode ) { - HB_TRACE(HB_TR_DEBUG, ("hb_fptReadDBHeader(%p)", pArea)); + HB_TRACE(HB_TR_DEBUG, ("hb_fptPutValueFile(%p, %hu, %s, %hu)", pArea, uiIndex, szFile, uiMode)); - if( SUPER_READDBHEADER( ( AREAP ) pArea ) == FAILURE ) + if( !uiIndex || uiIndex > pArea->uiFieldCount ) return FAILURE; -// Set in SUPER() now 3/05/2004 -// pArea->fHasMemo = ( pArea->bVersion == 0xF5 ); - - return SUCCESS; -} - -/* - * Write the database file header record in the WorkArea. - * ( DBENTRYP_V ) hb_fptWriteDBHeader - */ -static ERRCODE hb_fptWriteDBHeader( FPTAREAP pArea ) -{ - HB_TRACE(HB_TR_DEBUG, ("hb_fptWriteDBHeader(%p)", pArea)); - - if ( pArea->fHasMemo && pArea->bVersion != 0x30 && pArea->bVersion != 0x31 ) + /* TODO: add "V" field support */ + if( pArea->fHasMemo && pArea->hMemoFile != FS_ERROR && + pArea->lpFields[ uiIndex - 1 ].uiType == HB_IT_MEMO ) { - pArea->bVersion = 0xF5; + USHORT uiError; + BOOL bDeleted; + FHANDLE hFile; + + /* update any pending relations and reread record if necessary */ + uiError = SELF_DELETED( ( AREAP ) pArea, &bDeleted ); + if( uiError != SUCCESS ) + return uiError; + + if( !pArea->fPositioned ) + return FAILURE; + + /* Buffer is hot? */ + if( !pArea->fRecordChanged && SELF_GOHOT( ( AREAP ) pArea ) == FAILURE ) + return FAILURE; + + hFile = hb_fsExtOpen( szFile, NULL, FO_READ | FO_DENYNONE | + FXO_DEFAULTS | FXO_SHARELOCK, NULL, NULL ); + if( hFile == FS_ERROR ) + { + uiError = EDBF_OPEN_DBF; + } + else if( !hb_fptFileLockEx( pArea, TRUE ) ) + { + hb_fsClose( hFile ); + uiError = EDBF_LOCK; + } + else + { + HB_FOFFSET size = hb_fsSeekLarge( hFile, 0, FS_END ); + ULONG ulSize = HB_MIN( size, 0xFFFFFFFF - sizeof( FPTBLOCK ) ), + ulBlock, ulType, ulOldSize, ulOldType; + + if( pArea->bMemoType == DB_MEMO_SMT ) + ulType = SMT_IT_CHAR; + else + ulType = FPTIT_BINARY; + + hb_fsSeekLarge( hFile, 0, FS_SET ); + uiError = hb_dbfGetMemoData( (DBFAREAP) pArea, uiIndex - 1, + &ulBlock, &ulOldSize, &ulOldType ); + if( uiError == SUCCESS ) + uiError = hb_fptWriteMemo( pArea, ulBlock, ulOldSize, NULL, hFile, + ulType, ulSize, &ulBlock ); + if( uiError == SUCCESS ) + uiError = hb_dbfSetMemoData( (DBFAREAP) pArea, uiIndex - 1, ulBlock, ulSize, ulType ); +#if defined( HB_MEMO_SAFELOCK ) + if( uiError == SUCCESS ) + { + /* Force writer record to eliminate race condition */ + SELF_GOCOLD( ( AREAP ) pArea ); + } +#endif + hb_fptFileUnLock( pArea ); + hb_fsClose( hFile ); + } + /* Exit if any error */ + if( uiError != SUCCESS ) + { + hb_memoErrorRT( pArea, 0, uiError, + uiError == EDBF_OPEN_DBF || uiError == EDBF_READ ? + ( char * ) szFile : pArea->szMemoFileName, 0, 0 ); + return FAILURE; + } + return SUCCESS; } - return SUPER_WRITEDBHEADER( ( AREAP ) pArea ); + + return SUPER_PUTVALUEFILE( ( AREAP ) pArea, uiIndex, szFile, uiMode ); } /* @@ -2486,7 +3768,7 @@ static ERRCODE hb_fptInfo( FPTAREAP pArea, USHORT uiIndex, PHB_ITEM pItem ) switch( uiIndex ) { case DBI_MEMOEXT: - if ( pArea->fHasMemo && pArea->hMemoFile != FS_ERROR ) + if( pArea->fHasMemo && pArea->hMemoFile != FS_ERROR ) { PHB_FNAME pFileName; @@ -2496,30 +3778,78 @@ static ERRCODE hb_fptInfo( FPTAREAP pArea, USHORT uiIndex, PHB_ITEM pItem ) } else { - hb_itemPutC( pItem, ( hb_set.HB_SET_MFILEEXT && - strlen( hb_set.HB_SET_MFILEEXT ) > 0 ) ? - hb_set.HB_SET_MFILEEXT : - FPT_MEMOEXT ); + LPDBFDATA pData = ( LPDBFDATA ) SELF_RDDNODE( pArea )->lpvCargo; + if( pData->szMemoExt[ 0 ] ) + hb_itemPutC( pItem, pData->szMemoExt ); + else if( pArea->bMemoType == DB_MEMO_FPT && + hb_set.HB_SET_MFILEEXT && hb_set.HB_SET_MFILEEXT[ 0 ] ) + hb_itemPutC( pItem, hb_set.HB_SET_MFILEEXT ); + else + { + char * szExt = hb_memoDefaultFileExt( pArea->bMemoType ); + if( !szExt ) + szExt = hb_memoDefaultFileExt( pData->bMemoType ); + hb_itemPutC( pItem, szExt ); + } + } + break; + + case DBI_MEMOBLOCKSIZE: + if( pArea->fHasMemo && pArea->hMemoFile != FS_ERROR ) + hb_itemPutNI( pItem, pArea->uiMemoBlockSize ); + else if( pArea->bMemoType && pArea->uiMemoBlockSize ) + hb_itemPutNI( pItem, pArea->uiMemoBlockSize ); + else if( pArea->bMemoType == DB_MEMO_DBT ) + hb_itemPutNI( pItem, DBT_DEFBLOCKSIZE ); + else + { + hb_itemClear( pItem ); + return SELF_RDDINFO( SELF_RDDNODE( pArea ), RDDI_MEMOBLOCKSIZE, 0, pItem ); + } + break; + + case DBI_MEMOTYPE: + if( pArea->fHasMemo && pArea->hMemoFile != FS_ERROR ) + hb_itemPutNI( pItem, pArea->bMemoType ); + else if( pArea->bMemoType ) + hb_itemPutNI( pItem, pArea->bMemoType ); + else + { + hb_itemClear( pItem ); + return SELF_RDDINFO( SELF_RDDNODE( pArea ), RDDI_MEMOTYPE, 0, pItem ); + } + break; + + case DBI_MEMOVERSION: + if( pArea->fHasMemo && pArea->hMemoFile != FS_ERROR ) + hb_itemPutNI( pItem, pArea->uiMemoVersion ); + else if( pArea->bMemoType != DB_MEMO_NONE && + pArea->uiMemoVersion != 0 ) + hb_itemPutNI( pItem, pArea->uiMemoVersion ); + else + { + hb_itemClear( pItem ); + return SELF_RDDINFO( SELF_RDDNODE( pArea ), RDDI_MEMOVERSION, 0, pItem ); } break; /* case DBI_RDD_VERSION */ - case DBI_BLOB_DIRECT_EXPORT: - case DBI_BLOB_DIRECT_GET: - case DBI_BLOB_DIRECT_IMPORT: - case DBI_BLOB_DIRECT_PUT: - case DBI_BLOB_ROOT_GET: - case DBI_BLOB_ROOT_PUT: + case DBI_BLOB_DIRECT_EXPORT: /* BLOBDirectExport() { , , */ + case DBI_BLOB_DIRECT_GET: /* BLOBDirectGet() { , , } */ + case DBI_BLOB_DIRECT_IMPORT: /* BLOBDirectImport() { , } */ + case DBI_BLOB_DIRECT_PUT: /* BLOBDirectPut() { , } */ + + case DBI_BLOB_ROOT_GET: /* BLOBRootGet() */ + case DBI_BLOB_ROOT_PUT: /* BLOBRootPut( ) */ break; - case DBI_BLOB_ROOT_LOCK: + case DBI_BLOB_ROOT_LOCK: /* BLOBRootLock() */ hb_itemPutL( pItem, hb_fptFileLockEx( pArea, FALSE ) ); break; - case DBI_BLOB_ROOT_UNLOCK: - hb_fptFileUnLock( pArea ); - hb_itemClear( pItem ); + case DBI_BLOB_ROOT_UNLOCK: /* BLOBRootUnlock() */ + hb_itemPutL( pItem, hb_fptFileUnLock( pArea ) ); break; case DBI_BLOB_DIRECT_LEN: @@ -2551,64 +3881,141 @@ static ERRCODE hb_fptFieldInfo( FPTAREAP pArea, USHORT uiIndex, USHORT uiType, P if( pArea->fHasMemo && pArea->hMemoFile != FS_ERROR && pArea->lpFields[ uiIndex - 1 ].uiType == HB_IT_MEMO ) { - BOOL bLocked; -#if defined( HB_FPT_USE_READLOCK ) - ULONG ulOffset; -#endif + ULONG ulBlock, ulSize, ulType; + switch( uiType ) { - case DBS_BLOB_GET: + case DBS_BLOB_GET: /* BLOBGet() { , } */ + /* TODO: !!! pItem := { , } */ + return SUCCESS; case DBS_BLOB_LEN: + hb_itemPutNL( pItem, hb_fptGetMemoLen( pArea, uiIndex - 1 ) ); + return SUCCESS; case DBS_BLOB_OFFSET: + hb_dbfGetMemoData( (DBFAREAP) pArea, uiIndex - 1, + &ulBlock, &ulSize, &ulType ); + hb_itemPutNInt( pItem, ( HB_FOFFSET ) ulBlock * pArea->uiMemoBlockSize + + pArea->bMemoType == DB_MEMO_FPT ? sizeof( FPTBLOCK ) : 0 ); + return SUCCESS; case DBS_BLOB_POINTER: + hb_dbfGetMemoData( (DBFAREAP) pArea, uiIndex - 1, + &ulBlock, &ulSize, &ulType ); + hb_itemPutNL( pItem, ulBlock ); + return SUCCESS; case DBS_BLOB_TYPE: - break; - default: - return SUPER_FIELDINFO( ( AREAP ) pArea, uiIndex, uiType, pItem ); - } - - if ( hb_fptIsDbLocked( pArea, &bLocked ) == FAILURE ) - return FAILURE; - -#if defined( HB_FPT_USE_READLOCK ) - if ( bLocked || hb_fptReadLock( pArea, uiIndex, &ulOffset ) ) -#else - if ( bLocked || hb_fptFileLockSh( pArea, TRUE ) ) -#endif - { - switch( uiType ) - { - case DBS_BLOB_GET: - /* TODO: !!! pItem := { , } */ - break; - case DBS_BLOB_LEN: - hb_itemPutNL( pItem, hb_fptGetMemoLen( pArea, uiIndex - 1 ) ); - break; - case DBS_BLOB_OFFSET: - hb_itemPutNL( pItem, pArea->uiMemoBlockSize * - hb_dbfGetMemoBlock( (DBFAREAP) pArea, uiIndex - 1 ) ); - break; - case DBS_BLOB_POINTER: - hb_itemPutNL( pItem, - hb_dbfGetMemoBlock( (DBFAREAP) pArea, uiIndex - 1 ) ); - break; - case DBS_BLOB_TYPE: - hb_itemPutC( pItem, hb_fptGetMemoType( pArea, uiIndex - 1 ) ); - break; - } - if ( !bLocked ) - { -#if defined( HB_FPT_USE_READLOCK ) - hb_fptReadUnLock( pArea, ulOffset ) ; -#else - hb_fptFileUnLock( pArea ); -#endif - } + hb_itemPutC( pItem, hb_fptGetMemoType( pArea, uiIndex - 1 ) ); + return SUCCESS; } } - else + return SUPER_FIELDINFO( ( AREAP ) pArea, uiIndex, uiType, pItem ); +} + +/* + * Retrieve (set) information about RDD + * ( DBENTRYP_RSLV ) hb_fptRddInfo + */ +static ERRCODE hb_fptRddInfo( LPRDDNODE pRDD, USHORT uiIndex, ULONG ulConnect, PHB_ITEM pItem ) +{ + LPDBFDATA pData; + + HB_TRACE(HB_TR_DEBUG, ("hb_fptRddInfo(%p, %hu, %lu, %p)", pRDD, uiIndex, ulConnect, pItem)); + + pData = ( LPDBFDATA ) pRDD->lpvCargo; + + switch( uiIndex ) { - return SUPER_FIELDINFO( ( AREAP ) pArea, uiIndex, uiType, pItem ); + case RDDI_MEMOEXT: + { + char * szNew = hb_itemGetCPtr( pItem ); + + if( szNew && szNew[0] == '.' && szNew[1] ) + szNew = hb_strdup( szNew ); + else + szNew = NULL; + + if( pData->szMemoExt[ 0 ] ) + hb_itemPutC( pItem, pData->szMemoExt ); + else if( pData->bMemoType == DB_MEMO_FPT && + hb_set.HB_SET_MFILEEXT && hb_set.HB_SET_MFILEEXT[ 0 ] ) + hb_itemPutC( pItem, hb_set.HB_SET_MFILEEXT ); + else + hb_itemPutC( pItem, hb_memoDefaultFileExt( pData->bMemoType ) ); + + if( szNew ) + { + hb_strncpy( pData->szMemoExt, szNew, HB_MAX_FILE_EXT ); + hb_xfree( szNew ); + } + break; + } + case RDDI_MEMOBLOCKSIZE: + { + int iSize = hb_itemGetNI( pItem ); + + if( pData->uiMemoBlockSize ) + hb_itemPutNI( pItem, pData->uiMemoBlockSize ); + else if( hb_set.HB_SET_MBLOCKSIZE > 0 && hb_set.HB_SET_MBLOCKSIZE <= 0xFFFF ) + hb_itemPutNI( pItem, hb_set.HB_SET_MBLOCKSIZE ); + else if( pData->bMemoType == DB_MEMO_DBT ) + hb_itemPutNI( pItem, DBT_DEFBLOCKSIZE ); + else if( pData->bMemoType == DB_MEMO_SMT ) + hb_itemPutNI( pItem, SMT_DEFBLOCKSIZE ); + else + hb_itemPutNI( pItem, FPT_DEFBLOCKSIZE ); + + if( iSize > 0 && iSize <= 0xFFFF ) + pData->uiMemoBlockSize = iSize; + break; + } + case RDDI_MEMOTYPE: + { + int iType = hb_itemGetNI( pItem ); + + hb_itemPutNI( pItem, pData->bMemoType ? pData->bMemoType : DB_MEMO_FPT ); + + switch( iType ) + { + case DB_MEMO_DBT: + case DB_MEMO_FPT: + case DB_MEMO_SMT: + pData->bMemoType = ( BYTE ) iType; + } + break; + } + + case RDDI_MEMOVERSION: + { + int iType = hb_itemGetNI( pItem ); + + hb_itemPutNI( pItem, pData->bMemoExtType ? pData->bMemoExtType : DB_MEMOVER_FLEX ); + switch( iType ) + { + case DB_MEMOVER_STD: + case DB_MEMOVER_SIX: + case DB_MEMOVER_FLEX: + case DB_MEMOVER_CLIP: + pData->bMemoExtType = ( BYTE ) iType; + } + break; + } + + case RDDI_MEMOGCTYPE: + hb_itemPutNI( pItem, 0 ); + break; + case RDDI_MEMOREADLOCK: +#if defined( HB_MEMO_SAFELOCK ) + hb_itemPutL( pItem, TRUE ); +#else + hb_itemPutL( pItem, FALSE ); +#endif + break; + case RDDI_MEMOREUSE: + hb_itemPutL( pItem, TRUE ); + break; + + default: + return SUPER_RDDINFO( pRDD, uiIndex, ulConnect, pItem ); } + return SUCCESS; } diff --git a/harbour/source/rdd/dbfntx/Makefile b/harbour/source/rdd/dbfntx/Makefile index ce7f7ef235..56d3c565ac 100644 --- a/harbour/source/rdd/dbfntx/Makefile +++ b/harbour/source/rdd/dbfntx/Makefile @@ -10,6 +10,10 @@ C_SOURCES=\ PRG_SOURCES=\ dbfntx0.prg \ +ifeq ($(HB_MT),MT) + MT_LIBNAME=dbfntxmt +endif + LIBNAME=dbfntx include $(TOP)$(ROOT)config/lib.cf diff --git a/harbour/source/rdd/dbfntx/dbfntx0.prg b/harbour/source/rdd/dbfntx/dbfntx0.prg index d251392ad3..e692ddfc20 100644 --- a/harbour/source/rdd/dbfntx/dbfntx0.prg +++ b/harbour/source/rdd/dbfntx/dbfntx0.prg @@ -52,15 +52,18 @@ #include "error.ch" #include "rddsys.ch" +#include "dbinfo.ch" ANNOUNCE DBFNTX procedure DBFNTXInit + REQUEST _DBF REQUEST _DBFNTX rddRegister( "DBF", RDT_FULL ) rddRegister( "DBFNTX", RDT_FULL ) + rddInfo( RDDI_MEMOTYPE, DB_MEMO_DBT, "DBFNTX" ) return diff --git a/harbour/source/rdd/dbfntx/dbfntx1.c b/harbour/source/rdd/dbfntx/dbfntx1.c index 8134e77043..3edd59fb8e 100644 --- a/harbour/source/rdd/dbfntx/dbfntx1.c +++ b/harbour/source/rdd/dbfntx/dbfntx1.c @@ -55,7 +55,7 @@ * * commonError() * hb_IncString() - * numToStr() + * ntxNumToStr() * checkLogicalExpr() * hb__ntxTagKeyCount() * hb_ntxInTopScope() @@ -116,25 +116,36 @@ * ntxSetScope() */ +/* + * Copyright 2005 Przemyslaw Czerpak + * in practice most of the code rewritten + */ + +/* #define HB_NTX_NOMULTITAG */ + +/* #define HB_NTX_EXTERNAL_PAGEBUFFER */ + +/* +#define HB_NTX_DEBUG +#define HB_NTX_DEBUG_EXT +#define HB_NTX_DEBUG_DISP +*/ + #include "hbapi.h" #include "hbinit.h" -#include "hbapiitm.h" -#include "hbvm.h" -#include "hbstack.h" -#include "rddsys.ch" -#include "hbset.h" #include "hbapierr.h" #include "hbapilng.h" +#include "hbvm.h" +#include "hbset.h" +#include "hbmath.h" #include "hbrddntx.h" +#ifdef __XHARBOUR__ +#include "hbregex.h" +#endif #ifndef HB_CDP_SUPPORT_OFF #include "hbapicdp.h" #endif -#include -#ifdef HB_OS_BSD -#include /* We need mkstemp() */ -#endif - #define __PRG_SOURCE__ __FILE__ #ifdef HB_PCODE_VER @@ -142,8 +153,6 @@ #define HB_PRG_PCODE_VER HB_PCODE_VER #endif -extern USHORT hb_rddFieldIndex( AREAP pArea, char * szName ); - HB_FUNC( _DBFNTX ); HB_FUNC( DBFNTX_GETFUNCTABLE ); @@ -154,7 +163,7 @@ HB_INIT_SYMBOLS_END( dbfntx1__InitSymbols ) #if defined(HB_PRAGMA_STARTUP) #pragma startup dbfntx1__InitSymbols -#elif defined(_MSC_VER) +#elif defined(HB_MSC_STARTUP) #if _MSC_VER >= 1010 #pragma data_seg( ".CRT$XIY" ) #pragma comment( linker, "/Merge:.CRT=.data" ) @@ -165,490 +174,200 @@ HB_INIT_SYMBOLS_END( dbfntx1__InitSymbols ) #pragma data_seg() #endif +#ifdef HB_NTX_DEBUG_DISP + static ULONG s_rdNO = 0; + static ULONG s_wrNO = 0; +#endif static RDDFUNCS ntxSuper; +static USHORT s_uiRddId; -/* Internal functions */ -static LPKEYINFO hb_ntxKeyNew( LPKEYINFO pKeyFrom, int keylen ); -static LONG hb_ntxTagKeyFind( LPTAGINFO pTag, LPKEYINFO pKey, int keylen, BOOL* result, BOOL bSoftSeek ); -static BOOL hb_ntxIsRecBad( NTXAREAP pArea, LONG ulRecNo ); -static int hb_ntxTagFindCurrentKey( LPTAGINFO pTag, LPPAGEINFO pPage, LPKEYINFO pKey, int keylen, BOOL bExact, int lSeek ); -static USHORT hb_ntxPageFindCurrentKey( LPPAGEINFO pPage, ULONG ulRecno ); -static void hb_ntxGetCurrentKey( LPTAGINFO pTag, LPKEYINFO pKey ); -static void hb_ntxTagKeyGoTo( LPTAGINFO pTag, BYTE bTypRead, BOOL * lContinue ); -static LPPAGEINFO hb_ntxPageFind( LPTAGINFO pTag ,LONG ulOffset ); -static ERRCODE hb_ntxHeaderRead( LPNTXINDEX pIndex ); -static ERRCODE hb_ntxHeaderLoad( LPNTXINDEX pIndex , char * ITN ); - /* Load NTX header an fill structures pIndex */ -static void hb_ntxHeaderSave( LPNTXINDEX pIndex, BOOL bFull ); - /* Save NTX header */ +static BOOL s_fSortRecNo = FALSE; +static BOOL s_fMultiKey = FALSE; +static BOOL s_fStruct = FALSE; +static BOOL s_fStrictStruct = FALSE; +#if !defined( HB_NTX_NOMULTITAG ) +static BOOL s_fMultiTag = TRUE; +#endif -static LPNTXINDEX hb_ntxIndexNew( NTXAREAP pArea ); - /* Allocate space for information about Index and find free ID */ -static void hb_ntxIndexFree( LPNTXINDEX pIndex ); - /* Release all resources associated with index */ -static ERRCODE hb_ntxIndexCreate( LPNTXINDEX pIndex ); - /* Create index from database */ +#define hb_ntxKeyFree(K) hb_xfree(K) +#define hb_ntxFileOffset(I,B) ( (B) << ( (I)->LargeFile ? NTXBLOCKBITS : 0 ) ) +#define hb_ntxPageBuffer(p) ( (p)->buffer ) -static LPTAGINFO hb_ntxTagNew( LPNTXINDEX PIF, char * ITN, BOOL fTagName, char *szKeyExpr, - PHB_ITEM pKeyExpr, BYTE bKeyType, USHORT uiKeyLen, USHORT uiKeyDec, char *szForExp, - PHB_ITEM pForExp, BOOL fAscendKey, BOOL fUnique, BOOL fCustom, BOOL fMemory ); - /* Create Compound Tag with information about index */ +/* + * The helper functions (endian dependent) - on big endian machines + * or RISC with strict alignment it's much better to use functions + * then macros to inform compiler that can count complex parameters + * only once. + * On other machines it should not cause noticeable differences because + * most of modern C compilers auto inline small functions + */ +#if defined( HB_LITTLE_ENDIAN ) && !defined( HB_STRICT_ALIGNMENT ) -static LPPAGEINFO hb_ntxPageNew(LPTAGINFO pParentTag ); - /* Allocate space for new page */ -static void hb_ntxPageRelease( LPTAGINFO pTag, LPPAGEINFO pPage ); -static void hb_ntxPageFree( LPTAGINFO pTag, BOOL lFull ); - /* Release memory allocated for page. If page was modified save it */ -static LPPAGEINFO hb_ntxPageLoad( LPTAGINFO pTag, ULONG ulOffset ); - /* Load page from disk */ -static int hb_ntxItemCompare( char* s1, char* s2, int ilen1, int ilen2, BOOL Exact, PHB_CODEPAGE cdpage ); +#define hb_ntxGetKeyCount(p) HB_GET_LE_UINT16( hb_ntxPageBuffer(p) ) +#define hb_ntxSetKeyCount(p,n) HB_PUT_LE_UINT16( hb_ntxPageBuffer(p), (n) ) -#define KEYITEM(P,N) ( (NTXITEM*)( (P)->buffer+ *((USHORT*)((P)->buffer+(N)*2+2)) ) ) -#define KEYPOINTER(P,N) ( (USHORT*)((P)->buffer+(N)*2+2) ) -#define hb_ntxKeyFree(K) hb_xfree(K) +#define hb_ntxGetKeyOffset(p,n) HB_GET_LE_UINT16( hb_ntxPageBuffer(p)+2+((n)<<1) ) +#define hb_ntxGetKeyPtr(p,n) ( hb_ntxPageBuffer(p) + hb_ntxGetKeyOffset(p,n) ) +#define hb_ntxGetKeyPage(p,n) HB_GET_LE_UINT32( hb_ntxGetKeyPtr(p,n) ) +#define hb_ntxGetKeyRec(p,n) HB_GET_LE_UINT32( hb_ntxGetKeyPtr(p,n)+4 ) +#define hb_ntxGetKeyVal(p,n) ( hb_ntxGetKeyPtr(p,n)+8 ) -static ULONG* hb_ntxKeysInPage( ULONG ulRecCount, USHORT maxkeys ) +#define hb_ntxSetKeyOffset(p,n,u) HB_PUT_LE_UINT16( hb_ntxPageBuffer(p)+2+((n)<<1), u ) +#define hb_ntxSetKeyPage(p,n,l) HB_PUT_LE_UINT32( hb_ntxGetKeyPtr(p,n), l ) +#define hb_ntxSetKeyRec(p,n,l) HB_PUT_LE_UINT32( hb_ntxGetKeyPtr(p,n)+4, l ) + +#else + +static USHORT hb_ntxGetKeyCount( LPPAGEINFO pPage ) { - double dSum = 0, koeff, _maxkeys = (double) maxkeys, - recCount = (double)ulRecCount, dMul = 1; - int iLevel = 0, i, j; - ULONG *lpArray; - - do - { - dSum += maxkeys * dMul; - dMul *= (_maxkeys+1); - iLevel ++; - } - while( dSum < recCount ); - - lpArray = (ULONG*) hb_xgrab( sizeof(ULONG) * (iLevel+2) ); - lpArray[0] = (ULONG)iLevel; - for( i=1; i<=iLevel; i++ ) - lpArray[i] = 0; - - if( recCount > 0 ) - { - for( i=iLevel; i; i-- ) - { - koeff = dSum / recCount; - lpArray[i] = (ULONG) ceil( _maxkeys/koeff ); - dMul = 1; - for( j=iLevel,dSum=0; j; j-- ) - { - dSum += ( (lpArray[j])? lpArray[j]:maxkeys ) * dMul; - if( j > 1 ) - dMul *= (double)(( (lpArray[j])? lpArray[j]:maxkeys )+1); - } - } - dSum -= recCount; - lpArray[iLevel+1] = (dMul > dSum)? (ULONG)(dMul - dSum):(ULONG)dMul; - } - else - { - lpArray[1] = maxkeys; - lpArray[2] = 0; - } - - return lpArray; + char * ptr = hb_ntxPageBuffer( pPage ); + return HB_GET_LE_UINT16( ptr ); } -static void commonError( NTXAREAP pArea, USHORT uiGenCode, USHORT uiSubCode, char* filename, USHORT uiFlags ) +static void hb_ntxSetKeyCount( LPPAGEINFO pPage, USHORT uiKeys ) +{ + char * ptr = hb_ntxPageBuffer( pPage ); + HB_PUT_LE_UINT16( ptr, uiKeys ); +} + +static USHORT hb_ntxGetKeyOffset( LPPAGEINFO pPage, SHORT iKey ) +{ + char * ptr = hb_ntxPageBuffer( pPage ) + 2 + ( iKey << 1 ); + return HB_GET_LE_UINT16( ptr ); +} + +static void hb_ntxSetKeyOffset( LPPAGEINFO pPage, SHORT iKey, USHORT uiOffset ) +{ + char * ptr = hb_ntxPageBuffer( pPage ) + 2 + ( iKey << 1 ); + HB_PUT_LE_UINT16( ptr, uiOffset ); +} + +static char * hb_ntxGetKeyPtr( LPPAGEINFO pPage, SHORT iKey ) +{ + return hb_ntxPageBuffer( pPage ) + hb_ntxGetKeyOffset( pPage, iKey ); +} + +static ULONG hb_ntxGetKeyPage( LPPAGEINFO pPage, SHORT iKey ) +{ + char * ptr = hb_ntxGetKeyPtr( pPage, iKey ); + return HB_GET_LE_UINT32( ptr ); +} + +static void hb_ntxSetKeyPage( LPPAGEINFO pPage, SHORT iKey, ULONG ulPage ) +{ + char * ptr = hb_ntxGetKeyPtr( pPage, iKey ); + HB_PUT_LE_UINT32( ptr, ulPage ); +} + +static char * hb_ntxGetKeyVal( LPPAGEINFO pPage, SHORT iKey ) +{ + return hb_ntxGetKeyPtr( pPage, iKey ) + 8; +} + +static void hb_ntxSetKeyRec( LPPAGEINFO pPage, SHORT iKey, ULONG ulRec ) +{ + char * ptr = hb_ntxGetKeyPtr( pPage, iKey ) + 4; + HB_PUT_LE_UINT32( ptr, ulRec ); +} + +static ULONG hb_ntxGetKeyRec( LPPAGEINFO pPage, SHORT iKey ) +{ + char * ptr = hb_ntxGetKeyPtr( pPage, iKey ) + 4; + return HB_GET_LE_UINT32( ptr ); +} + +#endif + +/* + * generate Run-Time error + */ +static ERRCODE hb_ntxErrorRT( NTXAREAP pArea, USHORT uiGenCode, USHORT uiSubCode, char * szFileName, USHORT uiOsCode, USHORT uiFlags ) { PHB_ITEM pError; + ERRCODE iRet = FAILURE; - pError = hb_errNew(); - hb_errPutGenCode( pError, uiGenCode ); - hb_errPutSubCode( pError, uiSubCode ); - hb_errPutDescription( pError, hb_langDGetErrorDesc( uiGenCode ) ); - if( filename ) - hb_errPutFileName( pError, filename ); - if( uiFlags ) - hb_errPutFlags( pError, uiFlags ); - SUPER_ERROR( ( AREAP ) pArea, pError ); - hb_errRelease( pError ); - return; -} - -static void hb_IncString( NTXAREAP pArea, char* s, int slen ) -{ - char *ptr; - UINT nsymb; - - for( ptr=s+slen-1;ptr>=s;ptr-- ) + if( hb_vmRequestQuery() == 0 ) { - nsymb = (UINT) *ptr; - if( nsymb < 255 ) - { - UINT n1, i; - if( pArea->cdPage->lSort && ( n1 = (UINT) pArea->cdPage->s_chars[ nsymb ] ) != 0 ) - { - n1 ++; - for( i=0; i<255; i++ ) - { - if( n1 == (UINT) pArea->cdPage->s_chars[ i ] ) - { - *ptr = (char) i; - break; - } - } - if( i >= 255 ) - *ptr = (char) ++nsymb; - } - else - *ptr = (char) ++nsymb; - break; - } + pError = hb_errNew(); + hb_errPutGenCode( pError, uiGenCode ); + hb_errPutSubCode( pError, uiSubCode ); + hb_errPutOsCode( pError, uiOsCode ); + hb_errPutDescription( pError, hb_langDGetErrorDesc( uiGenCode ) ); + if( szFileName ) + hb_errPutFileName( pError, szFileName ); + if( uiFlags ) + hb_errPutFlags( pError, uiFlags ); + iRet = SELF_ERROR( ( AREAP ) pArea, pError ); + hb_errRelease( pError ); } + return iRet; } -static void hb_DecString( NTXAREAP pArea, char* s, int slen ) -{ - char *ptr; - UINT nsymb; - - for( ptr=s+slen-1;ptr>=s;ptr-- ) - { - nsymb = (UINT) *ptr; - if( nsymb > 0 ) - { - UINT n1, i; - if( pArea->cdPage->lSort && ( n1 = (UINT) pArea->cdPage->s_chars[ nsymb ] ) != 0 ) - { - n1 --; - for( i=0; i<255; i++ ) - { - if( n1 == (UINT) pArea->cdPage->s_chars[ i ] ) - { - *ptr = (char) i; - break; - } - } - if( i >= 255 ) - *ptr = (char) --nsymb; - } - else - *ptr = (char) --nsymb; - break; - } - } -} - -static char * numToStr( PHB_ITEM pItem, char* szBuffer, USHORT length, USHORT dec ) +/* + * convert numeric item into NTX key value + */ +static char * hb_ntxNumToStr( PHB_ITEM pItem, char* szBuffer, USHORT length, USHORT dec ) { char *ptr = szBuffer; hb_itemStrBuf( szBuffer, pItem, length, dec ); while( *ptr == ' ' ) - { *ptr++ = '0'; - } if( *ptr == '-' ) { *ptr = '0'; - szBuffer[0] = ','; - for( ptr = &szBuffer[1]; *ptr; ptr++ ) + for( ptr = &szBuffer[0]; *ptr; ptr++ ) { if( *ptr >= '0' && *ptr <= '9' ) - { - *ptr = (char) ( 92 - (int)*ptr ); - } + *ptr = (char) ( '0' - ( *ptr - '0' ) - 4 ); + /* + * I intentionally used the above formula to avoid problems on + * non ASCII machines though many of other xHarbour codes is + * hard coded to ASCII values and should be fixed. Druzus. + */ } } return szBuffer; } -/* Implementation of internal functions */ - -static BOOL checkLogicalExpr( PHB_ITEM pForItem, PHB_ITEM pItem ) +/* + * convert numeric NTX key value into item + */ +static PHB_ITEM hb_ntxStrToNum( PHB_ITEM pItem, char* szKeyVal, USHORT length, USHORT dec ) { - HB_MACRO_PTR pMacro; - BOOL res, lNewItem = FALSE; + char szBuffer[ NTX_MAX_KEY + 1 ]; + char *ptr = szKeyVal, *ptr2, c; + int iLen, iDec; + HB_LONG lValue; + double dValue; - if( !pItem ) - { - pItem = hb_itemNew( NULL ); - lNewItem = TRUE; - } - if( hb_itemType( pForItem ) == HB_IT_BLOCK ) - { - hb_vmPushSymbol( &hb_symEval ); - hb_vmPush( pForItem ); - hb_vmSend( 0 ); - hb_itemCopy( pItem, hb_stackReturnItem() ); - } - else - { - pMacro = ( HB_MACRO_PTR ) hb_itemGetPtr( pForItem ); - hb_macroRun( pMacro ); - hb_itemCopy( pItem, hb_stackItemFromTop( - 1 ) ); - hb_stackPop(); - } - res = hb_itemGetL( pItem ); - if( lNewItem ) - hb_itemRelease( pItem ); - return res; -} + HB_SYMBOL_UNUSED( dec ); -static void hb__ntxTagKeyCount( LPTAGINFO pTag, LPPAGEINFO pPage, ULONG* ulKeyCount ) -{ - LPNTXITEM p; - int i; - - *ulKeyCount += pPage->uiKeys; - for( i=0;iuiKeys+1;i++ ) + if( *ptr == '0' - 4 ) /* negative number */ { - p = KEYITEM( pPage, i ); - if( p->page ) - hb__ntxTagKeyCount( pTag, hb_ntxPageLoad( pTag,p->page ), - ulKeyCount ); - } - hb_ntxPageRelease( pTag,pPage ); -} - -static BOOL hb_ntxInTopScope( LPTAGINFO pTag, char* key ) -{ - if( pTag->topScope ) - { - int i = hb_ntxItemCompare( pTag->topScope->item.asString.value, - key, pTag->topScope->item.asString.length, - pTag->KeyLength,0,pTag->Owner->Owner->cdPage ); - return pTag->AscendKey ? i <= 0 : i >= 0; - } - else - return TRUE; -} - -static BOOL hb_ntxInBottomScope( LPTAGINFO pTag, char* key ) -{ - if( pTag->bottomScope ) - { - int i = hb_ntxItemCompare( pTag->bottomScope->item.asString.value, - key, pTag->bottomScope->item.asString.length, - pTag->KeyLength,0,pTag->Owner->Owner->cdPage ); - return pTag->AscendKey ? i >= 0 : i <= 0; - } - else - return TRUE; -} - -static ULONG hb_ntxTagKeyNo( LPTAGINFO pTag ) -{ - ULONG ulKeyNo = 0; - - if( pTag->Owner->Owner->fShared && !pTag->Memory ) - { - while( !hb_fsLock( pTag->Owner->DiskFile, NTX_LOCK_OFFSET, 1, FL_LOCK | FLX_SHARED | FLX_WAIT ) ); - pTag->Owner->Locked = TRUE; - } - - if( pTag->topScope || pTag->bottomScope ) - { - hb_ntxGetCurrentKey( pTag, pTag->CurKeyInfo ); - if( hb_ntxInTopScope( pTag, pTag->CurKeyInfo->key ) && - hb_ntxInBottomScope( pTag, pTag->CurKeyInfo->key ) ) + ptr2 = szBuffer; + while( ( c = *ptr++ ) != 0 ) { - BOOL lContinue = FALSE; - ULONG ulRecNo = pTag->Owner->Owner->ulRecNo; - LPKEYINFO pKeyTmp = hb_ntxKeyNew( pTag->CurKeyInfo,pTag->KeyLength ); - - do - { - ulKeyNo ++; - hb_ntxTagKeyGoTo( pTag, PREV_RECORD, &lContinue ); - } - while( !pTag->TagBOF && hb_ntxInTopScope( pTag, pTag->CurKeyInfo->key ) ); - memcpy( pTag->CurKeyInfo->key, pKeyTmp->key, pTag->KeyLength ); - pTag->CurKeyInfo->Tag = pKeyTmp->Tag; - pTag->CurKeyInfo->Xtra = pKeyTmp->Xtra; - hb_ntxKeyFree( pKeyTmp ); - pTag->Owner->Owner->ulRecNo = ulRecNo; + if( c != '.' ) + c = '0' - ( c - '0' + 4 ); + *ptr2++ = c; } + szBuffer[ 0 ] = '-'; + *ptr2 = '\0'; + ptr = szBuffer; } + if( hb_valStrnToNum( ptr, length, &lValue, &dValue, &iDec, &iLen ) ) + return hb_itemPutNDLen( pItem, dValue, iLen, iDec ); else - { - int seekRes; - SHORT i, j; - LPPAGEINFO pPage; - LPNTXITEM p; - LPKEYINFO pKey = hb_ntxKeyNew( NULL,pTag->KeyLength ); - - hb_ntxGetCurrentKey( pTag,pKey ); - pTag->stackLevel = 0; - seekRes = hb_ntxTagFindCurrentKey( pTag, hb_ntxPageLoad( pTag,0 ), pKey, (int)pTag->KeyLength, FALSE, 0 ); - hb_ntxKeyFree( pKey ); - if( !seekRes ) - { - ulKeyNo = 1; - for( i=0;i<=pTag->stackLevel;i++ ) - { - pPage = hb_ntxPageLoad( pTag,pTag->stack[i].page ); - ulKeyNo += pTag->stack[i].ikey; - if( pTag->stackLevel ) - pTag->stack[i].ikey --; - for( j=0;j<=pTag->stack[i].ikey;j++ ) - { - p = KEYITEM( pPage, j ); - if( p->page ) - hb__ntxTagKeyCount( pTag, hb_ntxPageLoad( pTag,p->page ), - &ulKeyNo ); - } - hb_ntxPageRelease( pTag,pPage ); - } - } - } - - if( pTag->Owner->Owner->fShared && !pTag->Memory ) - { - hb_ntxPageFree( pTag,FALSE ); - hb_fsLock( pTag->Owner->DiskFile, NTX_LOCK_OFFSET, 1, FL_UNLOCK ); - pTag->Owner->Locked = FALSE; - } - return ulKeyNo; -} - -static ULONG hb_ntxTagKeyCount( LPTAGINFO pTag ) -{ - LPPAGEINFO pPage; - LPNTXITEM p; - ULONG ulKeyCount = 0; - int i; - - if( pTag->Owner->Owner->fShared && !pTag->Memory ) - { - while( !hb_fsLock( pTag->Owner->DiskFile, NTX_LOCK_OFFSET, 1, FL_LOCK | FLX_SHARED | FLX_WAIT ) ); - pTag->Owner->Locked = TRUE; - } - else if( pTag->keyCount ) - return pTag->keyCount; - - if( pTag->topScope || pTag->bottomScope ) - { - BOOL lContinue = FALSE; - LONG lRecno = 1; - LPKEYINFO pKeyTmp = hb_ntxKeyNew( pTag->CurKeyInfo,pTag->KeyLength ); - ULONG ulRecNo = pTag->Owner->Owner->ulRecNo; - - if( pTag->topScope ) - { - LPKEYINFO pKey = hb_ntxKeyNew( NULL,pTag->KeyLength ); - - strncpy( pKey->key,pTag->topScope->item.asString.value,pTag->KeyLength ); - pTag->CurKeyInfo->Tag = pTag->CurKeyInfo->Xtra = pTag->TagEOF = 0; - pTag->stackLevel = 0; - lRecno = ( hb_ntxTagFindCurrentKey( pTag, hb_ntxPageLoad( pTag,0 ), - pKey, (int)pTag->KeyLength, FALSE, 1 ) <= 0 )? pTag->CurKeyInfo->Xtra:0; - hb_ntxKeyFree( pKey ); - if( lRecno ) - { - pPage = hb_ntxPageLoad( pTag,pTag->CurKeyInfo->Tag ); - pPage->CurKey = hb_ntxPageFindCurrentKey( pPage,pTag->CurKeyInfo->Xtra ); - if( pPage->CurKey ) - memcpy( pTag->CurKeyInfo->key, ( KEYITEM( pPage, pPage->CurKey-1 ) )->key, pTag->KeyLength ); - hb_ntxPageRelease( pTag,pPage ); - } - } - else - { - hb_ntxTagKeyGoTo( pTag, TOP_RECORD, NULL ); - } - if( lRecno ) - while( !pTag->TagEOF && hb_ntxInBottomScope( pTag, pTag->CurKeyInfo->key ) ) - { - ulKeyCount ++; - hb_ntxTagKeyGoTo( pTag, NEXT_RECORD, &lContinue ); - } - - memcpy( pTag->CurKeyInfo->key, pKeyTmp->key, pTag->KeyLength ); - pTag->CurKeyInfo->Tag = pKeyTmp->Tag; - pTag->CurKeyInfo->Xtra = pKeyTmp->Xtra; - hb_ntxKeyFree( pKeyTmp ); - pTag->Owner->Owner->ulRecNo = ulRecNo; - } - else - { - pPage = hb_ntxPageLoad( pTag,0 ); - ulKeyCount += pPage->uiKeys; - for( i=0;iuiKeys+1;i++ ) - { - p = KEYITEM( pPage, i ); - if( p->page ) - hb__ntxTagKeyCount( pTag, hb_ntxPageLoad( pTag,p->page ), - &ulKeyCount ); - } - hb_ntxPageRelease( pTag,pPage ); - } - - if( pTag->Owner->Owner->fShared && !pTag->Memory ) - { - hb_ntxPageFree( pTag,FALSE ); - hb_fsLock( pTag->Owner->DiskFile, NTX_LOCK_OFFSET, 1, FL_UNLOCK ); - pTag->Owner->Locked = FALSE; - } - else - pTag->keyCount = ulKeyCount; - return ulKeyCount; -} - -static void hb_ntxClearScope( LPTAGINFO pTag, USHORT nScope ) -{ - if( nScope == 0 ) - { - if( pTag->topScope ) - { - hb_itemRelease( pTag->topScope ); - pTag->topScope = NULL; - } - } - else - { - if( pTag->bottomScope ) - { - hb_itemRelease( pTag->bottomScope ); - pTag->bottomScope = NULL; - } - } -} - -static ERRCODE hb_ntxGoEof( NTXAREAP pArea ) -{ - ERRCODE retvalue; - LPTAGINFO lpCurTag = pArea->lpCurTag; - - pArea->lpCurTag = NULL; - retvalue = SUPER_GOTO( ( AREAP ) pArea, 0 ); - if( pArea->ulRecCount ) - pArea->fBof = lpCurTag->TagBOF = FALSE; - pArea->fEof = lpCurTag->TagEOF = TRUE; - pArea->lpCurTag = lpCurTag; - pArea->lpCurTag->CurKeyInfo->Tag = pArea->lpCurTag->CurKeyInfo->Xtra = 0; - return retvalue; -} - -static USHORT hb_ntxGetKeyType( LPTAGINFO pTag ) -{ - if( hb_itemType( pTag->pKeyItem ) == HB_IT_BLOCK ) - { - hb_vmPushSymbol( &hb_symEval ); - hb_vmPush( pTag->pKeyItem ); - hb_vmSend( 0 ); - return hb_itemType( hb_stackReturnItem() ); - } - else - { - USHORT nType; - HB_MACRO_PTR pMacro; - pMacro = ( HB_MACRO_PTR ) hb_itemGetPtr( pTag->pKeyItem ); - hb_macroRun( pMacro ); - nType = hb_itemType( hb_stackItemFromTop( - 1 ) ); - hb_stackPop(); - return nType; - } + return hb_itemPutNIntLen( pItem, lValue, length ); } +/* + * create new index key + */ static LPKEYINFO hb_ntxKeyNew( LPKEYINFO pKeyFrom, int keylen ) { LPKEYINFO pKey; @@ -668,740 +387,954 @@ static LPKEYINFO hb_ntxKeyNew( LPKEYINFO pKeyFrom, int keylen ) return pKey; } -static LONG hb_ntxTagKeyFind( LPTAGINFO pTag, LPKEYINFO pKey, int keylen, BOOL * result, BOOL bSoftSeek ) +/* + * copy index key, if dst is null create new dst key else destroy dst + */ +static LPKEYINFO hb_ntxKeyCopy( LPKEYINFO pKeyDest, LPKEYINFO pKey, int keylen ) { - int K; + if( !pKeyDest ) + pKeyDest = hb_ntxKeyNew( NULL, keylen ); - pTag->CurKeyInfo->Tag = pTag->CurKeyInfo->Xtra = 0; - pTag->TagBOF = pTag->TagEOF = *result = FALSE; - pTag->stackLevel = 0; - K = hb_ntxTagFindCurrentKey( pTag, hb_ntxPageLoad( pTag,0 ), pKey, keylen, FALSE, bSoftSeek ? 2 : 1 ); - if( K == 0 ) - { - *result = TRUE; - return pTag->CurKeyInfo->Xtra; - } - else if( K < 0 ) - { - return pTag->CurKeyInfo->Xtra; - } - else - pTag->TagEOF = TRUE; - return 0; + memcpy( pKeyDest->key, pKey->key, keylen ); + pKeyDest->Tag = pKey->Tag; + pKeyDest->Xtra = pKey->Xtra; + + return pKeyDest; } -static int hb_ntxPageKeySearch( LPTAGINFO pTag, LPPAGEINFO pPage, char* key, SHORT keylen, BOOL bExact, BOOL bInsert ) +/* + * get ntx key type for given item + */ +static BYTE hb_ntxItemType( PHB_ITEM pItem ) { - SHORT i, iLast = -1, k; - SHORT iBegin = 0, iEnd = pPage->uiKeys - 1; - - while( iBegin <= iEnd ) - { - i = ( iBegin + iEnd ) / 2; - k = hb_ntxItemCompare( key, KEYITEM( pPage, i )->key, keylen, pTag->KeyLength,bExact,pTag->Owner->Owner->cdPage ); - if( !pTag->AscendKey ) - k = -k; - if( k > 0 || ( bInsert && !k ) ) - iBegin = i + 1; - else if( k < 0 ) - { - iEnd = i - 1; - iLast = i; - } - else - { - while( !k && i-- ) - k = hb_ntxItemCompare( key, KEYITEM( pPage, i )->key, - keylen, pTag->KeyLength, bExact,pTag->Owner->Owner->cdPage ); - pPage->CurKey = i + 1; - return 0; - } - } - if( iLast >= 0 ) - { - pPage->CurKey = iLast; - return -1; - } - else - { - pPage->CurKey = pPage->uiKeys; - return 1; - } -} - -static int hb_ntxTagFindCurrentKey( LPTAGINFO pTag, LPPAGEINFO pPage, LPKEYINFO pKey, int keylen, BOOL bExact, int lSeek ) -{ - int k, kChild; - LPNTXITEM p; - - bExact = ( bExact || pTag->KeyType != 'C' ); - k = hb_ntxPageKeySearch( pTag, pPage, pKey->key, keylen, bExact, FALSE ); - do - { - p = KEYITEM( pPage, pPage->CurKey ); - if( pPage->CurKey == pPage->uiKeys ) - { - if( !p->page ) - break; - k = -1; - } - if( k <= 0 ) - /* pKey <= p */ - { - if( ( k == 0 && !lSeek && (ULONG)p->rec_no != pTag->Owner->Owner->ulRecNo ) - || ( lSeek && p->rec_no && hb_ntxIsRecBad( pTag->Owner->Owner, p->rec_no ) ) ) - k = 1; - if( k <= 0 && pPage->CurKey < pPage->uiKeys ) - { - pTag->CurKeyInfo->Xtra = p->rec_no; - pTag->CurKeyInfo->Tag = pPage->Page; - } - if( p->page && ( k < 0 || lSeek || ( (ULONG)p->rec_no != pTag->Owner->Owner->ulRecNo ) ) ) - { - kChild = hb_ntxTagFindCurrentKey( pTag, hb_ntxPageLoad( - pTag,p->page ), pKey, keylen, bExact, lSeek ); - if( kChild == 0 || ( lSeek==2 && kChild < 0 && k != 0 ) ) - k = kChild; - - if( k <= 0 ) - { - if( ++(pTag->stackLevel) >= pTag->stackDepth ) - { - pTag->stackDepth += 32; - pTag->stack = (LPTREESTACK) hb_xrealloc( pTag->stack, - sizeof(TREE_STACK) * pTag->stackDepth ); - } - } - } - else if( k <= 0 && pPage->CurKey < pPage->uiKeys ) - pTag->stackLevel = 0; - if( k <= 0 && pPage->CurKey < pPage->uiKeys && pTag->CurKeyInfo->Tag == 0 ) - { - pTag->CurKeyInfo->Xtra = p->rec_no; - pTag->CurKeyInfo->Tag = pPage->Page; - } - } - if( k > 0 && ++pPage->CurKey <= pPage->uiKeys ) - { - if( pPage->CurKey < pPage->uiKeys ) - { - k = hb_ntxItemCompare( pKey->key, KEYITEM( pPage, pPage->CurKey )->key, keylen, pTag->KeyLength,bExact,pTag->Owner->Owner->cdPage ); - if( !pTag->AscendKey ) - k = -k; - } - } - else - break; - } - while( 1 ); - if( k <= 0 ) - { - pTag->stack[pTag->stackLevel].page = pPage->Page; - pTag->stack[pTag->stackLevel].ikey = pPage->CurKey; - } - hb_ntxPageRelease( pTag,pPage ); - return k; -} - -static BOOL hb_ntxIsRecBad( NTXAREAP pArea, LONG ulRecNo ) -{ - - BOOL lResult = FALSE; - - if( hb_set.HB_SET_DELETED || pArea->dbfi.itmCobExpr ) - SELF_GOTO( ( AREAP ) pArea,ulRecNo ); - - if( hb_set.HB_SET_DELETED ) - SUPER_DELETED( ( AREAP ) pArea,&lResult ); - - if( !lResult && pArea->dbfi.itmCobExpr ) - { - PHB_ITEM pResult = hb_vmEvalBlock( pArea->dbfi.itmCobExpr ); - lResult = HB_IS_LOGICAL( pResult ) && !hb_itemGetL( pResult ); - } - - return lResult; -} - -static USHORT hb_ntxPageFindCurrentKey( LPPAGEINFO pPage, ULONG ulRecno ) -{ - int i; - for( i=0; i < pPage->uiKeys; i++ ) - if( KEYITEM( pPage,i )->rec_no == ulRecno ) - return ( i+1 ); - return 0; -} - -static void hb_ntxGetCurrentKey( LPTAGINFO pTag, LPKEYINFO pKey ) -{ - char szBuffer[ NTX_MAX_KEY ]; - PHB_ITEM pItem; -#ifndef HB_CDP_SUPPORT_OFF - PHB_CODEPAGE cdpTmp = hb_cdp_page; - hb_cdp_page = pTag->Owner->Owner->cdPage; -#endif - if( pTag->nField ) - { - pItem = hb_itemNew( NULL ); - SELF_GETVALUE( ( AREAP ) pTag->Owner->Owner, pTag->nField, pItem ); - } - else if( hb_itemType( pTag->pKeyItem ) == HB_IT_BLOCK ) - { - hb_vmPushSymbol( &hb_symEval ); - hb_vmPush( pTag->pKeyItem ); - hb_vmSend( 0 ); - pItem = hb_stackReturnItem(); - } - else - { - HB_MACRO_PTR pMacro; - pMacro = ( HB_MACRO_PTR ) hb_itemGetPtr( pTag->pKeyItem ); - hb_macroRun( pMacro ); - pItem = hb_stackItemFromTop( - 1 ); - } switch( hb_itemType( pItem ) ) { case HB_IT_STRING: - memcpy( pKey->key, pItem->item.asString.value, pTag->KeyLength ); - break; + case HB_IT_STRING | HB_IT_MEMO: + return 'C'; + case HB_IT_INTEGER: case HB_IT_LONG: case HB_IT_DOUBLE: - strcpy( pKey->key, numToStr( pItem, szBuffer, pTag->KeyLength, pTag->KeyDec ) ); - break; + return 'N'; + case HB_IT_DATE: - hb_itemGetDS( pItem, szBuffer ); - strcpy( pKey->key,szBuffer ); - break; + return 'D'; + case HB_IT_LOGICAL: - szBuffer[0] = ( hb_itemGetL( pItem ) ? 'T':'F' ); - szBuffer[1] = 0; - strcpy( pKey->key, szBuffer ); - break; - } - if( pTag->nField ) - hb_itemRelease( pItem ); - else if( hb_itemType( pTag->pKeyItem ) != HB_IT_BLOCK ) - hb_stackPop(); - pKey->Xtra = pTag->Owner->Owner->ulRecNo; -#ifndef HB_CDP_SUPPORT_OFF - hb_cdp_page = cdpTmp; -#endif -} + return 'L'; -static BOOL hb_ntxTagGoToNextKey( LPTAGINFO pTag, BOOL lContinue ) -{ - BOOL lCurrrentKey = FALSE; - LPPAGEINFO pPage = NULL, pChildPage; - LPNTXITEM p; - - /* pTag->blockNext = 0; pTag->keyNext = 0; */ - if( pTag->CurKeyInfo->Tag && ((ULONG)pTag->CurKeyInfo->Xtra) == pTag->Owner->Owner->ulRecNo ) - { - pPage = hb_ntxPageLoad( pTag,pTag->CurKeyInfo->Tag ); - pPage->CurKey = hb_ntxPageFindCurrentKey( pPage,pTag->CurKeyInfo->Xtra ); - if( pPage->CurKey && - ( pPage->CurKey < pPage->uiKeys || - ( pPage->CurKey == pPage->uiKeys && - ( KEYITEM( pPage, pPage->CurKey ) )->page ) ) ) - lCurrrentKey = TRUE; - else - hb_ntxPageRelease( pTag, pPage ); - } - - if( !lCurrrentKey ) - { - int seekRes; - LPKEYINFO pKey; - - pKey = hb_ntxKeyNew( NULL,pTag->KeyLength ); - if( lContinue ) - { - memcpy( pKey->key,pTag->CurKeyInfo->key,pTag->KeyLength ); - pTag->Owner->Owner->ulRecNo = pTag->CurKeyInfo->Xtra; - } - else - hb_ntxGetCurrentKey( pTag,pKey ); - pTag->stackLevel = 0; - seekRes = hb_ntxTagFindCurrentKey( pTag, hb_ntxPageLoad( pTag,0 ), pKey, (int)pTag->KeyLength, FALSE, 0 ); - hb_ntxKeyFree( pKey ); - if( seekRes ) - { - printf( "\n\rhb_ntxFindNextKey: Cannot find current key:" ); - return FALSE; - } - pPage = hb_ntxPageLoad( pTag,pTag->CurKeyInfo->Tag ); - pPage->CurKey = hb_ntxPageFindCurrentKey( pPage,pTag->CurKeyInfo->Xtra ); - } - - if( pPage->CurKey < pPage->uiKeys || - ( pPage->CurKey == pPage->uiKeys && ( KEYITEM( pPage, pPage->CurKey ) )->page ) ) - { - while( ( p = KEYITEM( pPage, pPage->CurKey ) )->page ) - { - pChildPage = hb_ntxPageLoad( pTag,p->page ); - hb_ntxPageRelease( pTag,pPage ); - pPage = pChildPage; - pPage->CurKey = 0; - } - memcpy( pTag->CurKeyInfo->key, p->key, pTag->KeyLength ); - pTag->CurKeyInfo->Xtra = p->rec_no; - pTag->CurKeyInfo->Tag = pPage->Page; - hb_ntxPageRelease( pTag,pPage ); - return TRUE; - } - else - { - SHORT i = 1; - hb_ntxPageRelease( pTag,pPage ); - /* - if( pTag->blockNext ) - { - pPage = hb_ntxPageLoad( pTag,pTag->blockNext ); - pPage->CurKey = pTag->keyNext; - */ - while( pTag->stackLevel >= i ) - { - pPage = hb_ntxPageLoad( pTag,pTag->stack[i].page ); - if( pTag->stack[i].ikey < pPage->uiKeys ) - break; - hb_ntxPageRelease( pTag,pPage ); - i ++; - } - if( pTag->stackLevel >= i ) - { - pPage->CurKey = pTag->stack[i].ikey; - /* - while( ( pPage->pKeys+pPage->CurKey )->Tag ) - { - pChildPage = hb_ntxPageLoad( ( pPage->pKeys+pPage->CurKey )->Tag ); - hb_ntxPageRelease( pPage ); - pPage = pChildPage; - pPage->CurKey = 0; - } - */ - memcpy( pTag->CurKeyInfo->key, ( KEYITEM( pPage, pPage->CurKey ) )->key, pTag->KeyLength ); - pTag->CurKeyInfo->Xtra = ( KEYITEM( pPage, pPage->CurKey ) )->rec_no; - pTag->CurKeyInfo->Tag = pPage->Page; - hb_ntxPageRelease( pTag,pPage ); - return TRUE; - } - else - return FALSE; + default: + return 'U'; } } -static BOOL hb_ntxTagGoToPrevKey( LPTAGINFO pTag, BOOL lContinue ) +/* + * store Item in index key + * TODO: uiType check and generate RT error if necessary + * probably not here or we will have to add parameter + * for scope key evaluation + */ +static LPKEYINFO hb_ntxKeyPutItem( LPKEYINFO pKey, PHB_ITEM pItem, ULONG ulRecNo, + LPTAGINFO pTag, BOOL fTrans, USHORT *puiLen ) { - BOOL lCurrrentKey = FALSE; - LPPAGEINFO pPage = NULL, pChildPage; + ULONG len; - /* pTag->blockPrev = 0; pTag->keyPrev = 0; */ - if( pTag->CurKeyInfo->Tag && ((ULONG)pTag->CurKeyInfo->Xtra) == pTag->Owner->Owner->ulRecNo ) + if( !pKey ) + pKey = hb_ntxKeyNew( NULL, pTag->KeyLength ); + + if( puiLen ) + *puiLen = pTag->KeyLength; + + switch( hb_ntxItemType( pItem ) ) { - pPage = hb_ntxPageLoad( pTag,pTag->CurKeyInfo->Tag ); - pPage->CurKey = hb_ntxPageFindCurrentKey( pPage,pTag->CurKeyInfo->Xtra ); - if( pPage->CurKey-- && - ( (KEYITEM( pPage, pPage->CurKey ))->page || pPage->CurKey >= 1 ) ) - lCurrrentKey = TRUE; - else - hb_ntxPageRelease( pTag,pPage ); - } - - if( !lCurrrentKey ) - { - int seekRes; - LPKEYINFO pKey; - - pKey = hb_ntxKeyNew( NULL,pTag->KeyLength ); - if( lContinue ) - { - memcpy( pKey->key,pTag->CurKeyInfo->key,pTag->KeyLength ); - pTag->Owner->Owner->ulRecNo = pTag->CurKeyInfo->Xtra; - } - else - hb_ntxGetCurrentKey( pTag, pKey ); - pTag->stackLevel = 0; - seekRes = hb_ntxTagFindCurrentKey( pTag, hb_ntxPageLoad( pTag,0 ), pKey, (int)pTag->KeyLength, FALSE, 0 ); - hb_ntxKeyFree( pKey ); - if( seekRes ) - { - printf( "\n\rhb_ntxFindPrevKey: Cannot find current key: |%ld %s|",pTag->Owner->Owner->ulRecNo,pKey->key ); - return FALSE; - } - pPage = hb_ntxPageLoad( pTag,pTag->CurKeyInfo->Tag ); - pPage->CurKey = hb_ntxPageFindCurrentKey( pPage,pTag->CurKeyInfo->Xtra ); - pPage->CurKey--; - } - - if( ( KEYITEM( pPage, pPage->CurKey ) )->page ) - { - do - { - pChildPage = hb_ntxPageLoad( pTag,( KEYITEM( pPage, pPage->CurKey ) )->page ); - hb_ntxPageRelease( pTag,pPage ); - pPage = pChildPage; - pPage->CurKey = pPage->uiKeys; - } - while( ( KEYITEM( pPage, pPage->CurKey ) )->page ); - pPage->CurKey--; - } - else - pPage->CurKey--; - if( pPage->CurKey >= 0 ) - { - memcpy( pTag->CurKeyInfo->key, ( KEYITEM( pPage, pPage->CurKey ) )->key, pTag->KeyLength ); - pTag->CurKeyInfo->Xtra = ( KEYITEM( pPage, pPage->CurKey ) )->rec_no; - pTag->CurKeyInfo->Tag = pPage->Page; - hb_ntxPageRelease( pTag,pPage ); - return TRUE; - } - else - { - SHORT i = 1; - hb_ntxPageRelease( pTag,pPage ); - /* - if( pTag->blockPrev ) - { - pPage = hb_ntxPageLoad( pTag,pTag->blockPrev ); - pPage->CurKey = pTag->keyPrev; - */ - while( pTag->stackLevel >= i ) - { - pPage = hb_ntxPageLoad( pTag,pTag->stack[i].page ); - pPage->CurKey = pTag->stack[i].ikey - 1; - if( pPage->CurKey < pPage->uiKeys && pPage->CurKey >= 0 ) - break; - hb_ntxPageRelease( pTag,pPage ); - i ++; - } - if( pTag->stackLevel >= i ) - { - memcpy( pTag->CurKeyInfo->key, ( KEYITEM( pPage, pPage->CurKey ) )->key, pTag->KeyLength ); - pTag->CurKeyInfo->Xtra = ( KEYITEM( pPage, pPage->CurKey ) )->rec_no; - pTag->CurKeyInfo->Tag = pPage->Page; - hb_ntxPageRelease( pTag,pPage ); - return TRUE; - } - else - return FALSE; - } -} - -static BOOL hb_ntxTagGoToTopKey( LPTAGINFO pTag, LPPAGEINFO pPage, ULONG ulOffset ) -{ - LPPAGEINFO pChildPage; - LPNTXITEM p; - - pChildPage = hb_ntxPageLoad( pTag,ulOffset ); - if( pPage ) - { - hb_ntxPageRelease( pTag,pPage ); - } - if( pChildPage != NULL && pChildPage->uiKeys ) - { - p = KEYITEM( pChildPage, 0 ); - ulOffset = p->page; - if( ulOffset ) - { - return hb_ntxTagGoToTopKey( pTag,pChildPage,ulOffset ); - } - else - { - memcpy( pTag->CurKeyInfo->key, p->key, pTag->KeyLength ); - pTag->CurKeyInfo->Xtra = p->rec_no; - pTag->CurKeyInfo->Tag = pChildPage->Page; - hb_ntxPageRelease( pTag,pChildPage ); - return TRUE; - } - } - else - return FALSE; -} - -static BOOL hb_ntxTagGoToBottomKey( LPTAGINFO pTag, LPPAGEINFO pPage, ULONG ulOffset ) -{ - LPPAGEINFO pChildPage; - LPNTXITEM p; - - pChildPage = hb_ntxPageLoad( pTag,ulOffset ); - if( pPage ) - hb_ntxPageRelease( pTag,pPage ); - if( pChildPage != NULL && pChildPage->uiKeys ) - { - ulOffset = ( KEYITEM( pChildPage, pChildPage->uiKeys ) )->page; - if( ulOffset ) - return hb_ntxTagGoToBottomKey( pTag,pChildPage,ulOffset ); - else - { - p = KEYITEM( pChildPage, pChildPage->uiKeys-1 ); - memcpy( pTag->CurKeyInfo->key, p->key, pTag->KeyLength ); - pTag->CurKeyInfo->Xtra = p->rec_no; - pTag->CurKeyInfo->Tag = pChildPage->Page; - hb_ntxPageRelease( pTag,pChildPage ); - return TRUE; - } - } - else - return FALSE; -} - -static void hb_ntxTagKeyGoTo( LPTAGINFO pTag, BYTE bTypRead, BOOL * lContinue ) -{ - BOOL wasLocked = FALSE; - - pTag->TagBOF = pTag->TagEOF = FALSE; - if( pTag->Owner->Owner->ulRecCount ) - { - if( pTag->Owner->Owner->fShared && !pTag->Owner->Locked && !pTag->Memory ) - { - while( !hb_fsLock( pTag->Owner->DiskFile, NTX_LOCK_OFFSET, 1, FL_LOCK | FLX_SHARED | FLX_WAIT ) ); - wasLocked = pTag->Owner->Locked; - pTag->Owner->Locked = TRUE; - } - - switch( bTypRead ) - { - case TOP_RECORD: - pTag->TagBOF = !hb_ntxTagGoToTopKey( pTag,NULL,0 ); - pTag->TagEOF = pTag->TagBOF; - break; - - case BTTM_RECORD: - pTag->TagEOF = !hb_ntxTagGoToBottomKey( pTag,NULL,0 ); - pTag->TagBOF = pTag->TagEOF; - break; - - case NEXT_RECORD: - pTag->TagEOF = !hb_ntxTagGoToNextKey( pTag, *lContinue ); - break; - - case PREV_RECORD: - pTag->TagBOF = !hb_ntxTagGoToPrevKey( pTag, *lContinue ); - break; - } - if( pTag->Owner->Owner->fShared && !pTag->Memory ) - { - hb_ntxPageFree( pTag,FALSE ); - /* pTag->RootPage = NULL; */ - if( !wasLocked ) + case 'C': + len = pItem->item.asString.length; + if( len < ( ULONG ) pTag->KeyLength ) { - hb_fsLock( pTag->Owner->DiskFile, NTX_LOCK_OFFSET, 1, FL_UNLOCK ); - pTag->Owner->Locked = FALSE; - } - } - } - else - { - if( bTypRead == PREV_RECORD) - { - pTag->TagBOF = TRUE; pTag->TagEOF = FALSE; - } - else - { - pTag->TagBOF = TRUE; pTag->TagEOF = TRUE; - } - } - if( pTag->TagBOF || pTag->TagEOF ) - { - if( !pTag->AscendKey ) - { - pTag->CurKeyInfo->Xtra = pTag->TagEOF; - pTag->TagEOF = pTag->TagBOF; - pTag->TagBOF = ( BOOL ) pTag->CurKeyInfo->Xtra; - } - pTag->CurKeyInfo->Xtra = 0; - } - if( lContinue ) - *lContinue = TRUE; -} - -static int hb_ntxItemCompare( char* s1, char* s2, int ilen1, int ilen2, BOOL Exact,PHB_CODEPAGE cdpage ) -{ - int iLimit, iResult, i; - - if( ( s2 == NULL || ilen2 == 0 ) && s1 && ilen1 ) - return 1; - if( s1 == NULL || ilen1 == 0 ) - return -1; - - iLimit = ( ilen1 > ilen2 ) ? ilen2 : ilen1; -#ifndef HB_CDP_SUPPORT_OFF - iResult = (cdpage->lSort)? hb_cdpcmp( s1, s2, (ULONG)iLimit, cdpage, NULL ):memcmp( s1, s2, iLimit ); -#else - iResult = memcmp( s1, s2, iLimit ); -#endif - if( !iResult ) - { - if( ( iResult = ilen1 - ilen2 ) != 0 ) - { - if( iResult > 0 ) - { - i = ilen1; - while( i > iLimit && s1[ i - 1 ] == ' ' ) i--; + memcpy( pKey->key, pItem->item.asString.value, len ); + memset( pKey->key + len, ' ', pTag->KeyLength - len ); + if( puiLen ) + *puiLen = ( USHORT ) len; } else { - i = ilen2; - while( i > iLimit && s2[ i - 1 ] == ' ' ) i--; + memcpy( pKey->key, pItem->item.asString.value, pTag->KeyLength ); } - if( i == iLimit ) - iResult = 0; + pKey->key[ pTag->KeyLength ] = '\0'; +#ifndef HB_CDP_SUPPORT_OFF + if( fTrans ) + hb_cdpnTranslate( pKey->key, hb_cdp_page, pTag->Owner->Owner->cdPage, pTag->KeyLength ); +#endif + break; + case 'N': + hb_ntxNumToStr( pItem, pKey->key, pTag->KeyLength, pTag->KeyDec ); + break; + case 'D': + hb_itemGetDS( pItem, pKey->key ); + break; + case 'L': + pKey->key[0] = ( hb_itemGetL( pItem ) ? 'T':'F' ); + pKey->key[1] = 0; + break; + default: + memset( pKey->key, '\0', pTag->KeyLength ); + } + pKey->Xtra = ulRecNo; + pKey->Tag = 0; + + return pKey; +} + +/* + * get Item from index key + */ +static PHB_ITEM hb_ntxKeyGetItem( PHB_ITEM pItem, LPKEYINFO pKey, + LPTAGINFO pTag, BOOL fTrans ) +{ + if( pKey ) + { + switch( pTag->KeyType ) + { + case 'C': +#ifndef HB_CDP_SUPPORT_OFF + if( fTrans && pTag->Owner->Owner->cdPage != hb_cdp_page ) + { + char * pVal = ( char * ) hb_xgrab( pTag->KeyLength + 1 ); + memcpy( pVal, pKey->key, pTag->KeyLength ); + pVal[ pTag->KeyLength ] = '\0'; + hb_cdpnTranslate( pVal, pTag->Owner->Owner->cdPage, hb_cdp_page, + pTag->KeyLength ); + pItem = hb_itemPutCPtr( pItem, pVal, pTag->KeyLength ); + } + else +#endif + { + pItem = hb_itemPutCL( pItem, pKey->key, pTag->KeyLength ); + } + break; + case 'N': + pItem = hb_ntxStrToNum( pItem, pKey->key, pTag->KeyLength, pTag->KeyDec ); + break; + case 'D': + pItem = hb_itemPutDS( pItem, pKey->key ); + break; + case 'L': + pItem = hb_itemPutL( pItem, pKey->key[0] == 'T' ); + break; + default: + if( pItem ) + hb_itemClear( pItem ); + else + pItem = hb_itemNew( NULL ); } - if( iResult < 0 && !Exact ) - iResult = 0; + } + else if( pItem ) + hb_itemClear( pItem ); + else + pItem = hb_itemNew( NULL ); + + return pItem; +} + +/* + * destroy compiled expression + */ +static void hb_ntxDestroyExp( PHB_ITEM pExp ) +{ + if( hb_itemType( pExp ) != HB_IT_BLOCK ) + hb_macroDelete( ( HB_MACRO_PTR ) hb_itemGetPtr( pExp ) ); + hb_itemRelease( pExp ); +} + +/* + * evaluate conditional expression and return the logical result + */ +static BOOL hb_ntxEvalCond( NTXAREAP pArea, PHB_ITEM pCondItem, BOOL fSetWA ) +{ + int iCurrArea = 0; + BOOL fRet; + + if( fSetWA ) + { + iCurrArea = hb_rddGetCurrentWorkAreaNumber(); + if( iCurrArea != pArea->uiArea ) + hb_rddSelectWorkAreaNumber( pArea->uiArea ); + else + iCurrArea = 0; } - if( iResult < 0 ) - return -1; - else if( iResult > 0 ) - return 1; - else - return 0; + fRet = hb_itemGetL( hb_vmEvalBlockOrMacro( pCondItem ) ); + + if( iCurrArea ) + hb_rddSelectWorkAreaNumber( iCurrArea ); + + return fRet; } -static void hb_ntxPageSave( LPTAGINFO pTag, LPPAGEINFO pPage ) +/* + * evaluate seek/skip block: {|key, rec| ... } + */ +static BOOL hb_ntxEvalSeekCond( LPTAGINFO pTag, PHB_ITEM pCondItem ) { - ( ( LPNTXBUFFER ) pPage->buffer )->item_count = pPage->uiKeys; - hb_fsSeek( pTag->Owner->DiskFile, pPage->Page, FS_SET ); - hb_fsWrite( pTag->Owner->DiskFile, (BYTE *) pPage->buffer, NTXBLOCKSIZE ); - pTag->Owner->fFlush = TRUE; - pPage->Changed = FALSE; + BOOL fRet; + PHB_ITEM pKeyVal, pKeyRec; + + pKeyVal = hb_ntxKeyGetItem( NULL, pTag->CurKeyInfo, pTag, TRUE ); + pKeyRec = hb_itemPutNInt( NULL, pTag->CurKeyInfo->Xtra ); + + fRet = hb_itemGetL( hb_vmEvalBlockV( pCondItem, 2, pKeyVal, pKeyRec ) ); + + hb_itemRelease( pKeyVal ); + hb_itemRelease( pKeyRec ); + + return fRet; } -static LPPAGEINFO hb_ntxPageLoad( LPTAGINFO pTag, ULONG ulOffset ) +/* + * get ITEM type of key expression + */ +static BYTE hb_ntxGetKeyType( LPTAGINFO pTag ) +{ + BYTE bType; + + if( pTag->nField ) + { + PHB_ITEM pItem = hb_itemNew( NULL ); + SELF_GETVALUE( ( AREAP ) pTag->Owner->Owner, pTag->nField, pItem ); + bType = hb_ntxItemType( pItem ); + hb_itemRelease( pItem ); + } + else + { + int iCurrArea = hb_rddGetCurrentWorkAreaNumber(); + + if( iCurrArea != pTag->Owner->Owner->uiArea ) + hb_rddSelectWorkAreaNumber( pTag->Owner->Owner->uiArea ); + else + iCurrArea = 0; + + bType = hb_ntxItemType( hb_vmEvalBlockOrMacro( pTag->pKeyItem ) ); + + if( iCurrArea ) + hb_rddSelectWorkAreaNumber( iCurrArea ); + } + return bType; +} + +/* + * evaluate key expression and create new Key from the result + */ +static LPKEYINFO hb_ntxEvalKey( LPKEYINFO pKey, LPTAGINFO pTag ) +{ + NTXAREAP pArea = pTag->Owner->Owner; + PHB_ITEM pItem; +#ifndef HB_CDP_SUPPORT_OFF + /* TODO%: this hack is not thread safe, hb_cdp_page has to be thread specific */ + PHB_CODEPAGE cdpTmp = hb_cdp_page; + hb_cdp_page = pArea->cdPage; +#endif + + if( pTag->nField ) + { + pItem = hb_itemNew( NULL ); + SELF_GETVALUE( ( AREAP ) pArea, pTag->nField, pItem ); + pKey = hb_ntxKeyPutItem( pKey, pItem, pArea->ulRecNo, pTag, FALSE, NULL ); + hb_itemRelease( pItem ); + } + else + { + int iCurrArea = hb_rddGetCurrentWorkAreaNumber(); + + if( iCurrArea != pArea->uiArea ) + hb_rddSelectWorkAreaNumber( pArea->uiArea ); + else + iCurrArea = 0; + + pItem = hb_vmEvalBlockOrMacro( pTag->pKeyItem ); + pKey = hb_ntxKeyPutItem( pKey, pItem, pArea->ulRecNo, pTag, FALSE, NULL ); + + if( iCurrArea ) + hb_rddSelectWorkAreaNumber( iCurrArea ); + } + +#ifndef HB_CDP_SUPPORT_OFF + hb_cdp_page = cdpTmp; +#endif + + return pKey; +} + +/* + * compare two values using Tag conditions (len & type) + */ +static int hb_ntxValCompare( LPTAGINFO pTag, char* val1, int len1, + char* val2, int len2, BOOL fExact ) +{ + int iLimit, iResult = 0; + + iLimit = (len1 > len2) ? len2 : len1; + + if( pTag->KeyType == 'C' ) + { + if( iLimit > 0 ) + { +#ifndef HB_CDP_SUPPORT_OFF + if( pTag->Owner->Owner->cdPage->lSort ) + iResult = hb_cdpcmp( val1, val2, ( ULONG ) iLimit, pTag->Owner->Owner->cdPage, NULL ); + else +#endif + iResult = memcmp( val1, val2, iLimit ); + } + + if( iResult == 0 ) + { + if( len1 > len2 ) + iResult = 1; + else if( len1 < len2 && fExact ) + iResult = -1; + } + } + else + { + if( iLimit <= 0 || (iResult = memcmp( val1, val2, iLimit )) == 0 ) + { + if( len1 > len2 ) + iResult = 1; + else if( len1 < len2 ) + iResult = -1; + } + } + return iResult; +} + +/* + * check if a given key is in top scope + */ +static BOOL hb_ntxInTopScope( LPTAGINFO pTag, char* key ) +{ + PHB_NTXSCOPE pScope = pTag->fUsrDescend ? &pTag->bottom : &pTag->top; + + if( pScope->scopeKeyLen ) + { + int i = hb_ntxValCompare( pTag, pScope->scopeKey->key, pScope->scopeKeyLen, + key, pTag->KeyLength, FALSE ); + return pTag->fUsrDescend ? i >= 0 : i <= 0; + } + else + return TRUE; +} + +/* + * check if a given key is in bottom scope + */ +static BOOL hb_ntxInBottomScope( LPTAGINFO pTag, char* key ) +{ + PHB_NTXSCOPE pScope = pTag->fUsrDescend ? &pTag->top : &pTag->bottom; + + if( pScope->scopeKeyLen ) + { + int i = hb_ntxValCompare( pTag, pScope->scopeKey->key, pScope->scopeKeyLen, + key, pTag->KeyLength, FALSE ); + return pTag->fUsrDescend ? i <= 0 : i >= 0; + } + else + return TRUE; +} + +/* + * check if a given key is in current scope + */ +static BOOL hb_ntxKeyInScope( LPTAGINFO pTag, LPKEYINFO pKey ) +{ + return hb_ntxInTopScope( pTag, pKey->key ) && + hb_ntxInBottomScope( pTag, pKey->key ); +} + +/* + * clear top or bottom scope + */ +static void hb_ntxTagClearScope( LPTAGINFO pTag, USHORT nScope ) +{ + NTXAREAP pArea = pTag->Owner->Owner; + PHB_NTXSCOPE pScope; + + /* resolve any pending scope relations first */ + if( pArea->lpdbPendingRel && pArea->lpdbPendingRel->isScoped ) + SELF_FORCEREL( ( AREAP ) pArea ); + + if( pTag->fUsrDescend ) + nScope = ( nScope == 0 ) ? 1 : 0; + + pScope = ( nScope == 0 ) ? &pTag->top : &pTag->bottom; + + if( pScope->scopeKey ) + { + hb_ntxKeyFree( pScope->scopeKey ); + pScope->scopeKey = NULL; + } + if( pScope->scopeItem ) + { + hb_itemRelease( pScope->scopeItem ); + pScope->scopeItem = NULL; + } + pScope->scopeKeyLen = 0; + + pTag->keyCount = 0; +} + +/* + * set top or bottom scope + */ +static void hb_ntxTagSetScope( LPTAGINFO pTag, USHORT nScope, PHB_ITEM pItem ) +{ + NTXAREAP pArea = pTag->Owner->Owner; + PHB_ITEM pScopeVal; + + /* resolve any pending scope relations first */ + if( pArea->lpdbPendingRel && pArea->lpdbPendingRel->isScoped ) + SELF_FORCEREL( ( AREAP ) pArea ); + + pScopeVal = ( hb_itemType( pItem ) == HB_IT_BLOCK ) ? + hb_vmEvalBlock( pItem ) : pItem; + + if( pTag->KeyType == hb_ntxItemType( pScopeVal ) ) + { + PHB_NTXSCOPE pScope; + BOOL fTop = ( nScope == 0 ); + + if( pTag->fUsrDescend ) + fTop = !fTop; + + pScope = fTop ? &pTag->top : &pTag->bottom; + + pScope->scopeKey = hb_ntxKeyPutItem( pScope->scopeKey, pScopeVal, + ( fTop == pTag->AscendKey ) ? NTX_IGNORE_REC_NUM : NTX_MAX_REC_NUM, + pTag, TRUE, &pScope->scopeKeyLen ); + + if( pScope->scopeItem == NULL ) + pScope->scopeItem = hb_itemNew( NULL ); + hb_itemCopy( pScope->scopeItem, pItem ); + + pTag->keyCount = 0; + } + else + { + hb_ntxTagClearScope( pTag, nScope ); + } +} + +/* + * get top or bottom scope item + */ +static void hb_ntxTagGetScope( LPTAGINFO pTag, USHORT nScope, PHB_ITEM pItem ) +{ + NTXAREAP pArea = pTag->Owner->Owner; + PHB_NTXSCOPE pScope; + + /* resolve any pending scope relations first */ + if( pArea->lpdbPendingRel && pArea->lpdbPendingRel->isScoped ) + SELF_FORCEREL( ( AREAP ) pArea ); + + if( pTag->fUsrDescend ) + nScope = ( nScope == 0 ) ? 1 : 0; + + pScope = ( nScope == 0 ) ? &pTag->top : &pTag->bottom; + + if( pScope->scopeItem ) + hb_itemCopy( pItem, pScope->scopeItem ); + else + hb_itemClear( pItem ); +} + +/* + * refresh top and bottom scope value if set as codeblock + */ +static void hb_ntxTagRefreshScope( LPTAGINFO pTag ) +{ + PHB_ITEM pItem; + + /* resolve any pending scope relations first */ + if( pTag->Owner->Owner->lpdbPendingRel && + pTag->Owner->Owner->lpdbPendingRel->isScoped ) + SELF_FORCEREL( ( AREAP ) pTag->Owner->Owner ); + + if( hb_itemType( pTag->top.scopeItem ) == HB_IT_BLOCK ) + { + pItem = hb_vmEvalBlock( pTag->top.scopeItem ); + pTag->top.scopeKey = hb_ntxKeyPutItem( pTag->top.scopeKey, pItem, + pTag->top.scopeKey->Xtra, pTag, TRUE, &pTag->top.scopeKeyLen ); + } + if( hb_itemType( pTag->bottom.scopeItem ) == HB_IT_BLOCK ) + { + pItem = hb_vmEvalBlock( pTag->bottom.scopeItem ); + pTag->bottom.scopeKey = hb_ntxKeyPutItem( pTag->bottom.scopeKey, pItem, + pTag->bottom.scopeKey->Xtra, pTag, TRUE, &pTag->bottom.scopeKeyLen ); + } +} + +/* + * an interface for fast check record number in record filter + */ +static BOOL hb_ntxCheckRecordScope( NTXAREAP pArea, ULONG ulRec ) +{ + LONG lRecNo = ( LONG ) ulRec; + + if ( SELF_COUNTSCOPE( ( AREAP ) pArea, NULL, &lRecNo ) == SUCCESS && lRecNo == 0 ) + { + return FALSE; + } + return TRUE; +} + +#ifdef HB_NTX_DEBUG +static void hb_ntxTagCheckBuffers( LPTAGINFO pTag ) { LPPAGEINFO pPage; - BOOL bReplace = FALSE; - ULONG ul = 0; + ULONG i; - if( !ulOffset ) + if( ( pTag->HdrChanged || pTag->Owner->Changed ) && !pTag->Owner->lockWrite ) + hb_errInternal( 9999, "hb_ntxTagCheckBuffers: tag modified in unlocked index", "", "" ); + + for( i = 0; i < pTag->Owner->ulPages; i++ ) { - if( pTag->Owner->Owner->fShared && !pTag->Memory ) + pPage = pTag->Owner->pages[ i ]; + if( pPage->Changed && !pTag->Owner->lockWrite ) + hb_errInternal( 9999, "hb_ntxTagCheckBuffers: page modified in unlocked index", "", "" ); + if( pPage->iUsed ) + hb_errInternal( 9999, "hb_ntxTagCheckBuffers: page still allocated", "", "" ); + } +} + +static void hb_ntxPageCheckKeys( LPPAGEINFO pPage, LPTAGINFO pTag, int iPos, int iType ) +{ + USHORT u; + int i; + + for( u = 1; u < pPage->uiKeys; u++ ) + { + i = hb_ntxValCompare( pTag, + hb_ntxGetKeyVal( pPage, u - 1 ), pTag->KeyLength, + hb_ntxGetKeyVal( pPage, u ), pTag->KeyLength, TRUE ); + if( !pTag->AscendKey ) + i = -i; + if( i > 0 ) { - hb_ntxHeaderRead( pTag->Owner ); + printf("\r\nuiKeys=%d(%d/%d), (%d)[%.*s]>(%d)[%.*s]", pPage->uiKeys, iPos, iType, + u - 1, pTag->KeyLength, hb_ntxGetKeyVal( pPage, u - 1 ), + u, pTag->KeyLength, hb_ntxGetKeyVal( pPage, u ) ); + fflush(stdout); + hb_errInternal( 9999, "hb_ntxPageCheckKeys: keys sorted wrong.", "", "" ); } - ulOffset = pTag->RootBlock; } - if( pTag->Memory ) +} +#endif + +/* + * read a given block from index file + */ +static BOOL hb_ntxBlockRead( LPNTXINDEX pIndex, ULONG ulBlock, BYTE *buffer, int iSize ) +{ + if( !pIndex->lockRead && !pIndex->lockWrite ) + hb_errInternal( 9103, "hb_ntxBlockRead on not locked index file.", "", "" ); + +#ifdef HB_NTX_DEBUG_DISP + s_rdNO++; +#endif + hb_fsSeekLarge( pIndex->DiskFile, + hb_ntxFileOffset( pIndex, ulBlock ), FS_SET ); + if( hb_fsRead( pIndex->DiskFile, buffer, iSize ) != iSize ) { - return pTag->pages + ( ulOffset / NTXBLOCKSIZE - 1 ); + hb_ntxErrorRT( pIndex->Owner, EG_READ, EDBF_READ, + pIndex->IndexName, hb_fsError(), 0 ); + return FALSE; } - pPage = hb_ntxPageFind( pTag, ulOffset ); - if( pPage ) + return TRUE; +} + +/* + * write a given block into index file + */ +static BOOL hb_ntxBlockWrite( LPNTXINDEX pIndex, ULONG ulBlock, BYTE *buffer, int iSize ) +{ + if( !pIndex->lockWrite ) + hb_errInternal( 9102, "hb_ntxBlockWrite on not locked index file.", "", "" ); + +#ifdef HB_NTX_DEBUG_DISP + s_wrNO++; +#endif + hb_fsSeekLarge( pIndex->DiskFile, + hb_ntxFileOffset( pIndex, ulBlock ), FS_SET ); + if( hb_fsWrite( pIndex->DiskFile, buffer, iSize ) != iSize ) { - pPage->lBusy = TRUE; + hb_ntxErrorRT( pIndex->Owner, EG_WRITE, EDBF_WRITE, + pIndex->IndexName, hb_fsError(), 0 ); + return FALSE; + } + return TRUE; +} + +/* + * write a given tag page to file + */ +static BOOL hb_ntxPageSave( LPNTXINDEX pIndex, LPPAGEINFO pPage ) +{ + hb_ntxSetKeyCount( pPage, pPage->uiKeys ); + if( !hb_ntxBlockWrite( pIndex, pPage->Page, + (BYTE *) hb_ntxPageBuffer( pPage ), NTXBLOCKSIZE ) ) + return FALSE; + pPage->Changed = FALSE; + pIndex->fFlush = TRUE; + /* In shared mode we have to update counter in version field of + NTXHEADER to signal for other stations that their index buffers + has to be discarded */ + if( pIndex->fShared ) + pIndex->Changed = TRUE; + return TRUE; +} + +/* + * discard all index buffers due to concurrent access + */ +static void hb_ntxDiscardBuffers( LPNTXINDEX pIndex ) +{ + pIndex->ulPages = pIndex->ulPageLast = 0; + pIndex->pChanged = pIndex->pFirst = pIndex->pLast = NULL; + if( pIndex->Compound ) + { + int i; + + for( i = 0; i < pIndex->iTags; i++ ) + { + pIndex->lpTags[ i ]->RootBlock = 0; + pIndex->lpTags[ i ]->stackLevel = 0; + } + } + else + { + pIndex->TagBlock = 0; + if( pIndex->iTags ) + pIndex->lpTags[ 0 ]->stackLevel = 0; + } +} + +/* + * update tag flags + */ +static void hb_ntxTagUpdateFlags( LPTAGINFO pTag ) +{ + USHORT uiSignature = pTag->Signature; + + pTag->Custom = ( uiSignature & NTX_FLAG_CUSTOM ) != 0; + pTag->ChgOnly = ( uiSignature & NTX_FLAG_CHGONLY ) != 0; + pTag->Partial = ( uiSignature & NTX_FLAG_PARTIAL ) != 0; + pTag->Template = ( uiSignature & NTX_FLAG_TEMPLATE ) != 0; + pTag->MultiKey = ( uiSignature & NTX_FLAG_MULTIKEY ) != 0; + pTag->fSortRec = ( uiSignature & NTX_FLAG_SORTRECNO ) != 0; +} + +/* + * check tag header in compound index + */ +static BOOL hb_ntxTagHeaderCheck( LPTAGINFO pTag ) +{ + if( !pTag->RootBlock ) + { + if( pTag->HeadBlock ) + { + BYTE buffer[ 12 ]; + if( hb_ntxBlockRead( pTag->Owner, pTag->HeadBlock, buffer, 12 ) ) + { + pTag->Signature = HB_GET_LE_UINT16( ( ( LPNTXHEADER ) buffer )->type ); + pTag->RootBlock = HB_GET_LE_UINT32( ( ( LPNTXHEADER ) buffer )->root ); + hb_ntxTagUpdateFlags( pTag ); + } + } + } + return pTag->RootBlock != 0; +} + +/* + * free buffers for pages in the tag + */ +static void hb_ntxFreePageBuffer( LPNTXINDEX pIndex ) +{ + ULONG ul, ulMax = pIndex->ulPagesDepth; + LPPAGEINFO * pPagePtr = pIndex->pages; + + if( ulMax ) + { + for( ul = 0; ul < ulMax; ul++, pPagePtr++ ) + { + if( *pPagePtr ) + { +#ifdef HB_NTX_EXTERNAL_PAGEBUFFER + if( hb_ntxPageBuffer( *pPagePtr ) ) + hb_xfree( hb_ntxPageBuffer( *pPagePtr ) ); +#endif + hb_xfree( *pPagePtr ); + } + } + hb_xfree( pIndex->pages ); + pIndex->pages = NULL; + pIndex->ulPages = pIndex->ulPageLast = pIndex->ulPagesDepth = 0; + pIndex->pFirst = pIndex->pLast = pIndex->pChanged = NULL; + } +} + +/* + * trunc index file, left only space for header + */ +static void hb_ntxIndexTrunc( LPNTXINDEX pIndex ) +{ + if( !pIndex->lockWrite ) + hb_errInternal( 9102, "hb_ntxIndexTrunc on not locked index file.", "", "" ); + + hb_ntxFreePageBuffer( pIndex ); + pIndex->Update = pIndex->Changed = pIndex->fFlush = TRUE; + pIndex->TagBlock = pIndex->NextAvail = 0; + pIndex->Version = 0; + hb_fsSeek( pIndex->DiskFile, NTXBLOCKSIZE, FS_SET ); + hb_fsWrite( pIndex->DiskFile, NULL, 0 ); +} + +/* + * try to find given tag page in the buffer + */ +static LPPAGEINFO hb_ntxPageFind( LPTAGINFO pTag, ULONG ulPage ) +{ + LPPAGEINFO * pPagePtr = pTag->Owner->pages; + ULONG u; + + for( u = pTag->Owner->ulPages; u; u--, pPagePtr++ ) + { + if( *pPagePtr && (*pPagePtr)->Page == ulPage ) + return *pPagePtr; + } + return NULL; +} + +/* + * try to find free space in buffer + */ +static LPPAGEINFO hb_ntxPageGetBuffer( LPTAGINFO pTag, ULONG ulPage ) +{ + LPNTXINDEX pIndex = pTag->Owner; + LPPAGEINFO * pPagePtr; + + if( pIndex->ulPages < pIndex->ulPagesDepth ) + { + pPagePtr = &pIndex->pages[ pIndex->ulPages++ ]; + } + else if( pIndex->pFirst ) + { + LPPAGEINFO pPage = pIndex->pFirst; + + if( pPage->iUsed ) + hb_errInternal( 9999, "hb_ntxPageGetBuffer: page used.", "", "" ); + if( pPage->Changed ) + hb_errInternal( 9999, "hb_ntxPageGetBuffer: page changed.", "", "" ); + + pIndex->pFirst = pPage->pNext; + if( pIndex->pFirst ) + pIndex->pFirst->pPrev = NULL; + else + pIndex->pLast = NULL; + pPage->pPrev = NULL; + pPage->Page = ulPage; + pPage->iUsed = 1; + return pPage; } - if( pTag->ulPages == pTag->ulPagesDepth ) + else if( pIndex->ulPagesDepth == 0 ) { - - pPage = pTag->pages; - while( ul < pTag->ulPages ) + pIndex->ulPages = 1; + pIndex->ulPageLast = 0; + pIndex->ulPagesDepth = NTX_PAGES_PER_TAG; + pIndex->pages = (LPPAGEINFO*) hb_xgrab( sizeof(LPPAGEINFO) * NTX_PAGES_PER_TAG ); + memset( pIndex->pages, 0, sizeof(LPPAGEINFO) * NTX_PAGES_PER_TAG ); + pPagePtr = &pIndex->pages[0]; + } + else + { + ULONG ul = pIndex->ulPageLast; + do { - /* - if( ( !pIndex->Owner->fShared && !pPage->lBusy ) || - ( pIndex->Owner->fShared && pPage->Page == -1 ) ) - */ - if( !pPage->lBusy ) - break; - pPage ++; - ul ++; + if( ++ul >= pIndex->ulPagesDepth ) + ul = 0; + pPagePtr = &pIndex->pages[ ul ]; + if( !(*pPagePtr)->iUsed && !(*pPagePtr)->Changed ) + { + pIndex->ulPageLast = ul; + break; + } + if( ul == pIndex->ulPageLast ) + { + ul = pIndex->ulPagesDepth; + pIndex->ulPagesDepth += NTX_PAGES_PER_TAG >> 1; + pIndex->pages = (LPPAGEINFO*) hb_xrealloc( pIndex->pages, + sizeof(LPPAGEINFO) * pIndex->ulPagesDepth ); + memset( pIndex->pages + ul, 0, + ( NTX_PAGES_PER_TAG >> 1 ) * sizeof( LPPAGEINFO ) ); + pIndex->ulPages++; + pPagePtr = &pIndex->pages[ ul ]; + pIndex->ulPageLast = 0; + break; + } } - if( ul < pTag->ulPages ) - bReplace = TRUE; + while( TRUE ); } - if( !bReplace ) + if( !*pPagePtr ) { - /* LPPAGEINFO pLastPage; ? */ - - if( pTag->ulPages == pTag->ulPagesDepth ) - { - pTag->ulPagesDepth += NTX_PAGES_PER_TAG/2; - pTag->pages = (LPPAGEINFO) hb_xrealloc( pTag->pages, - sizeof(HB_PAGEINFO) * pTag->ulPagesDepth ); - for( ul=pTag->ulPages; ululPagesDepth; ul++ ) - memset( pTag->pages+ul, 0 ,sizeof( HB_PAGEINFO ) ); - } - pPage = pTag->pages + pTag->ulPages; - pTag->ulPages ++; - if( !pPage->buffer ) - pPage->buffer = ( char* ) hb_xgrab( NTXBLOCKSIZE ); + *pPagePtr = ( LPPAGEINFO ) hb_xgrab( sizeof( HB_PAGEINFO ) ); + memset( *pPagePtr, 0, sizeof( HB_PAGEINFO ) ); } - pPage->Page = ulOffset; +#ifdef HB_NTX_EXTERNAL_PAGEBUFFER + if( !hb_ntxPageBuffer( *pPagePtr ) ) + { + hb_ntxPageBuffer( *pPagePtr ) = ( char* ) hb_xgrab( NTXBLOCKSIZE ); + memset( hb_ntxPageBuffer( *pPagePtr ), 0, NTXBLOCKSIZE ); + } +#endif + (*pPagePtr)->pPrev = NULL; + (*pPagePtr)->Page = ulPage; + (*pPagePtr)->iUsed = 1; + return *pPagePtr; +} - hb_fsSeek( pTag->Owner->DiskFile, ulOffset, FS_SET ); - if( hb_fsRead( pTag->Owner->DiskFile, (BYTE *) pPage->buffer, NTXBLOCKSIZE ) - != NTXBLOCKSIZE ) - return NULL; +/* + * free the index page for future reuse + */ +static void hb_ntxPageFree( LPTAGINFO pTag, LPPAGEINFO pPage ) +{ + hb_ntxSetKeyPage( pPage, 0, pTag->Owner->NextAvail ); + pTag->Owner->NextAvail = pPage->Page; + pTag->Owner->Changed = pPage->Changed = TRUE; +} - pPage->CurKey = -1; - pPage->lBusy = TRUE; - pPage->Changed = FALSE; - pPage->uiKeys = * (USHORT*)pPage->buffer; +/* + * mark used page as free + */ +static void hb_ntxPageRelease( LPTAGINFO pTag, LPPAGEINFO pPage ) +{ + LPNTXINDEX pIndex = pTag->Owner; + if( --pPage->iUsed == 0 ) + { + if( pPage->Changed ) + { + if( !pPage->pPrev ) + { + pPage->pPrev = pPage; + pPage->pNext = pIndex->pChanged; + pIndex->pChanged = pPage; + } + } + else if( pIndex->pLast ) + { + pIndex->pLast->pNext = pPage; + pPage->pPrev = pIndex->pLast; + pPage->pNext = NULL; + pIndex->pLast = pPage; + } + else + { + pPage->pNext = pPage->pPrev = NULL; + pIndex->pFirst = pIndex->pLast = pPage; + } + } + else if( pPage->iUsed < 0 ) + hb_errInternal( 9999, "hb_ntxPageRelease: unused page freed.", "", "" ); +} + +/* + * load page from index file or the buffer + */ +static LPPAGEINFO hb_ntxPageLoad( LPTAGINFO pTag, ULONG ulPage ) +{ + LPPAGEINFO pPage; + + if( !ulPage ) + { + if( hb_ntxTagHeaderCheck( pTag ) ) + ulPage = pTag->RootBlock; + if( !ulPage ) + { + hb_ntxErrorRT( pTag->Owner->Owner, EG_CORRUPTION, EDBF_CORRUPT, + pTag->Owner->IndexName, 0, 0 ); + } + } + pPage = hb_ntxPageFind( pTag, ulPage ); + if( pPage ) + { + if( !pPage->Changed && !pPage->iUsed ) + { + if( pPage->pNext ) + pPage->pNext->pPrev = pPage->pPrev; + else + pTag->Owner->pLast = pPage->pPrev; + if( pPage->pPrev ) + { + pPage->pPrev->pNext = pPage->pNext; + pPage->pPrev = NULL; + } + else + pTag->Owner->pFirst = pPage->pNext; + } + pPage->iUsed++; + } + else + { + pPage = hb_ntxPageGetBuffer( pTag, ulPage ); + if( !hb_ntxBlockRead( pTag->Owner, ulPage, + (BYTE *) hb_ntxPageBuffer( pPage ), NTXBLOCKSIZE ) ) + return NULL; + pPage->Changed = FALSE; + pPage->uiKeys = hb_ntxGetKeyCount( pPage ); + } return pPage; } -static void hb_ntxPageRelease( LPTAGINFO pTag, LPPAGEINFO pPage ) +/* + * initialize empty page structure + */ +static void hb_ntxPageInit( LPTAGINFO pTag, LPPAGEINFO pPage ) { + USHORT u, o = ( pTag->MaxKeys + 2 ) << 1; - if( pTag->Memory ) - return; - pPage->lBusy = FALSE; - if( pPage->Changed ) - hb_ntxPageSave( pTag,pPage ); - if( pTag->NewRoot ) - { - pTag->RootBlock = pPage->Page; - hb_ntxHeaderSave( pTag->Owner, FALSE ); - pTag->NewRoot = FALSE; - } + for( u = 0; u <= pTag->MaxKeys; u++, o += pTag->KeyLength + 8 ) + hb_ntxSetKeyOffset( pPage, u, o ); + hb_ntxSetKeyPage( pPage, 0, 0 ); + pPage->uiKeys = 0; } -static void hb_ntxPageFree( LPTAGINFO pTag, BOOL lFull ) +/* + * allocate new page address + */ +static ULONG hb_ntxPageAlloc( LPNTXINDEX pIndex ) { - - ULONG ul = 0, ulMax = (lFull)? pTag->ulPagesDepth:pTag->ulPages; - LPPAGEINFO pPage = pTag->pages; - - if( pTag->Memory ) + ULONG ulPage; + if( !pIndex->TagBlock ) { - if( !lFull ) - return; - hb_xfree( pTag->pages[0].buffer ); - ul = pTag->ulPagesStart; - pPage = pTag->pages + ul; + HB_FOFFSET fOffset; + fOffset = hb_fsSeekLarge( pIndex->DiskFile, 0, FS_END ); + pIndex->TagBlock = ( ULONG ) + ( fOffset >> ( pIndex->LargeFile ? NTXBLOCKBITS : 0 ) ); } - for( ; ul < ulMax; ul++,pPage++ ) - { - if( pPage->Changed && !pTag->Memory ) - hb_ntxPageSave( pTag, pPage ); - if( pTag->NewRoot && !pTag->Memory ) - { - pTag->RootBlock = pPage->Page; - hb_ntxHeaderSave( pTag->Owner, FALSE ); - pTag->NewRoot = FALSE; - } - if( lFull ) - { - if( pPage->buffer ) - { - hb_xfree( pPage->buffer ); - pPage->buffer = NULL; - } - } - pPage->Page = -1; - } - pTag->ulPages = 0; + ulPage = pIndex->TagBlock; + pIndex->TagBlock += pIndex->LargeFile ? 1 : NTXBLOCKSIZE; + return ulPage; } -static LPPAGEINFO hb_ntxPageNew( LPTAGINFO pTag ) +/* + * allocate new page in index file - reuse freed one or increase file + */ +static LPPAGEINFO hb_ntxPageNew( LPTAGINFO pTag, BOOL fNull ) { - LPPAGEINFO pPage = NULL; + LPPAGEINFO pPage; - if( pTag->Owner->NextAvail > 0 ) + if( pTag->Owner->NextAvail != 0 ) { /* Handling of a pool of empty pages. Some sources says that this address is in the first 4 bytes of @@ -1411,2091 +1344,4217 @@ static LPPAGEINFO hb_ntxPageNew( LPTAGINFO pTag ) in the page - it is done here now in such a way. = Alexander Kresin = */ - pPage = hb_ntxPageLoad( pTag,pTag->Owner->NextAvail ); - pPage->Page = pTag->Owner->NextAvail; - pTag->Owner->NextAvail = KEYITEM( pPage, 0 )->page; - hb_ntxHeaderSave( pTag->Owner, FALSE ); + pPage = hb_ntxPageLoad( pTag, pTag->Owner->NextAvail ); + if( ! pPage ) + return NULL; + if( pPage->uiKeys != 0 ) + { + hb_ntxErrorRT( pTag->Owner->Owner, EG_CORRUPTION, EDBF_CORRUPT, + pTag->Owner->IndexName, 0, 0 ); + return NULL; + } + pTag->Owner->NextAvail = hb_ntxGetKeyPage( pPage, 0 ); +#if defined( HB_NTX_NOMULTITAG ) + hb_ntxSetKeyPage( pPage, 0, 0 ); + pPage->uiKeys = 0; +#else + hb_ntxPageInit( pTag, pPage ); +#endif } else { - int i; - LPNTXBUFFER itemlist; - BOOL bReplace = FALSE; - ULONG ul = 0; - - if( pTag->ulPages == pTag->ulPagesDepth ) - { - pPage = pTag->pages; - while( ul < pTag->ulPages ) - { - if( !pPage->lBusy ) - break; - pPage ++; - ul ++; - } - if( ul < pTag->ulPages ) - bReplace = TRUE; - } - - if( bReplace ) - { - pPage->uiKeys = 0; - } - else - { - if( pTag->ulPages == pTag->ulPagesDepth ) - { - pTag->ulPagesDepth += NTX_PAGES_PER_TAG/2; - pTag->pages = (LPPAGEINFO) hb_xrealloc( pTag->pages, - sizeof(HB_PAGEINFO) * pTag->ulPagesDepth ); - for( ul=pTag->ulPages; ululPagesDepth; ul++ ) - memset( pTag->pages+ul, 0 ,sizeof( HB_PAGEINFO ) ); - } - pPage = pTag->pages + pTag->ulPages; - pTag->ulPages ++; - if( !pPage->buffer ) - pPage->buffer = ( char* ) hb_xgrab( NTXBLOCKSIZE ); - } - memset( pPage->buffer, 0, NTXBLOCKSIZE ); - itemlist = ( LPNTXBUFFER ) pPage->buffer; - for( i = 0; i < pTag->MaxKeys+1; i++ ) - itemlist->item_offset[i] = 2 + 2 * ( pTag->MaxKeys + 1 ) + - i * ( pTag->KeyLength + 8 ); - pTag->TagBlock += 1024; - pPage->Page = pTag->TagBlock; - pPage->CurKey = -1; - pPage->lBusy = TRUE; - pPage->Changed = FALSE; + pPage = hb_ntxPageGetBuffer( pTag, fNull ? 0 : hb_ntxPageAlloc( pTag->Owner ) ); + hb_ntxPageInit( pTag, pPage ); } + pTag->Owner->Changed = pPage->Changed = TRUE; return pPage; } -static void hb_ntxKeysMove( LPTAGINFO pTag, LPPAGEINFO pPageDest, LPPAGEINFO pPageSrc, USHORT iDest, USHORT iSrc, USHORT iKeys ) -{ - int i, keyLength = pTag->KeyLength + 8; - for( i=0;ibuffer + *((USHORT*)(pPageDest->buffer+(i+iDest)*2+2)), - pPageSrc->buffer+ *((USHORT*)(pPageSrc->buffer+(i+iSrc)*2+2)), keyLength ); -} - -static BOOL hb_ntxPageJoin( LPTAGINFO pTag, LPPAGEINFO pPageParent, LPPAGEINFO pPage1, LPPAGEINFO pPage2, SHORT ikey1, SHORT ikey2 ) -{ - int i; - USHORT ntmp; - - KEYITEM( pPage1, pPage1->uiKeys )->rec_no = KEYITEM( pPageParent, ikey1 )->rec_no; - memcpy( KEYITEM( pPage1, pPage1->uiKeys )->key,KEYITEM( pPageParent, ikey1 )->key,pTag->KeyLength ); - KEYITEM( pPageParent, ikey2 )->page = pPage1->Page; - - hb_ntxKeysMove( pTag, pPage1, pPage2, pPage1->uiKeys+1, 0, pPage2->uiKeys+1 ); - - pPage1->uiKeys += pPage2->uiKeys + 1; - pPage1->Changed = TRUE; - pPage2->uiKeys = 0; - pPage2->Changed = TRUE; - KEYITEM( pPage2, 0 )->page = pTag->Owner->NextAvail; - pTag->Owner->NextAvail = pPage2->Page; - hb_ntxHeaderSave( pTag->Owner, FALSE ); - - hb_ntxPageRelease( pTag,pPage1 ); - hb_ntxPageRelease( pTag,pPage2 ); - - ntmp = *KEYPOINTER( pPageParent,ikey1 ); - for( i=ikey1; i<=pPageParent->uiKeys; i++ ) - *KEYPOINTER( pPageParent,i ) = *KEYPOINTER( pPageParent,i+1 ); - *KEYPOINTER( pPageParent,pPageParent->uiKeys ) = ntmp; - pPageParent->uiKeys--; - pPageParent->Changed = TRUE; - if( pPageParent->uiKeys < pTag->MaxKeys/2 ) - return FALSE; - - return TRUE; - -} - -static void hb_ntxPageBalance( LPTAGINFO pTag, LPPAGEINFO pPageParent, LPPAGEINFO pPage1, LPPAGEINFO pPage2, SHORT ikey1, SHORT ikey2 ) -{ - int i; - USHORT ntmp; - int nKeys = ( pPage1->uiKeys + pPage2->uiKeys ) / 2 - pPage1->uiKeys; - - if( ikey2 > ikey1 ) - { - /* printf( "\nntxPageBalance - 10 %d %d %d ",pPage1->uiKeys,pPage2->uiKeys,nKeys ); */ - KEYITEM( pPage1, pPage1->uiKeys )->rec_no = KEYITEM( pPageParent, ikey1 )->rec_no; - memcpy( KEYITEM( pPage1, pPage1->uiKeys )->key,KEYITEM( pPageParent, ikey1 )->key,pTag->KeyLength ); - - hb_ntxKeysMove( pTag, pPage1, pPage2, pPage1->uiKeys+1, 0, nKeys-1 ); - - KEYITEM( pPageParent, ikey1 )->rec_no = KEYITEM( pPage2, nKeys-1 )->rec_no; - memcpy( KEYITEM( pPageParent, ikey1 )->key, KEYITEM( pPage2, nKeys-1 )->key,pTag->KeyLength ); - KEYITEM( pPage1, pPage1->uiKeys+nKeys )->page = KEYITEM( pPage2, nKeys-1 )->page; - - pPage2->uiKeys -= nKeys; - for( i=0; i<=pPage2->uiKeys; i++ ) - { - ntmp = *KEYPOINTER( pPage2,i ); - *KEYPOINTER( pPage2,i ) = *KEYPOINTER( pPage2,i+nKeys ); - *KEYPOINTER( pPage2,i+nKeys ) = ntmp; - } - } - else - { - /* printf( "\nntxPageBalance - 20 %d",nKeys ); */ - for( i=pPage1->uiKeys; i>=0; i-- ) - { - ntmp = *KEYPOINTER( pPage1,i+nKeys ); - *KEYPOINTER( pPage1,i+nKeys ) = *KEYPOINTER( pPage1,i ); - *KEYPOINTER( pPage1,i ) = ntmp; - } - - KEYITEM( pPage1, nKeys-1 )->rec_no = KEYITEM( pPageParent, ikey2 )->rec_no; - memcpy( KEYITEM( pPage1, nKeys-1 )->key,KEYITEM( pPageParent, ikey2 )->key,pTag->KeyLength ); - KEYITEM( pPage1, nKeys-1 )->page = KEYITEM( pPage2, pPage2->uiKeys )->page; - - pPage2->uiKeys -= nKeys; - hb_ntxKeysMove( pTag, pPage1, pPage2, 0, pPage2->uiKeys+1, nKeys-1 ); - - KEYITEM( pPageParent, ikey2 )->rec_no = KEYITEM( pPage2, pPage2->uiKeys )->rec_no; - memcpy( KEYITEM( pPageParent, ikey2 )->key, KEYITEM( pPage2, pPage2->uiKeys )->key,pTag->KeyLength ); - } - pPage1->uiKeys += nKeys; - pPage1->Changed = TRUE; - pPage2->Changed = TRUE; - pPageParent->Changed = TRUE; - hb_ntxPageRelease( pTag,pPage1 ); - hb_ntxPageRelease( pTag,pPage2 ); - hb_ntxPageRelease( pTag,pPageParent ); -} - -static void hb_ntxTagBalance( LPTAGINFO pTag, int level ) -{ - - if( pTag->stackLevel > level ) - { - SHORT thiskey,pairkey; - LPPAGEINFO pPagePair; - LPPAGEINFO pPage = hb_ntxPageLoad( pTag, pTag->stack[level].page ); - LPPAGEINFO pPageParent = hb_ntxPageLoad( pTag, pTag->stack[level+1].page ); - - /* printf( "\nntxTagBalance-1, %d %d %x %x",pTag->stackLevel,level,pPageParent->Page,pPage->Page ); */ - thiskey = pairkey = pTag->stack[level+1].ikey; - do - pairkey ++; - while( pairkey <= pPageParent->uiKeys && !KEYITEM( pPageParent, pairkey )->page ); - if( pairkey > pPageParent->uiKeys && thiskey >= pPageParent->uiKeys-1 ) - { - pairkey = thiskey; - do - pairkey --; - while( pairkey >= 0 && !(KEYITEM( pPageParent, pairkey )->page) ); - if( pairkey < 0 && thiskey == 0 ) - { - hb_ntxPageRelease( pTag,pPageParent ); - return; - } - if( thiskey - pairkey > 1 ) - { - hb_ntxPageRelease( pTag,pPageParent ); - } - else - { - pPagePair = hb_ntxPageLoad( pTag, KEYITEM( pPageParent, pairkey )->page ); - if( pPageParent->uiKeys == 1 && pPage->uiKeys && pPagePair->uiKeys && - ( pPage->uiKeys + pPagePair->uiKeys ) > pTag->MaxKeys - 2 ) - { - hb_ntxPageRelease( pTag,pPageParent ); - hb_ntxPageRelease( pTag,pPagePair ); - return; - } - - if( pPagePair->uiKeys <= pTag->MaxKeys/2 ) - { - /* printf( "\nntxTagBalance - 10, %d %d",thiskey,pairkey ); */ - if( !hb_ntxPageJoin( pTag,pPageParent,pPagePair,pPage,pairkey,thiskey ) ) - hb_ntxTagBalance( pTag, level+1 ); - hb_ntxPageRelease( pTag,pPageParent ); - } - else - { - /* printf( "\nntxTagBalance - 20, %d %d",thiskey,pairkey ); */ - hb_ntxPageBalance( pTag, pPageParent, pPage,pPagePair,thiskey,pairkey ); - } - } - } - else - { - if( pairkey - thiskey > 1 ) - { - hb_ntxPageRelease( pTag,pPageParent ); - } - else - { - pPagePair = hb_ntxPageLoad( pTag, KEYITEM( pPageParent, pairkey )->page ); - if( pPageParent->uiKeys == 1 && pPage->uiKeys && pPagePair->uiKeys && - ( pPage->uiKeys + pPagePair->uiKeys ) > pTag->MaxKeys - 2 ) - { - hb_ntxPageRelease( pTag,pPageParent ); - hb_ntxPageRelease( pTag,pPagePair ); - return; - } - /* printf( "\nntxTagBalance - 3A %x %x %x %d",pPageParent->Page,pPage->Page,pPagePair->Page,pPagePair->uiKeys ); */ - if( pPagePair->uiKeys <= pTag->MaxKeys/2 ) - { - /* printf( "\nntxTagBalance - 30, %d %d",thiskey,pairkey ); */ - if( !hb_ntxPageJoin( pTag,pPageParent,pPage,pPagePair,thiskey,pairkey ) ) - hb_ntxTagBalance( pTag, level+1 ); - hb_ntxPageRelease( pTag,pPageParent ); - } - else - { - /* printf( "\nntxTagBalance - 40, %d %d",thiskey,pairkey ); */ - hb_ntxPageBalance( pTag, pPageParent, pPage,pPagePair,thiskey,pairkey ); - } - } - } - } -} - -static void hb_ntxPageKeyInsert( LPTAGINFO pTag, LPPAGEINFO pPage, LPKEYINFO pKey, int pos ) -{ - int i; - USHORT ntmp; - - ntmp = *KEYPOINTER( pPage,pPage->uiKeys+1 ); - - for( i=pPage->uiKeys; i>=pos; i-- ) - *KEYPOINTER( pPage,i+1 ) = *KEYPOINTER( pPage,i ); - - *KEYPOINTER( pPage,pos ) = ntmp; - - pPage->uiKeys++; - pPage->Changed = TRUE; - KEYITEM( pPage, pos )->rec_no = pKey->Xtra; - memcpy( KEYITEM( pPage, pos )->key, pKey->key,pTag->KeyLength ); - KEYITEM( pPage, pos )->page = pKey->Tag; -} - -static LPKEYINFO hb_ntxPageKeyDel( LPTAGINFO pTag, LPPAGEINFO pPage, SHORT pos, USHORT level ) -{ - int i; - LPKEYINFO pKey = NULL; - - if( KEYITEM( pPage, pos )->page ) - { - LPPAGEINFO pPageChild = hb_ntxPageLoad( pTag,KEYITEM( pPage, pos )->page ); - LPKEYINFO pKeyNew = NULL; - SHORT CurKey = ( KEYITEM( pPageChild, pPageChild->uiKeys )->page )? - pPageChild->uiKeys : pPageChild->uiKeys-1; - - /* printf( "\nhb_ntxPageKeyDel-1 %d %d %x",level,pos,pPage->Page ); */ - for( i=pTag->stackLevel; i>=0; i-- ) - { - pTag->stack[i+1].page = pTag->stack[i].page; - pTag->stack[i+1].ikey = pTag->stack[i].ikey; - } - if( ++(pTag->stackLevel) >= pTag->stackDepth ) - { - pTag->stackDepth += 32; - pTag->stack = (LPTREESTACK) hb_xrealloc( pTag->stack, - sizeof(TREE_STACK) * pTag->stackDepth ); - } - pTag->stack[0].page = pPageChild->Page; - pTag->stack[0].ikey = CurKey; - - pKey = hb_ntxPageKeyDel( pTag, pPageChild, CurKey,level+1 ); - hb_ntxPageRelease( pTag,pPageChild ); - if( level > 1 ) - { - if( pos == pPage->uiKeys ) - { - pKey->Tag = pPage->Page; - /* printf( "\nhb_ntxPageKeyDel-A %d %x",pKey->Xtra,pPage->Page ); */ - return pKey; - } - else - { - pKeyNew = hb_ntxKeyNew( NULL,pTag->KeyLength ); - memcpy( pKeyNew->key, KEYITEM( pPage, pos )->key,pTag->KeyLength ); - pKeyNew->Xtra = KEYITEM( pPage, pos )->rec_no; - pKeyNew->Tag = pPage->Page; - /* printf( "\nhb_ntxPageKeyDel-B %d %x",pKeyNew->Xtra,pPage->Page ); */ - } - } - memcpy( KEYITEM( pPage, pos )->key, pKey->key,pTag->KeyLength ); - KEYITEM( pPage, pos )->page = pKey->Tag; - KEYITEM( pPage, pos )->rec_no = pKey->Xtra; - /* printf( "\nhb_ntxPageKeyDel-C %d %x",pKey->Xtra,pKey->Tag ); */ - pPage->Changed = TRUE; - hb_ntxKeyFree( pKey ); - return pKeyNew; - } - else - { - /* printf( "\nhb_ntxPageKeyDel-2 %d %d %x",level,pos,pPage->Page ); */ - if( level > 1 ) - { - pKey = hb_ntxKeyNew( NULL,pTag->KeyLength ); - memcpy( pKey->key, KEYITEM( pPage, pos )->key,pTag->KeyLength ); - pKey->Xtra = KEYITEM( pPage, pos )->rec_no; - pKey->Tag = pPage->Page; - } - else - { - USHORT ntmp = *KEYPOINTER( pPage,pos ); - for( i=pos; i<=pPage->uiKeys; i++ ) - *KEYPOINTER( pPage,i ) = *KEYPOINTER( pPage,i+1 ); - *KEYPOINTER( pPage,pPage->uiKeys ) = ntmp; - } - pPage->uiKeys--; - pPage->Changed = TRUE; - if( pPage->uiKeys < pTag->MaxKeys/2 ) - pTag->stack[0].ikey = -1; - /* - if( !pPage->uiKeys ) - { - if( pKey ) - pKey->Tag = 0; - KEYITEM( pPage, 0 )->page = pTag->Owner->NextAvail; - // pPage->pKeys->Tag = pTag->Owner->NextAvail; - pTag->Owner->NextAvail = pPage->Page; - hb_ntxHeaderSave( pTag->Owner, FALSE ); - } - */ - return pKey; - } -} - -static LPKEYINFO hb_ntxPageSplit( LPTAGINFO pTag, LPPAGEINFO pPage, LPKEYINFO pKey, int pos ) -{ - LPPAGEINFO pNewPage = hb_ntxPageNew( pTag ); - LPKEYINFO pKeyNew = hb_ntxKeyNew( NULL, pTag->KeyLength ); - int i, j, iHalf = pPage->uiKeys/2; - USHORT ntmp; - - if( pos < iHalf+1 ) - { - /* Move to the new page the keys, less than inserted */ - if( pos ) - hb_ntxKeysMove( pTag, pNewPage, pPage, 0, 0, pos ); - if( pos < iHalf ) - { - /* Copy the inserted key */ - KEYITEM( pNewPage, pos )->rec_no = pKey->Xtra; - memcpy( KEYITEM( pNewPage, pos )->key, pKey->key,pTag->KeyLength ); - KEYITEM( pNewPage, pos )->page = pKey->Tag; - /* Move to the new page the keys, greater than inserted */ - hb_ntxKeysMove( pTag, pNewPage, pPage, pos+1, pos, iHalf-pos-1 ); - /* Create key for the parent page */ - pKeyNew->Xtra = KEYITEM( pPage,iHalf-1 )->rec_no; - pKeyNew->Tag = pNewPage->Page; - memcpy( pKeyNew->key, KEYITEM( pPage,iHalf-1 )->key, pTag->KeyLength ); - - KEYITEM( pNewPage,iHalf )->page = KEYITEM( pPage,iHalf-1 )->page; - } - else - { - /* Create key for the parent page */ - pKeyNew->Xtra = pKey->Xtra; - pKeyNew->Tag = pNewPage->Page; - memcpy( pKeyNew->key, pKey->key,pTag->KeyLength ); - - KEYITEM( pNewPage,iHalf )->page = pKey->Tag; - } - - /* Move second half of a page to the moved first half */ - for( i=0,j=iHalf; j<=pPage->uiKeys; i++,j++ ) - { - ntmp = *KEYPOINTER( pPage,i ); - *KEYPOINTER( pPage,i ) = *KEYPOINTER( pPage,j ); - *KEYPOINTER( pPage,j ) = ntmp; - } - pPage->uiKeys -= iHalf; - } - else - { - /* Move to the new page the first half */ - hb_ntxKeysMove( pTag, pNewPage, pPage, 0, 0, iHalf ); - /* Create key for the parent page */ - pKeyNew->Xtra = KEYITEM( pPage,iHalf )->rec_no; - pKeyNew->Tag = pNewPage->Page; - memcpy( pKeyNew->key, KEYITEM( pPage,iHalf )->key,pTag->KeyLength ); - KEYITEM( pNewPage,iHalf )->page = KEYITEM( pPage,iHalf )->page; - - /* Move second half of a page to the moved first half */ - for( i=0,j=iHalf+1; j<=pPage->uiKeys; i++,j++ ) - { - ntmp = *KEYPOINTER( pPage,i ); - *KEYPOINTER( pPage,i ) = *KEYPOINTER( pPage,j ); - *KEYPOINTER( pPage,j ) = ntmp; - } - pPage->uiKeys -= (iHalf+1); - /* Insert new key */ - hb_ntxPageKeyInsert( pTag, pPage, pKey, pos-iHalf-1 ); - } - pNewPage->uiKeys = iHalf; - pPage->Changed = pNewPage->Changed = TRUE; - hb_ntxPageRelease( pTag,pNewPage ); - return pKeyNew; -} - -static LPKEYINFO hb_ntxPageKeyAdd( LPTAGINFO pTag, LPPAGEINFO pPage, LPKEYINFO pKey ) -{ - - hb_ntxPageKeySearch( pTag, pPage, pKey->key, pTag->KeyLength, TRUE, TRUE ); - - if( KEYITEM( pPage, pPage->CurKey )->page != 0 ) - { - LPKEYINFO pKeyFromChild, pKeyReturn = NULL; - LPPAGEINFO pChildPage = hb_ntxPageLoad( pTag, - KEYITEM( pPage, pPage->CurKey )->page ); - pKeyFromChild = hb_ntxPageKeyAdd( pTag, pChildPage, pKey ); - hb_ntxPageRelease( pTag,pChildPage ); - if( pKeyFromChild ) - { - if( pPage->uiKeys == pTag->MaxKeys ) - pKeyReturn = hb_ntxPageSplit( pTag, pPage, pKeyFromChild, pPage->CurKey ); - else - hb_ntxPageKeyInsert( pTag, pPage, pKeyFromChild, pPage->CurKey ); - - hb_ntxKeyFree( pKeyFromChild ); - } - return pKeyReturn; - } - else if( pPage->uiKeys == pTag->MaxKeys ) - { - return hb_ntxPageSplit( pTag, pPage, pKey, pPage->CurKey ); - } - else - { - hb_ntxPageKeyInsert( pTag, pPage, pKey, pPage->CurKey ); - return NULL; - } -} - -static void hb_ntxTagKeyAdd( LPTAGINFO pTag, LPKEYINFO pKey ) -{ - - LPPAGEINFO pPage = hb_ntxPageLoad( pTag,0 ); - - if( pPage->uiKeys == 0 ) - { - pPage->uiKeys = 1; - KEYITEM( pPage, 0 )->rec_no = pKey->Xtra; - memcpy( KEYITEM( pPage, 0 )->key, pKey->key,pTag->KeyLength ); - KEYITEM( pPage, 1 )->page = 0; - pPage->Changed = TRUE; - } - else - { - LPKEYINFO pKeyFromChild = hb_ntxPageKeyAdd( pTag, pPage, pKey ); - - if( pKeyFromChild ) - { - LPPAGEINFO pNewPage = hb_ntxPageNew( pTag ); - - pNewPage->uiKeys = 1; - KEYITEM( pNewPage, 0 )->rec_no = pKeyFromChild->Xtra; - KEYITEM( pNewPage, 0 )->page = pKeyFromChild->Tag; - memcpy( KEYITEM( pNewPage, 0 )->key, pKeyFromChild->key,pTag->KeyLength ); - KEYITEM( pNewPage, 1 )->page = pPage->Page; - - pNewPage->Changed = pTag->NewRoot = TRUE; - hb_ntxPageRelease( pTag,pNewPage ); - hb_ntxKeyFree( pKeyFromChild ); - } - } - hb_ntxPageRelease( pTag,pPage ); -} - -typedef struct _SWAPPAGE -{ - ULONG offset; - USHORT numAllkeys; - USHORT numReadkeys; - USHORT numkeys; - short int curkey; - char page[ 512 ]; -} SWAPPAGE; - -typedef SWAPPAGE * LPSWAPPAGE; - -typedef struct _PAGEITEM -{ - UINT32 rec_no; - char key[ 1 ]; -} PAGEITEM; - -typedef PAGEITEM * LPPAGEITEM; - -struct _SORTITEM; -typedef struct _SORTITEM -{ - struct _SORTITEM * pNext; - UINT32 rec_no; - char key[ 1 ]; -} SORTITEM; - -typedef SORTITEM * LPSORTITEM; - -typedef struct _NTXSORTINFO -{ - ULONG Tag; - ULONG ulKeyCount; - ULONG ulSqrt; - ULONG nItems; - USHORT itemLength; - USHORT nSwappages; - BYTE * sortBuffer; - LPSORTITEM pKeyFirst; - LPSORTITEM pKeyTemp; - LPSORTITEM pKey1; - LPSORTITEM pKey2; - char** pageBuffers; - BYTE* swappages; - FHANDLE tempHandle; -} NTXSORTINFO; - -typedef NTXSORTINFO * LPNTXSORTINFO; - -static void hb_ntxSwapPageSave( LPTAGINFO pTag, LPNTXSORTINFO pSortInfo, USHORT nPart ) -{ - LPSORTITEM pKey = pSortInfo->pKeyFirst; - USHORT itemLength = sizeof( UINT32 ) + pTag->KeyLength; - USHORT numKeys = 0, maxKeys = 512/itemLength, numAllkeys = 0; - LPSWAPPAGE pSwapPage = (LPSWAPPAGE) ( pSortInfo->swappages + sizeof(SWAPPAGE)*nPart ); - LPPAGEITEM ptr; - - pSwapPage->offset = hb_fsSeek( pSortInfo->tempHandle, 0, SEEK_END ); - pSwapPage->numReadkeys = pSwapPage->curkey = pSwapPage->numkeys = 0; - while( pKey ) - { - ptr = (LPPAGEITEM) ( pSwapPage->page + numKeys*itemLength ); - ptr->rec_no = pKey->rec_no; - memcpy( ptr->key, pKey->key, pTag->KeyLength ); - pKey = pKey->pNext; - numAllkeys ++; - if( ++numKeys == maxKeys || !pKey ) - { - hb_fsWrite( pSortInfo->tempHandle, (BYTE *) pSwapPage->page, - numKeys * itemLength ); - numKeys = 0; - } - } - pSwapPage->numAllkeys = numAllkeys; -} - -static void hb_ntxKeysSort( LPNTXSORTINFO pSortInfo, LPSORTITEM* pKeyFirst, LPSORTITEM pKeyNew, int KeyLength, BOOL fDescend, BOOL fUnique ) -{ - LPSORTITEM pKey, pKeyTmp, pKeyLast = NULL, pKeyPrev; - int result; - - while( pKeyNew ) - { - pKeyPrev = NULL; - pKeyTmp = pKeyNew->pNext; - pKeyNew->pNext = NULL; - - if( pKeyLast ) - { - pKeyPrev = pKeyLast; - pKey = pKeyLast->pNext; - } - else if( pSortInfo->pKey1 ) - { -#ifndef HB_CDP_SUPPORT_OFF - result = (hb_cdp_page->lSort)? - hb_cdpcmp( pKeyNew->key, pSortInfo->pKey1->key, (ULONG)KeyLength, hb_cdp_page, NULL ):memcmp( pKeyNew->key, pSortInfo->pKey1->key, KeyLength ); -#else - result = memcmp( pKeyNew->key, pSortInfo->pKey1->key, KeyLength ); -#endif - if( fDescend && result ) - result = ( result > 0 )? -1:1; - if( result >= 0 ) - { - if( !result && fUnique ) - { - pSortInfo->ulKeyCount --; - pKeyNew = pKeyTmp; - continue; - } - else - { - pKeyPrev = pSortInfo->pKey1; - pKey = pSortInfo->pKey1->pNext; - } - } - else - pKey = *pKeyFirst; - } - else - pKey = *pKeyFirst; - while( pKey ) - { -#ifndef HB_CDP_SUPPORT_OFF - result = (hb_cdp_page->lSort)? - hb_cdpcmp( pKeyNew->key, pKey->key, (ULONG)KeyLength, hb_cdp_page, NULL ):memcmp( pKeyNew->key, pKey->key, KeyLength ); -#else - result = memcmp( pKeyNew->key, pKey->key, KeyLength ); -#endif - if( fDescend && result ) - result = ( result > 0 )? -1:1; - if( result < 0 ) - { - pKeyNew->pNext = pKey; - if( pKeyPrev ) - { - pKeyPrev->pNext = pKeyNew; - pSortInfo->pKey1 = pKeyNew; - } - else - *pKeyFirst = pKeyNew; - break; - } - else if( !result && fUnique ) - { - pSortInfo->ulKeyCount --; - pKeyNew = pKeyLast; - break; - } - pKeyPrev = pKey; - pKey = pKey->pNext; - } - if( !pKey ) - { - pKeyPrev->pNext = pKeyNew; - pSortInfo->pKey1 = pKeyNew; - } - - pKeyLast = pKeyNew; - pKeyNew = pKeyTmp; - } -} - -static void hb_ntxSortKeyAdd( LPTAGINFO pTag, LPNTXSORTINFO pSortInfo, char* szkey, ULONG ulKeyNo ) -{ - LPSORTITEM pKeyNew = (LPSORTITEM) ( pSortInfo->sortBuffer + - pSortInfo->itemLength * ( ulKeyNo - 1 ) ); - pKeyNew->rec_no = pTag->Owner->Owner->ulRecNo; - pKeyNew->pNext = NULL; - memcpy( pKeyNew->key, szkey, pTag->KeyLength ); - - if( ++(pSortInfo->nItems) < 2 ) - { - pSortInfo->pKeyTemp = pKeyNew; - } - else - { - hb_ntxKeysSort( pSortInfo, &(pSortInfo->pKeyTemp), pKeyNew, pTag->KeyLength, !pTag->AscendKey, pTag->UniqueKey ); - - if( pSortInfo->nItems == pSortInfo->ulSqrt ) - { - if( !pSortInfo->pKeyFirst ) - { - pSortInfo->pKeyFirst = pSortInfo->pKeyTemp; - pSortInfo->pKey2 = pSortInfo->pKey1; - } - else - { - pSortInfo->pKey1 = pSortInfo->pKey2; - hb_ntxKeysSort( pSortInfo, &(pSortInfo->pKeyFirst), pSortInfo->pKeyTemp, pTag->KeyLength, !pTag->AscendKey, pTag->UniqueKey ); - pSortInfo->pKey2 = pSortInfo->pKey1; - } - pSortInfo->nItems = 0; - } - } /* - { - int i = 0; - char ctmp[30]; - ctmp[ pTag->KeyLength ] = 0; - printf( "\n\r------------------" ); - for( pKey = pSortInfo->pKeyFirst; pKey ; pKey = pKey->pNext,i++ ) - { - memcpy( ctmp,pKey->key,pTag->KeyLength ); - printf( "\n\r%d %s",i,ctmp ); - } - } -*/ -} - -static void hb_ntxSortKeyEnd( LPTAGINFO pTag, LPNTXSORTINFO pSortInfo ) + * add given page to list of free pages + */ +static void hb_ntxPageAddFree( LPTAGINFO pTag, ULONG ulPage ) { - if( pSortInfo->nItems ) - { - if( !pSortInfo->pKeyFirst ) - pSortInfo->pKeyFirst = pSortInfo->pKeyTemp; - else - { - pSortInfo->pKey1 = pSortInfo->pKey2; - hb_ntxKeysSort( pSortInfo, &(pSortInfo->pKeyFirst), pSortInfo->pKeyTemp, pTag->KeyLength, !pTag->AscendKey, pTag->UniqueKey ); - } - pSortInfo->nItems = 0; - } + LPPAGEINFO pPage = hb_ntxPageGetBuffer( pTag, ulPage ); + pPage->Changed = TRUE; + hb_ntxPageInit( pTag, pPage ); + hb_ntxPageFree( pTag, pPage ); + hb_ntxPageSave( pTag->Owner, pPage ); + hb_ntxPageRelease( pTag, pPage ); } -static void hb_ntxWritePage( LPTAGINFO pTag, LPNTXSORTINFO pSortInfo, char* buffer ) +/* + * get free page in index file + */ +static ULONG hb_ntxPageGetFree( LPTAGINFO pTag ) { - pSortInfo->Tag += NTXBLOCKSIZE; - if( pTag->Memory ) + LPPAGEINFO pPage = hb_ntxPageNew( pTag, FALSE ); + ULONG ulPage = 0; + + if( pPage ) { - ULONG ul = pSortInfo->Tag/NTXBLOCKSIZE-1; - /* printf( "\nhb_ntxWritePage-1 %d",ul ); */ - pTag->pages[ul].Page = pSortInfo->Tag; - pTag->pages[ul].uiKeys = (( LPNTXBUFFER )buffer)->item_count; - memcpy( pTag->pages[ul].buffer, buffer, NTXBLOCKSIZE ); - /* printf( "\nhb_ntxWritePage-1A" ); */ - } - else - { - hb_fsWrite( pTag->Owner->DiskFile, (BYTE *) buffer, NTXBLOCKSIZE ); - pTag->Owner->fFlush = TRUE; + ulPage = pPage->Page; + pPage->Changed = FALSE; + hb_ntxPageRelease( pTag, pPage ); } + return ulPage; } -static void hb_ntxRootPage( LPTAGINFO pTag, LPNTXSORTINFO pSortInfo, LPSORTITEM pKey, ULONG* lpArray, USHORT level ) -{ - USHORT i, maxKeys = ( USHORT ) lpArray[level+1]; - LPNTXBUFFER itemlist; - LPNTXITEM item; - - /* printf( "\nhb_ntxRootPage-0 %d %d %d %x",lpArray[0],level,maxKeys,(ULONG)pKey ); */ - if( level == (USHORT) lpArray[0] ) - return; - if( !pSortInfo->pageBuffers[ level ] ) - { - if( !pKey ) - return; - pSortInfo->pageBuffers[ level ] = (char*) hb_xgrab( NTXBLOCKSIZE ); - memset( pSortInfo->pageBuffers[ level ], 0, NTXBLOCKSIZE ); - itemlist = ( LPNTXBUFFER ) pSortInfo->pageBuffers[ level ]; - for( i = 0; i < pTag->MaxKeys+1; i++ ) - itemlist->item_offset[i] = 2 + 2 * ( pTag->MaxKeys + 1 ) + - i * ( pTag->KeyLength + 8 ); - } - else - itemlist = ( LPNTXBUFFER ) pSortInfo->pageBuffers[ level ]; - item = (NTXITEM *)( pSortInfo->pageBuffers[ level ] + itemlist->item_offset[itemlist->item_count] ); - item->page = pSortInfo->Tag; - if( itemlist->item_count < maxKeys && pKey ) - { - item->rec_no = pKey->rec_no; - memcpy( item->key, pKey->key, pTag->KeyLength ); - itemlist->item_count++; - } - else - { - if( pKey || itemlist->item_count > 0 ) - { - hb_ntxWritePage( pTag, pSortInfo, pSortInfo->pageBuffers[ level ] ); - itemlist->item_count = 0; - memset( pSortInfo->pageBuffers[ level ] + 4 + 2 * ( pTag->MaxKeys + 1 ), - 0, NTXBLOCKSIZE - 6 - 2 * ( pTag->MaxKeys + 1 ) ); - } - if( !pKey ) - pTag->RootBlock = pSortInfo->Tag; - hb_ntxRootPage( pTag, pSortInfo, pKey, lpArray, level+1 ); - } -} - -static BOOL hb_ntxGetSortedKey( LPTAGINFO pTag, LPNTXSORTINFO pSortInfo, LPSORTITEM* ppKey, LPSORTITEM pKeyRoot ) -{ - char *key1, *key2; - short int nPage, iPage; - int result = 0; /* TODO: It's something wrong here, result was - not initialized. I forced initialization - but this code should be cleaned. Alex please do - that. Best regards, Przemek. - */ - BOOL fDescend = !pTag->AscendKey; - USHORT itemLength = sizeof( UINT32 ) + pTag->KeyLength; - LPSORTITEM pKey = *ppKey; - LPSWAPPAGE pSwapPage = (LPSWAPPAGE) ( pSortInfo->swappages ); - - if( pSwapPage->curkey >= 0 ) - key1 = ( (LPPAGEITEM) ( pSwapPage->page + - itemLength*pSwapPage->curkey ) )->key; - else - key1 = NULL; - nPage = 0; - for( iPage=1;iPagenSwappages;iPage++ ) - { - pSwapPage = (LPSWAPPAGE) ( pSortInfo->swappages + sizeof(SWAPPAGE)*iPage ); - if( pSwapPage->curkey >= 0 ) - { - key2 = ( (LPPAGEITEM) ( pSwapPage->page + - itemLength*pSwapPage->curkey ) )->key; - if( key1 ) - { - result = memcmp( (BYTE*)key1,(BYTE*)key2,pTag->KeyLength ); - if( fDescend && result ) - result = ( result > 0 )? -1:1; - } - if( !key1 || result > 0 ) - { - nPage = iPage; - key1 = key2; - } - } - } - if( pKey && key1 ) - { - result = memcmp( (BYTE*)key1,(BYTE*)pKey->key,pTag->KeyLength ); - if( fDescend && result ) - result = ( result > 0 )? -1:1; - } - if( ( pKey && !key1 ) || ( pKey && result > 0 ) ) - { - pKeyRoot->rec_no = pKey->rec_no; - memcpy( pKeyRoot->key, pKey->key, pTag->KeyLength ); - *ppKey = pKey->pNext; - /* printf( "\nSortedKey - 1 %d %c%c%c%c%c%c",*rec_no,key1[0],key1[1],key1[2],key1[3],key1[4],key1[5] ); */ - } - else if( key1 ) - { - LPSWAPPAGE pSwapPage = (LPSWAPPAGE) ( pSortInfo->swappages + sizeof(SWAPPAGE)*nPage ); - - pKeyRoot->rec_no = ( (LPPAGEITEM) ( pSwapPage->page + - itemLength*pSwapPage->curkey ) )->rec_no; - memcpy( pKeyRoot->key, key1, pTag->KeyLength ); - /* printf( "\nSortedKey - 2 %d %d %c%c%c%c%c%c",nPage,*rec_no,key1[0],key1[1],key1[2],key1[3],key1[4],key1[5] ); */ - if( ++(pSwapPage->curkey) == pSwapPage->numkeys ) - { - USHORT pageItemLength = sizeof( UINT32 ) + pTag->KeyLength; - USHORT maxKeys = 512/pageItemLength, nRead; - - if( pSwapPage->numReadkeys >= pSwapPage->numAllkeys ) - pSwapPage->curkey = -1; - else - { - hb_fsSeek( pSortInfo->tempHandle, pSwapPage->offset + - pageItemLength*pSwapPage->numReadkeys , SEEK_SET ); - nRead = hb_fsRead( pSortInfo->tempHandle, (BYTE*)pSwapPage->page, - ( (pSwapPage->numAllkeys-pSwapPage->numReadkeys < maxKeys)? - pSwapPage->numAllkeys-pSwapPage->numReadkeys:maxKeys ) * pageItemLength ); - pSwapPage->numkeys = nRead/pageItemLength; - pSwapPage->numReadkeys += nRead/pageItemLength; - pSwapPage->curkey = 0; - } - } - /* printf( "\nSortedKey - 3 %d %d %c%c%c%c%c%c",nPage,*rec_no,key1[0],key1[1],key1[2],key1[3],key1[4],key1[5] ); */ - } - else - return FALSE; - return TRUE; -} - -static void hb_ntxBufferSave( LPTAGINFO pTag, LPNTXSORTINFO pSortInfo ) -{ - USHORT i, maxKeys; - LPNTXBUFFER itemlist; - LPNTXITEM item; - ULONG numKey = 0, ulFullNodes; - LPSORTITEM pKey = pSortInfo->pKeyFirst; - char* buffer; - BOOL lSave = FALSE; - ULONG* lpArray = hb_ntxKeysInPage( pSortInfo->ulKeyCount, pTag->MaxKeys-1 ); - - maxKeys = (USHORT)lpArray[1]; - ulFullNodes = lpArray[lpArray[0]+1]; - if( pTag->Memory ) - { - ULONG ul; - pTag->ulPagesStart = 1; - for( ul=lpArray[0];ul>1;ul-- ) - pTag->ulPagesStart += (lpArray[ul]+1) * ( (ul==lpArray[0])? 1:(lpArray[ul+1]+1) ); - - pTag->ulPagesDepth = pTag->ulPagesStart; - pTag->pages = (LPPAGEINFO) hb_xgrab( sizeof(HB_PAGEINFO)*pTag->ulPagesStart ); - memset( pTag->pages , 0 ,sizeof( HB_PAGEINFO )*pTag->ulPagesStart ); - - pTag->pages[0].buffer = (char*) hb_xgrab( pTag->ulPagesStart*NTXBLOCKSIZE ); - for( ul=1; ululPagesStart; ul++ ) - pTag->pages[ul].buffer = pTag->pages[0].buffer + ul*NTXBLOCKSIZE; - } - else - { - hb_fsSeek( pTag->Owner->DiskFile, 1024, FS_SET ); - } - pSortInfo->Tag = 0; - pSortInfo->pageBuffers = (char**) hb_xgrab( sizeof( char* ) * lpArray[0] ); - for( i = 0; i < (USHORT)lpArray[0]; i++ ) - { - pSortInfo->pageBuffers[i] = NULL; - } - pSortInfo->pageBuffers[0] = (char*) hb_xgrab( NTXBLOCKSIZE ); - memset( pSortInfo->pageBuffers[0], 0, NTXBLOCKSIZE ); - itemlist = ( LPNTXBUFFER ) pSortInfo->pageBuffers[0]; - for( i = 0; i < pTag->MaxKeys+1; i++ ) - { - itemlist->item_offset[i] = 2 + 2 * ( pTag->MaxKeys + 1 ) + - i * ( pTag->KeyLength + 8 ); - } - buffer = pSortInfo->pageBuffers[0]; - - if( !pKey ) - { - itemlist->item_count = 0; - hb_ntxWritePage( pTag, pSortInfo, buffer ); - } - - /* printf( "\nhb_ntxBufferSave - 1 ( maxKeys=%d )",maxKeys ); */ - if( pSortInfo->nSwappages > 1 ) - { - BOOL lKeys = FALSE; - LPSORTITEM pKeyRoot = (LPSORTITEM) hb_xgrab( pSortInfo->itemLength ); - USHORT pageItemLength = sizeof( UINT32 ) + pTag->KeyLength; - USHORT maxKeysSwapPage = 512/pageItemLength, nRead; - LPSWAPPAGE pSwapPage; - - for( i = 0; i < pSortInfo->nSwappages; i++ ) - { - pSwapPage = (LPSWAPPAGE) ( pSortInfo->swappages + sizeof(SWAPPAGE)*i ); - hb_fsSeek( pSortInfo->tempHandle, pSwapPage->offset, SEEK_SET ); - nRead = hb_fsRead( pSortInfo->tempHandle, (BYTE*)pSwapPage->page, - ( (pSwapPage->numAllkeys-pSwapPage->numReadkeys < maxKeysSwapPage)? - pSwapPage->numAllkeys-pSwapPage->numReadkeys:maxKeysSwapPage ) * pageItemLength ); - pSwapPage->numkeys = nRead/pageItemLength; - pSwapPage->numReadkeys = nRead/pageItemLength; - pSwapPage->curkey = 0; - } - - do - { - /* for( i = 0; i < maxKeys; i++ ) */ - for( i = 0; i < maxKeys || numKey == pSortInfo->ulKeyCount-1; i++ ) - { - lKeys = hb_ntxGetSortedKey( pTag, pSortInfo, &pKey, pKeyRoot ); - if( !lKeys ) - break; - numKey++; - item = (NTXITEM *)( buffer + itemlist->item_offset[i] ); - item->page = 0; - item->rec_no = pKeyRoot->rec_no; - memcpy( item->key, pKeyRoot->key, pTag->KeyLength ); - } - itemlist->item_count = i; - - if( itemlist->item_count ) - { - hb_ntxWritePage( pTag, pSortInfo, buffer ); - lKeys = hb_ntxGetSortedKey( pTag, pSortInfo, &pKey, pKeyRoot ); - if( lKeys ) - { - hb_ntxRootPage( pTag, pSortInfo, pKeyRoot, lpArray, 1 ); - numKey++; - } - else - hb_ntxRootPage( pTag, pSortInfo, NULL, lpArray, 1 ); - if( ulFullNodes ) - { - ulFullNodes --; - if( !ulFullNodes ) - maxKeys --; - } - } - } - while( lKeys ); - hb_xfree( pKeyRoot ); - } - else - { - while( pKey ) - { - for( i = 0; ( i < maxKeys || numKey == pSortInfo->ulKeyCount-1 ) && pKey; i++, numKey++, pKey = pKey->pNext ) - { - /* printf( "\nhb_ntxBufferSave - 2 ( i=%d maxKeys=%d )",i,maxKeys ); */ - item = (NTXITEM *)( buffer + itemlist->item_offset[i] ); - item->page = 0; - item->rec_no = pKey->rec_no; - memcpy( item->key, pKey->key, pTag->KeyLength ); - } - itemlist->item_count = i; - - if( itemlist->item_count ) - { - hb_ntxWritePage( pTag, pSortInfo, buffer ); - } - /* printf( "\nhb_ntxBufferSave - 5 ( numKey=%d )",numKey ); */ - hb_ntxRootPage( pTag, pSortInfo, pKey, lpArray, 1 ); - if( ulFullNodes ) - { - ulFullNodes --; - if( !ulFullNodes ) - maxKeys --; - } - if( pKey ) - { - numKey ++; - pKey = pKey->pNext; - } - } - } - hb_xfree( pSortInfo->pageBuffers[ 0 ] ); - for( i = 1; i < (USHORT)lpArray[0]; i++ ) - if( pSortInfo->pageBuffers[ i ] ) - { - itemlist = ( LPNTXBUFFER ) pSortInfo->pageBuffers[ i ]; - if( itemlist->item_count ) - { - if( lSave ) - { - item = (NTXITEM *)( pSortInfo->pageBuffers[ i ] + itemlist->item_offset[itemlist->item_count] ); - item->page = pSortInfo->Tag; - } - lSave = TRUE; - hb_ntxWritePage( pTag, pSortInfo, pSortInfo->pageBuffers[ i ] ); - pTag->RootBlock = pSortInfo->Tag; - } - hb_xfree( pSortInfo->pageBuffers[ i ] ); - } - hb_xfree( pSortInfo->pageBuffers ); - hb_xfree( lpArray ); - if( !pTag->RootBlock ) - pTag->RootBlock = 1024; -} - -static BOOL hb_ntxReadBuf( NTXAREAP pArea, BYTE* readBuffer, SHORT* numRecinBuf, LPDBORDERCONDINFO lpdbOrdCondInfo, ULONG ulRecNo ) -{ - if( *numRecinBuf >= 0 ) - { - if( *numRecinBuf == 10 ) - *numRecinBuf = 0; - if( *numRecinBuf == 0 ) - { - ULONG ulBufLen = pArea->uiRecordLen * 10; - hb_fsSeekLarge( pArea->hDataFile, - ( HB_FOFFSET ) pArea->uiHeaderLen + - ( HB_FOFFSET ) pArea->uiRecordLen * - ( HB_FOFFSET ) ( ulRecNo - 1 ), FS_SET ); - hb_fsReadLarge( pArea->hDataFile, readBuffer, ulBufLen ); - } - pArea->pRecord = readBuffer + (*numRecinBuf) * pArea->uiRecordLen; - pArea->fDeleted = ( pArea->pRecord[ 0 ] == '*' ); - pArea->ulRecNo = ulRecNo; - (*numRecinBuf) ++; - return TRUE; - } - else if( lpdbOrdCondInfo ) - { - if( lpdbOrdCondInfo->lNextCount < 0 ) - return FALSE; - if( lpdbOrdCondInfo->lRecno ) - { - lpdbOrdCondInfo->lNextCount = -1; - return TRUE; - } - if( lpdbOrdCondInfo->lNextCount > 0 ) - { - lpdbOrdCondInfo->lNextCount --; - if( !lpdbOrdCondInfo->lNextCount ) - lpdbOrdCondInfo->lNextCount --; - return TRUE; - } - if( lpdbOrdCondInfo->itmCobWhile ) - return checkLogicalExpr( lpdbOrdCondInfo->itmCobWhile, NULL ); - if( lpdbOrdCondInfo->fUseCurrent && pArea->fEof ) - return FALSE; - - return TRUE; - } - return TRUE; -} - -static ERRCODE hb_ntxIndexCreate( LPNTXINDEX pIndex ) -{ - ULONG ulRecNo, ulRecCount, ulKeyNo = 0, lStep = 0, ulRecMax; - USHORT uiCurLen; - char szBuffer[ NTX_MAX_KEY ]; - char * pszTempName = NULL; - NTXAREAP pArea = pIndex->Owner; - LPTAGINFO pTag; - HB_MACRO_PTR pMacro; - PHB_ITEM pItem; - BOOL bWhileOk; - NTXSORTINFO sortInfo; - BYTE* readBuffer; - SHORT numRecinBuf = -1; - USHORT nParts = 0; - BYTE * pRecordTmp = NULL; - BOOL fValidBuffer = FALSE; - LPTAGINFO pSaveTag = pArea->lpCurTag; -#ifndef HB_CDP_SUPPORT_OFF - PHB_CODEPAGE cdpTmp = hb_cdp_page; - hb_cdp_page = pArea->cdPage; -#endif - - ulRecCount = pArea->ulRecCount; - pTag = pIndex->CompoundTag; - pItem = hb_itemNew( NULL ); - - memset( &sortInfo, 0, sizeof( sortInfo ) ); - readBuffer = (BYTE*) hb_xgrab( pArea->uiRecordLen * 10 ); - /* itemLength = sizeof( LPSORTITEM ) + sizeof( ULONG ) + pTag->KeyLength; */ - sortInfo.itemLength = sizeof( LPSORTITEM ) + sizeof( UINT32 ) + pTag->KeyLength; - sortInfo.nItems = 0; - sortInfo.pKey1 = sortInfo.pKey2 = sortInfo.pKeyFirst = sortInfo.pKeyTemp = NULL; - if( pArea->lpdbOrdCondInfo && pArea->lpdbOrdCondInfo->fCustom ) - ulRecCount = 0; - ulRecMax = ulRecCount; - if( ulRecCount ) - { - sortInfo.sortBuffer = (BYTE*) hb_xalloc( ulRecCount * sortInfo.itemLength ); - if( !sortInfo.sortBuffer ) - { - /* If there isn't memory enough for the sortBuffer, we need to - create a buffer of less size and use swapping */ - do - { - nParts = (nParts)? nParts*2:2; - sortInfo.sortBuffer = (BYTE*) hb_xalloc( - (ulRecCount/nParts+1) * sortInfo.itemLength ); - if( sortInfo.sortBuffer ) - sortInfo.swappages = (BYTE*) hb_xalloc( nParts * sizeof( SWAPPAGE ) ); - if( !sortInfo.swappages ) - { - hb_xfree( sortInfo.sortBuffer ); - sortInfo.sortBuffer = NULL; - } - } - while( !sortInfo.sortBuffer && nParts < 200 ); - if( !sortInfo.sortBuffer ) - hb_errInternal( HB_EI_ERRUNRECOV, "Not enough room for index buffer", "hb_ntxIndexCreate", NULL ); - sortInfo.nSwappages = nParts - 1; - ulRecMax = ulRecCount/nParts+1; - /* printf( "\nnParts=%d ulRecMax=%d",nParts,ulRecMax ); */ - nParts = 1; - } - sortInfo.ulSqrt = (ulRecMax>50)? (ULONG)floor( sqrt( ( double) ulRecMax ) ):ulRecMax; - } - else - sortInfo.sortBuffer = NULL; - - if( !hb_set.HB_SET_STRICTREAD && !pArea->lpdbRelations && - ( !pArea->lpdbOrdCondInfo || pArea->lpdbOrdCondInfo->fAll ) ) - { - pRecordTmp = pArea->pRecord; - fValidBuffer = pArea->fValidBuffer; - pArea->fValidBuffer = TRUE; - numRecinBuf = 0; - } - else - { - if ( !pArea->lpdbOrdCondInfo || pArea->lpdbOrdCondInfo->fAll ) - { - pArea->lpCurTag = NULL; - SELF_GOTOP( ( AREAP ) pArea ); - } - else if ( pArea->lpdbOrdCondInfo->lRecno ) - { - SELF_GOTO( ( AREAP ) pArea, pArea->lpdbOrdCondInfo->lRecno ); - } - else if ( pArea->lpdbOrdCondInfo->fUseCurrent ) - { - if ( pArea->lpdbOrdCondInfo->lStartRecno ) - { - SELF_GOTO( ( AREAP ) pArea, pArea->lpdbOrdCondInfo->lStartRecno ); - } - else - { - SELF_GOTOP( ( AREAP ) pArea ); - } - } - else if ( pArea->lpdbOrdCondInfo->fRest || pArea->lpdbOrdCondInfo->lNextCount ) - { - if ( pArea->lpdbOrdCondInfo->lStartRecno ) - { - SELF_GOTO( ( AREAP ) pArea, pArea->lpdbOrdCondInfo->lStartRecno ); - } - } - else - { - pArea->lpCurTag = NULL; - SELF_GOTOP( ( AREAP ) pArea ); - } - } - - bWhileOk = TRUE; - for( ulRecNo = 1; ulRecNo <= ulRecCount; ulRecNo++) - { - if( !hb_ntxReadBuf( pArea, readBuffer, &numRecinBuf, pArea->lpdbOrdCondInfo, ulRecNo ) ) - break; - if( pTag->pForItem != NULL ) - bWhileOk = checkLogicalExpr( pTag->pForItem, pItem ); - if( bWhileOk ) - { - ulKeyNo ++; - sortInfo.ulKeyCount ++; - if( sortInfo.nSwappages && ulKeyNo > ulRecMax ) - { - if( nParts == 1 ) - { - BYTE szTempName[ _POSIX_PATH_MAX + 1 ]; - sortInfo.tempHandle = hb_fsCreateTemp( NULL, NULL, FC_NORMAL, szTempName ); - if( sortInfo.tempHandle == FS_ERROR ) - hb_errInternal( HB_EI_ERRUNRECOV, "Cannot create temp file", "hb_ntxIndexCreate", NULL ); - pszTempName = hb_strdup( ( const char * ) szTempName ); - } - hb_ntxSortKeyEnd( pTag, &sortInfo ); - hb_ntxSwapPageSave( pTag, &sortInfo, nParts-1 ); - sortInfo.nItems = 0; - sortInfo.pKey1 = sortInfo.pKey2 = sortInfo.pKeyFirst = sortInfo.pKeyTemp = NULL; - ulKeyNo = 1; - nParts ++; - } - if( pTag->nField ) - { - /* printf( "\nIndexCreate-1 %d",pTag->nField ); */ - SELF_GETVALUE( ( AREAP ) pArea, pTag->nField, pItem ); - } - else if( hb_itemType( pTag->pKeyItem ) == HB_IT_BLOCK ) - { - hb_vmPushSymbol( &hb_symEval ); - hb_vmPush( pTag->pKeyItem ); - hb_vmSend( 0 ); - hb_itemCopy( pItem, hb_stackReturnItem() ); - } - else - { - pMacro = ( HB_MACRO_PTR ) hb_itemGetPtr( pTag->pKeyItem ); - hb_macroRun( pMacro ); - hb_itemCopy( pItem, hb_stackItemFromTop( - 1 ) ); - hb_stackPop(); - } - switch( hb_itemType( pItem ) ) - { - case HB_IT_STRING: - uiCurLen = (USHORT) pItem->item.asString.length; - if(uiCurLen > NTX_MAX_KEY ) - uiCurLen = NTX_MAX_KEY ; - if( pTag->KeyLength != uiCurLen ) - { - hb_itemRelease( pItem ); - return FAILURE; - } - hb_ntxSortKeyAdd( pTag, &sortInfo, pItem->item.asString.value, ulKeyNo ); - break; - case HB_IT_INTEGER: - case HB_IT_LONG: - case HB_IT_DOUBLE: - numToStr( pItem, szBuffer, pTag->KeyLength, pTag->KeyDec ); - hb_ntxSortKeyAdd( pTag, &sortInfo,szBuffer, ulKeyNo ); - break; - case HB_IT_DATE: - hb_itemGetDS( pItem, szBuffer ); - hb_ntxSortKeyAdd( pTag, &sortInfo, szBuffer, ulKeyNo ); - break; - case HB_IT_LOGICAL: - szBuffer[0] = ( hb_itemGetL( pItem ) ? 'T' : 'F' ); - szBuffer[1] = 0; - hb_ntxSortKeyAdd( pTag, &sortInfo, szBuffer, ulKeyNo ); - break; - default: - printf( "ntxCreateOrder" ); - } - } - if( pArea->lpdbOrdCondInfo ) - { - if( pArea->lpdbOrdCondInfo->lStep ) - { - lStep ++; - if( lStep == (ULONG) pArea->lpdbOrdCondInfo->lStep ) - lStep = 0; - } - if( pArea->lpdbOrdCondInfo->itmCobEval && !lStep ) - { - hb_vmPushSymbol( &hb_symEval ); - hb_vmPush( pArea->lpdbOrdCondInfo->itmCobEval ); - hb_vmSend( 0 ); - if( ! hb_itemGetL( hb_stackReturnItem() ) ) - break; - } - } - if( numRecinBuf < 0 ) - SELF_SKIP( ( AREAP ) pArea, 1 ); - } - hb_ntxSortKeyEnd( pTag, &sortInfo ); - if( numRecinBuf >= 0 ) - { - pArea->pRecord = pRecordTmp; - pArea->fValidBuffer = fValidBuffer; - } - pArea->lpCurTag = pSaveTag; - - if( sortInfo.nSwappages ) - sortInfo.nSwappages = nParts - 1; - - /* Building index file with previously sorted keys */ - hb_ntxBufferSave( pTag, &sortInfo ); - -#ifndef HB_CDP_SUPPORT_OFF - hb_cdp_page = cdpTmp; -#endif - if( pszTempName ) - { /* Close temporary swap file, delete it and free name buffer */ - hb_fsClose( sortInfo.tempHandle ); - hb_fsDelete( (BYTE*) pszTempName ); - hb_xfree( pszTempName ); - } - if( sortInfo.swappages ) - hb_xfree( sortInfo.swappages ); - if( sortInfo.sortBuffer ) - hb_xfree( sortInfo.sortBuffer ); - hb_xfree( readBuffer ); - hb_itemRelease( pItem ); - return SUCCESS; -} - -static void hb_ntxHeaderSave( LPNTXINDEX pIndex, BOOL bFull ) -{ - NTXHEADER Header; - - if( pIndex->CompoundTag->Memory ) - return; - hb_fsSeek( pIndex->DiskFile , 0 , 0 ); - memset( (void*) &Header, 0, sizeof( NTXHEADER ) ); - Header.type = 0x06 | ( pIndex->CompoundTag->ForExpr ? 0x01 : 0x00 ) | - ( pIndex->Owner->bLockType == HB_SET_DBFLOCK_CL53 ? 0x20 : 0 ); - Header.version = 1; - Header.root = pIndex->CompoundTag->RootBlock; - Header.next_page = pIndex->NextAvail; - Header.item_size = pIndex->CompoundTag->KeyLength+8; - Header.key_size = pIndex->CompoundTag->KeyLength; - Header.key_dec = pIndex->CompoundTag->KeyDec; - - if( bFull ) - { - Header.max_item = pIndex->CompoundTag->MaxKeys; - Header.half_page = Header.max_item/2; - strcpy( Header.key_expr , pIndex->CompoundTag->KeyExpr ); - if( pIndex->CompoundTag->ForExpr ) - strcpy( Header.for_expr , pIndex->CompoundTag->ForExpr ); - if( pIndex->CompoundTag->fTagName ) - strncpy( Header.tag_name , pIndex->CompoundTag->TagName, NTX_MAX_TAGNAME ); - - Header.unique = pIndex->CompoundTag->UniqueKey; - Header.descend = !pIndex->CompoundTag->AscendKey; - Header.custom = pIndex->CompoundTag->Custom; - hb_fsWrite( pIndex->DiskFile,(BYTE*)&Header,sizeof(NTXHEADER) ); - memset( (BYTE*)&Header, 0, NTXBLOCKSIZE-sizeof(NTXHEADER) ); - hb_fsWrite( pIndex->DiskFile, (BYTE*)&Header, NTXBLOCKSIZE-sizeof(NTXHEADER) ); - } - else - hb_fsWrite( pIndex->DiskFile,(BYTE*)&Header,16 ); - - pIndex->fFlush = TRUE; -} - -static LPTAGINFO hb_ntxTagNew( LPNTXINDEX PIF, char * ITN, BOOL fTagName, char *szKeyExpr, - PHB_ITEM pKeyExpr, BYTE bKeyType, USHORT uiKeyLen, USHORT uiKeyDec, - char *szForExp, PHB_ITEM pForExp, BOOL fAscendKey, BOOL fUnique, - BOOL fCustom, BOOL fMemory ) +/* + * create the new tag structure + */ +static LPTAGINFO hb_ntxTagNew( LPNTXINDEX pIndex, + char * szTagName, BOOL fTagName, + char *szKeyExpr, PHB_ITEM pKeyExpr, + BYTE bKeyType, USHORT uiKeyLen, USHORT uiKeyDec, + char *szForExpr, PHB_ITEM pForExpr, + BOOL fAscendKey, BOOL fUnique, BOOL fCustom, + BOOL fSortRec ) { LPTAGINFO pTag; pTag = ( LPTAGINFO ) hb_xgrab( sizeof( TAGINFO ) ); memset( pTag, 0, sizeof( TAGINFO ) ); - pTag->TagName = ITN; + pTag->TagName = hb_strndup( szTagName, NTX_MAX_TAGNAME ); pTag->fTagName = fTagName; - pTag->Owner = PIF; + pTag->Owner = pIndex; if( szKeyExpr ) { - pTag->KeyExpr = (char *) hb_xgrab( NTX_MAX_KEY ); - strcpy( pTag->KeyExpr, szKeyExpr ); + pTag->KeyExpr = hb_strndup( szKeyExpr, NTX_MAX_EXP ); } - if( szForExp ) + if( pForExpr && szForExpr ) { - pTag->ForExpr = (char *) hb_xgrab( NTX_MAX_KEY ); - strcpy( pTag->ForExpr, szForExp ); + pTag->ForExpr = hb_strndup( szForExpr, NTX_MAX_EXP ); } - pTag->nField = hb_rddFieldIndex( (AREAP) pTag->Owner->Owner, - hb_strUpper(pTag->KeyExpr,strlen(pTag->KeyExpr)) ); + pTag->nField = hb_rddFieldExpIndex( ( AREAP ) pIndex->Owner, pTag->KeyExpr ); pTag->pKeyItem = pKeyExpr; - pTag->pForItem = pForExp; + pTag->pForItem = pForExpr; pTag->AscendKey = fAscendKey; + pTag->fUsrDescend = !pTag->AscendKey; pTag->UniqueKey = fUnique; pTag->Custom = fCustom; + pTag->MultiKey = fCustom && s_fMultiKey; pTag->KeyType = bKeyType; pTag->KeyLength = uiKeyLen; pTag->KeyDec = uiKeyDec; - /* Please check me - it was: (NTXBLOCKSIZE-6)/(uiKeyLen+10) - 1 */ - pTag->MaxKeys = (NTXBLOCKSIZE-3)/(uiKeyLen+10) - 1; - if( pTag->MaxKeys%2 && pTag->MaxKeys>2 ) + pTag->fSortRec = fSortRec; + /* + * TODO?: keep during page update the offset to 'MaxKeys' key fixed + * so we will be able to store 1 key more in the page + */ + pTag->MaxKeys = ( NTXBLOCKSIZE - 2 ) / ( uiKeyLen + 10 ) - 1; + + /* TODO?: is it necessary? It should not interact with well implemented + algorithm */ + if( pTag->MaxKeys & 0x01 && pTag->MaxKeys > 2 ) pTag->MaxKeys--; - pTag->CurKeyInfo = hb_ntxKeyNew( NULL,pTag->KeyLength ); - pTag->stack = (LPTREESTACK) hb_xgrab( sizeof(TREE_STACK) * 32 ); - pTag->stackDepth = 32; - pTag->ulPages = 0; - pTag->ulPagesDepth = NTX_PAGES_PER_TAG; - if( !fMemory ) - { - pTag->pages = (LPPAGEINFO) hb_xgrab( sizeof(HB_PAGEINFO)*NTX_PAGES_PER_TAG ); - memset( pTag->pages , 0 ,sizeof( HB_PAGEINFO )*NTX_PAGES_PER_TAG ); - } - pTag->Memory = fMemory; - pTag->TagRoot = 1; + + pTag->CurKeyInfo = hb_ntxKeyNew( NULL, pTag->KeyLength ); + return pTag; } +/* + * free from memory tag structure + */ +static void hb_ntxTagFree( LPTAGINFO pTag ) +{ + if( pTag == pTag->Owner->Owner->lpCurTag ) + pTag->Owner->Owner->lpCurTag = NULL; + hb_xfree( pTag->TagName ); + if( pTag->KeyExpr ) + hb_xfree( pTag->KeyExpr ); + if( pTag->ForExpr ) + hb_xfree( pTag->ForExpr ); + if( pTag->pKeyItem ) + hb_ntxDestroyExp( pTag->pKeyItem ); + if( pTag->pForItem ) + hb_ntxDestroyExp( pTag->pForItem ); + if( pTag->HotKeyInfo ) + hb_ntxKeyFree( pTag->HotKeyInfo ); + hb_ntxKeyFree( pTag->CurKeyInfo ); + hb_ntxTagClearScope( pTag, 0 ); + hb_ntxTagClearScope( pTag, 1 ); + if( pTag->stack ) + hb_xfree( pTag->stack ); + hb_xfree( pTag ); +} + +/* + * delete tag from compund index + */ +static void hb_ntxTagDelete( LPTAGINFO pTag ) +{ + LPNTXINDEX pIndex = pTag->Owner; + int i; + + for( i = 0; i < pIndex->iTags; i++ ) + { + if( pTag == pIndex->lpTags[ i ] ) + { + while( ++i < pIndex->iTags ) + pIndex->lpTags[ i - 1 ] = pIndex->lpTags[ i ]; + if( --pIndex->iTags ) + pIndex->lpTags = ( LPTAGINFO * ) hb_xrealloc( pIndex->lpTags, + sizeof( LPTAGINFO ) * pIndex->iTags ); + else + hb_xfree( pIndex->lpTags ); + break; + } + } + hb_ntxTagFree( pTag ); + pIndex->Owner->fSetTagNumbers = TRUE; + return; +} + +/* + * add tag to compund index + */ +static ERRCODE hb_ntxTagAdd( LPNTXINDEX pIndex, LPTAGINFO pTag ) +{ + if( pIndex->iTags >= CTX_MAX_TAGS ) + return FAILURE; + + if( pIndex->iTags ) + pIndex->lpTags = ( LPTAGINFO * ) hb_xrealloc( pIndex->lpTags, + sizeof( LPTAGINFO ) * ( pIndex->iTags + 1 ) ); + else + pIndex->lpTags = ( LPTAGINFO * ) hb_xgrab( sizeof( LPTAGINFO ) ); + + pIndex->lpTags[ pIndex->iTags++ ] = pTag; + pIndex->Owner->fSetTagNumbers = TRUE; + return SUCCESS; +} + +/* + * create new tag and load it from index file + */ +static LPTAGINFO hb_ntxTagLoad( LPNTXINDEX pIndex, ULONG ulBlock, + char * szTagName, BYTE * buffer ) +{ + LPNTXHEADER lpNTX = ( LPNTXHEADER ) buffer; + LPTAGINFO pTag; + PHB_ITEM pKeyExp, pForExp = NULL; + USHORT usType; + BOOL fName; + + usType = HB_GET_LE_UINT16( lpNTX->type ); + + if( ( usType & ~NTX_FLAG_MASK ) || + ( ( usType & NTX_FLAG_DEFALUT ) != NTX_FLAG_DEFALUT && + usType != NTX_FLAG_OLDDEFALUT ) || + lpNTX->key_expr[0] < 0x20 ) + return NULL; + + if( SELF_COMPILE( ( AREAP ) pIndex->Owner, lpNTX->key_expr ) == FAILURE ) + return NULL; + pKeyExp = pIndex->Owner->valResult; + pIndex->Owner->valResult = NULL; + + if( usType & NTX_FLAG_FORITEM && lpNTX->for_expr[0] >= 0x20 ) + { + if( SELF_COMPILE( ( AREAP ) pIndex->Owner, lpNTX->for_expr ) == FAILURE ) + { + hb_ntxDestroyExp( pKeyExp ); + return NULL; + } + pForExp = pIndex->Owner->valResult; + pIndex->Owner->valResult = NULL; + } + fName = !pIndex->Compound && lpNTX->tag_name[0] >= 0x20; + pTag = hb_ntxTagNew( pIndex, + fName ? (char *) lpNTX->tag_name : szTagName, fName, + (char *) lpNTX->key_expr, pKeyExp, + '\0', + HB_GET_LE_UINT16( lpNTX->key_size ), + HB_GET_LE_UINT16( lpNTX->key_dec ), + (char *) lpNTX->for_expr, pForExp, + lpNTX->descend[0] == 0, lpNTX->unique[0] != 0, + ( usType & NTX_FLAG_CUSTOM ) != 0 || lpNTX->custom[0] != 0, + ( usType & NTX_FLAG_SORTRECNO ) != 0 ); + + pTag->Signature = usType; + hb_ntxTagUpdateFlags( pTag ); + pTag->HeadBlock = ulBlock; + pTag->RootBlock = HB_GET_LE_UINT32( lpNTX->root ); + pTag->MaxKeys = HB_GET_LE_UINT16( lpNTX->max_item ); + pTag->KeyType = hb_ntxGetKeyType( pTag ); + + pIndex->LargeFile = ( usType & NTX_FLAG_LARGEFILE ) != 0; + + if( !pIndex->Compound ) + { + pIndex->Version = HB_GET_LE_UINT16( lpNTX->version ); + pIndex->NextAvail = HB_GET_LE_UINT32( lpNTX->next_page ); + pIndex->TagBlock = 0; + + /* TODO: this breaks unlocking !!! */ + if( usType & NTX_FLAG_LARGEFILE ) + { + pIndex->Owner->bLockType = DB_DBFLOCK_XHB64; + } + else if( usType & NTX_FLAG_EXTLOCK ) + { + pIndex->Owner->bLockType = DB_DBFLOCK_CL53EXT; + } + else if( ! pIndex->Owner->bLockType ) + { + pIndex->Owner->bLockType = usType & NTX_FLAG_EXTLOCK ? + DB_DBFLOCK_CL53EXT : DB_DBFLOCK_CLIP; + } + } + return pTag; +} + +/* + * add tag into CTX header + */ +static void hb_ntxIndexTagAdd( LPNTXINDEX pIndex, LPTAGINFO pTag ) +{ + LPCTXHEADER lpCTX = ( LPCTXHEADER ) pIndex->HeaderBuff; + int iTags = HB_GET_LE_UINT16( lpCTX->ntags ), i; + LPCTXTAGITEM pTagItem = ( LPCTXTAGITEM ) lpCTX->tags; + + for( i = 0; i < iTags; pTagItem++, i++ ) + { + if( !hb_strnicmp( ( char * ) pTagItem->tag_name, pTag->TagName, NTX_MAX_TAGNAME ) ) + break; + } + if( i == iTags ) + { + ++iTags; + HB_PUT_LE_UINT16( lpCTX->ntags, iTags ); + strncpy( ( char * ) pTagItem->tag_name, pTag->TagName, NTX_MAX_TAGNAME ); + } + HB_PUT_LE_UINT32( pTagItem->tag_header, pTag->HeadBlock ); + pIndex->Update = TRUE; +} + +/* + * delete tag from CTX header + */ +static void hb_ntxIndexTagDel( LPNTXINDEX pIndex, char * szTagName ) +{ + LPCTXHEADER lpCTX = ( LPCTXHEADER ) pIndex->HeaderBuff; + int iTags = HB_GET_LE_UINT16( lpCTX->ntags ), i; + LPCTXTAGITEM pTagItem = ( LPCTXTAGITEM ) lpCTX->tags; + + for( i = 0; i < iTags; pTagItem++, i++ ) + { + if( !hb_strnicmp( ( char * ) pTagItem->tag_name, szTagName, NTX_MAX_TAGNAME ) ) + { + memmove( pTagItem, pTagItem + 1, ( iTags - i ) * NTX_TAGITEMSIZE ); + memset( pTagItem + iTags - 1, 0, NTX_TAGITEMSIZE ); + --iTags; + HB_PUT_LE_UINT16( lpCTX->ntags, iTags ); + pIndex->Update = TRUE; + break; + } + } +} + +/* + * find tag header block in CTX header + */ +static ULONG hb_ntxIndexTagFind( LPCTXHEADER lpCTX, char * szTagName ) +{ + int iTags = HB_GET_LE_UINT16( lpCTX->ntags ), i; + LPCTXTAGITEM pTagItem = ( LPCTXTAGITEM ) lpCTX->tags; + + for( i = 0; i < iTags; pTagItem++, i++ ) + { + if( !hb_strnicmp( ( char * ) pTagItem->tag_name, szTagName, NTX_MAX_TAGNAME ) ) + return HB_GET_LE_UINT32( pTagItem->tag_header ); + } + return NTX_DUMMYNODE; +} + +/* + * Write tag header + */ +static ERRCODE hb_ntxTagHeaderSave( LPTAGINFO pTag ) +{ + LPNTXINDEX pIndex = pTag->Owner; + NTXHEADER Header; + int iSize = 12, type, version = 0; + ULONG next = 0; + + if( pIndex->Compound ) + { + if( !pTag->HeadBlock ) + { + pTag->HeadBlock = hb_ntxPageGetFree( pTag ); + if( !pTag->HeadBlock ) + return FAILURE; + hb_ntxIndexTagAdd( pIndex, pTag ); + } + } + else + { + if( pTag->HeadBlock ) + { + hb_ntxPageAddFree( pTag, pTag->HeadBlock ); + pTag->HeadBlock = 0; + pIndex->Update = TRUE; + } + pIndex->Version++; + version = pIndex->Version &= 0xffff; + next = pIndex->NextAvail; + } + + type = NTX_FLAG_DEFALUT | + ( pTag->ForExpr ? NTX_FLAG_FORITEM : 0 ) | + ( pTag->Partial ? NTX_FLAG_PARTIAL | NTX_FLAG_FORITEM : 0 ) | + ( pIndex->Owner->bLockType == DB_DBFLOCK_CL53EXT ? NTX_FLAG_EXTLOCK : 0 ) | + ( pTag->Partial ? NTX_FLAG_PARTIAL | NTX_FLAG_FORITEM : 0 ) | + /* non CLipper flags */ + ( pTag->Custom ? NTX_FLAG_CUSTOM : 0 ) | + ( pTag->ChgOnly ? NTX_FLAG_CHGONLY : 0 ) | + ( pTag->Template ? NTX_FLAG_TEMPLATE : 0 ) | + ( pTag->MultiKey ? NTX_FLAG_MULTIKEY : 0 ) | + ( pTag->fSortRec ? NTX_FLAG_SORTRECNO : 0 ) | + ( pIndex->LargeFile ? NTX_FLAG_LARGEFILE : 0 ); + + HB_PUT_LE_UINT16( Header.type, type ); + HB_PUT_LE_UINT16( Header.version, version ); + HB_PUT_LE_UINT32( Header.root, pTag->RootBlock ); + HB_PUT_LE_UINT32( Header.next_page, next ); + + if( pIndex->Update ) + { + memset( ( BYTE * ) &Header + 12, 0, sizeof( NTXHEADER ) - 12 ); + + HB_PUT_LE_UINT16( Header.item_size, pTag->KeyLength + 8 ); + HB_PUT_LE_UINT16( Header.key_size, pTag->KeyLength ); + HB_PUT_LE_UINT16( Header.key_dec, pTag->KeyDec ); + HB_PUT_LE_UINT16( Header.max_item, pTag->MaxKeys ); + HB_PUT_LE_UINT16( Header.half_page, pTag->MaxKeys >> 1 ); + Header.unique[0] = pTag->UniqueKey ? 1 : 0; + Header.descend[0] = pTag->AscendKey ? 0 : 1; + Header.custom[0] = pTag->Custom ? 1 : 0; + strncpy( ( char * ) Header.key_expr, pTag->KeyExpr, NTX_MAX_EXP ); + if( pTag->ForExpr ) + strncpy( ( char * ) Header.for_expr, pTag->ForExpr, NTX_MAX_EXP ); + if( pTag->fTagName ) + strncpy( ( char * ) Header.tag_name, pTag->TagName, NTX_MAX_TAGNAME ); + iSize = sizeof( NTXHEADER ); + } + + if( !hb_ntxBlockWrite( pIndex, pTag->HeadBlock, ( BYTE * ) &Header, iSize ) ) + return FAILURE; + pTag->HdrChanged = FALSE; + pIndex->Changed = pIndex->Compound; + pIndex->fFlush = TRUE; + return SUCCESS; +} + +/* + * create new index structure + */ static LPNTXINDEX hb_ntxIndexNew( NTXAREAP pArea ) { LPNTXINDEX pIndex; pIndex = ( LPNTXINDEX ) hb_xgrab( sizeof( NTXINDEX ) ); memset( pIndex, 0, sizeof( NTXINDEX ) ); - pIndex->DiskFile = FS_ERROR; + pIndex->DiskFile = FS_ERROR; pIndex->Owner = pArea; - pIndex->NextAvail = 0; return pIndex; } +/* + * close the index file and free from memory index and tag structures + */ static void hb_ntxIndexFree( LPNTXINDEX pIndex ) { - LPTAGINFO pTag; - - pTag = pIndex->CompoundTag; - hb_ntxPageFree( pTag,TRUE ); - hb_fsClose( pIndex->DiskFile ); - hb_xfree( pTag->TagName ); - if( pTag->KeyExpr != NULL ) - hb_xfree( pTag->KeyExpr ); - if( pTag->ForExpr != NULL ) - hb_xfree( pTag->ForExpr ); - if( pTag->pKeyItem != NULL ) + hb_ntxFreePageBuffer( pIndex ); + if( pIndex->iTags ) { - if( hb_itemType( pTag->pKeyItem ) != HB_IT_BLOCK ) - hb_macroDelete( ( HB_MACRO_PTR ) hb_itemGetPtr( pTag->pKeyItem ) ); - hb_itemRelease( pTag->pKeyItem ); + int i; + for( i = 0; i < pIndex->iTags; i++ ) + hb_ntxTagFree( pIndex->lpTags[i] ); + hb_xfree( pIndex->lpTags ); } - if( pTag->pForItem != NULL ) + if( pIndex->HeaderBuff ) + hb_xfree( pIndex->HeaderBuff ); + if( pIndex->DiskFile != FS_ERROR ) { - if( hb_itemType( pTag->pForItem ) != HB_IT_BLOCK ) - hb_macroDelete( ( HB_MACRO_PTR ) hb_itemGetPtr( pTag->pForItem ) ); - hb_itemRelease( pTag->pForItem ); + hb_fsClose( pIndex->DiskFile ); + if( pIndex->fDelete ) + { + hb_fsDelete( ( BYTE * ) ( pIndex->RealName ? + pIndex->RealName : pIndex->IndexName ) ); + } } - hb_ntxKeyFree( pTag->CurKeyInfo ); - hb_ntxClearScope( pTag,0 ); - hb_ntxClearScope( pTag,1 ); - hb_xfree( pTag->stack ); - hb_xfree( pTag->pages ); - hb_xfree( pTag ); - hb_xfree( pIndex->IndexName ); + if( pIndex->IndexName ) + hb_xfree( pIndex->IndexName ); + if( pIndex->RealName ) + hb_xfree( pIndex->RealName ); hb_xfree( pIndex ); } -static ERRCODE hb_ntxHeaderRead( LPNTXINDEX pIndex ) +/* + * Write tag header + */ +static ERRCODE hb_ntxIndexHeaderSave( LPNTXINDEX pIndex ) { - NTXHEADER Header; - ULONG ulPos; - - ulPos = hb_fsSeek( pIndex->DiskFile, 0, SEEK_END ); - hb_fsSeek( pIndex->DiskFile , 0 , 0 ); - if( hb_fsRead( pIndex->DiskFile,(BYTE*)&Header,16 ) != 16 ) - return FAILURE; - - pIndex->NextAvail = Header.next_page; - pIndex->CompoundTag->TagBlock = ulPos - 1024; - pIndex->CompoundTag->RootBlock = Header.root; - return SUCCESS; -} - -static ERRCODE hb_ntxHeaderLoad( LPNTXINDEX pIndex , char *ITN ) -{ - NTXHEADER Header; - LPTAGINFO pTag; - PHB_ITEM pKeyExp, pForExp = NULL; - ULONG ulPos; - - ulPos = hb_fsSeek( pIndex->DiskFile, 0, SEEK_END ); - - hb_fsSeek( pIndex->DiskFile , 0 , 0 ); - if( hb_fsRead( pIndex->DiskFile,(BYTE*)&Header,sizeof(NTXHEADER)) != sizeof(NTXHEADER) ) - return FAILURE; - - if( SELF_COMPILE( ( AREAP ) pIndex->Owner, (BYTE*)Header.key_expr ) == FAILURE ) - return FAILURE; - pKeyExp = hb_itemNew( NULL ); - hb_itemCopy( pKeyExp, pIndex->Owner->valResult ); - - if( Header.for_expr[0] > 20 ) + if( pIndex->Compound ) { - if( SELF_COMPILE( ( AREAP ) pIndex->Owner, (BYTE*)Header.for_expr ) == FAILURE ) + LPCTXHEADER lpCTX = ( LPCTXHEADER ) pIndex->HeaderBuff; + int iSize = pIndex->Update ? NTXBLOCKSIZE : 16; + USHORT type; + + type = NTX_FLAG_COMPOUND | ( pIndex->LargeFile ? NTX_FLAG_LARGEFILE : 0 ); + + pIndex->Version++; + HB_PUT_LE_UINT16( lpCTX->type, type ); + HB_PUT_LE_UINT16( lpCTX->ntags, pIndex->iTags ); + HB_PUT_LE_UINT32( lpCTX->version, pIndex->Version ); + HB_PUT_LE_UINT32( lpCTX->freepage, pIndex->NextAvail ); + HB_PUT_LE_UINT32( lpCTX->filesize, pIndex->TagBlock ); + + if( !hb_ntxBlockWrite( pIndex, 0, ( BYTE * ) lpCTX, iSize ) ) return FAILURE; - pForExp = hb_itemNew( NULL ); - hb_itemCopy( pForExp, pIndex->Owner->valResult ); } - - pTag = ( LPTAGINFO ) hb_xgrab( sizeof( TAGINFO ) ); - memset( pTag, 0, sizeof( TAGINFO ) ); - pIndex->CompoundTag = pTag; - pIndex->NextAvail = Header.next_page; - pTag->TagBlock = ulPos - 1024; - pTag->RootBlock = Header.root; - if( Header.tag_name[0] > 20 ) - { - pTag->fTagName = TRUE; - pTag->TagName = (char *) hb_xgrab( NTX_MAX_TAGNAME + 1 ); - hb_strncpyUpper( pTag->TagName, Header.tag_name, NTX_MAX_TAGNAME ); - } - else - { - pTag->fTagName = FALSE; - pTag->TagName = (char *) hb_xgrab( NTX_MAX_TAGNAME + 1 ); - hb_strncpyUpper( pTag->TagName, ITN, NTX_MAX_TAGNAME ); - } - pTag->KeyExpr = (char *) hb_xgrab( NTX_MAX_KEY ); - strcpy( pTag->KeyExpr, Header.key_expr ); - - if( pForExp ) - { - pTag->ForExpr = (char *) hb_xgrab( NTX_MAX_KEY ); - strcpy( pTag->ForExpr, Header.for_expr ); - } - - pTag->nField = hb_rddFieldIndex( (AREAP) pIndex->Owner, - hb_strUpper(Header.key_expr,strlen(Header.key_expr)) ); - pTag->pKeyItem = pKeyExp; - pTag->pForItem = pForExp; - pTag->UniqueKey = Header.unique; - pTag->AscendKey = !Header.descend; - pTag->Custom = Header.custom; - pTag->KeyType = 'C'; /* bKeyType; */ - pTag->KeyLength = Header.key_size; - pTag->KeyDec = Header.key_dec; - pTag->Owner = pIndex; - pTag->MaxKeys = Header.max_item; - pTag->CurKeyInfo = hb_ntxKeyNew( NULL,pTag->KeyLength ); - pTag->stack = (LPTREESTACK) hb_xgrab( sizeof(TREE_STACK) * 32 ); - pTag->stackDepth = 32; - pTag->ulPages = 0; - pTag->ulPagesDepth = NTX_PAGES_PER_TAG; - pTag->pages = (LPPAGEINFO) hb_xgrab( sizeof(HB_PAGEINFO)*NTX_PAGES_PER_TAG ); - memset( pTag->pages , 0 ,sizeof( HB_PAGEINFO )*NTX_PAGES_PER_TAG ); - pTag->TagRoot = 1; + pIndex->Changed = pIndex->Update = FALSE; return SUCCESS; } -static LPPAGEINFO hb_ntxPageFind( LPTAGINFO pTag, LONG ulOffset ) +/* + * load new tags from index file + */ +static ERRCODE hb_ntxIndexLoad( LPNTXINDEX pIndex, char * szTagName ) { - LPPAGEINFO pPage = pTag->pages; - ULONG i = 0; - /* printf( "\nntxPageFind - 0 ( %5lx %5lx %d )",pIndex,pPage,ulOffset ); */ - for( ; i < pTag->ulPagesDepth; i++,pPage++ ) - if( pPage->Page == ulOffset ) - break; - return ( i < pTag->ulPagesDepth )? pPage:NULL; + LPTAGINFO pTag; + USHORT type; + + if( !pIndex->fValidHeader ) + { + if( !pIndex->HeaderBuff ) + pIndex->HeaderBuff = ( BYTE * ) hb_xgrab( NTXBLOCKSIZE ); + if( !hb_ntxBlockRead( pIndex, 0, pIndex->HeaderBuff, NTXBLOCKSIZE ) ) + return FAILURE; + pIndex->fValidHeader = TRUE; + } + + type = HB_GET_LE_UINT16( pIndex->HeaderBuff ); +#if !defined( HB_NTX_NOMULTITAG ) + pIndex->Compound = ( type & NTX_FLAG_COMPOUND ) != 0; + if( pIndex->Compound ) + { + BYTE tagbuffer[ NTXBLOCKSIZE ]; + LPCTXHEADER lpCTX = ( LPCTXHEADER ) pIndex->HeaderBuff; + LPCTXTAGITEM pTagItem = ( LPCTXTAGITEM ) lpCTX->tags; + ULONG ulBlock; + int iTags; + + iTags = HB_GET_LE_UINT16( lpCTX->ntags ); + if( iTags > CTX_MAX_TAGS ) + return FAILURE; + pIndex->Version = HB_GET_LE_UINT32( lpCTX->version ); + pIndex->NextAvail = HB_GET_LE_UINT32( lpCTX->freepage ); + pIndex->TagBlock = HB_GET_LE_UINT32( lpCTX->filesize ); + pIndex->LargeFile = ( type & NTX_FLAG_LARGEFILE ) != 0; + + for( pIndex->iTags = 0; pIndex->iTags < iTags; pTagItem++ ) + { + ulBlock = HB_GET_LE_UINT32( pTagItem->tag_header ); + if( ulBlock == 0 || pTagItem->tag_name[ 0 ] <= 0x20 ) + return FAILURE; + if( !hb_ntxBlockRead( pIndex, ulBlock, tagbuffer, NTXBLOCKSIZE ) ) + return FAILURE; + pTag = hb_ntxTagLoad( pIndex, ulBlock, ( char * ) pTagItem->tag_name, tagbuffer ); + if( !pTag ) + return FAILURE; + hb_ntxTagAdd( pIndex, pTag ); + } + } + else +#endif + { + pTag = hb_ntxTagLoad( pIndex, 0, szTagName, pIndex->HeaderBuff ); + if( !pTag ) + return FAILURE; + hb_ntxTagAdd( pIndex, pTag ); + } + + return SUCCESS; } -static LPTAGINFO ntxFindIndex( NTXAREAP pArea , PHB_ITEM lpOrder ) +/* + * read index header and check for concurrent access + */ +static ERRCODE hb_ntxIndexHeaderRead( LPNTXINDEX pIndex ) { - LPTAGINFO start, current; + USHORT type; - start = pArea->lpNtxTag; - if( !start ) - return NULL; - current = start; + if( !pIndex->HeaderBuff ) + pIndex->HeaderBuff = ( BYTE * ) hb_xgrab( NTXBLOCKSIZE ); - if( !lpOrder ) - return pArea->lpCurTag; - else if( hb_itemType( lpOrder ) == HB_IT_STRING ) + if( !hb_ntxBlockRead( pIndex, 0, pIndex->HeaderBuff, NTXBLOCKSIZE ) ) + return FAILURE; + + type = HB_GET_LE_UINT16( pIndex->HeaderBuff ); + if( ( type & NTX_FLAG_COMPOUND ) != 0 ) { - do +#if defined( HB_NTX_NOMULTITAG ) + hb_ntxErrorRT( pIndex->Owner, EG_CORRUPTION, EDBF_CORRUPT, + pIndex->IndexName, hb_fsError(), 0 ); + return FAILURE; +#else + LPCTXHEADER lpCTX = ( LPCTXHEADER ) pIndex->HeaderBuff; + ULONG ulVersion, ulNext; + /* USHORT usTags = HB_GET_LE_UINT16( lpCTX->ntags ); */ + + ulVersion = HB_GET_LE_UINT32( lpCTX->version ); + ulNext = HB_GET_LE_UINT32( lpCTX->freepage ); + pIndex->TagBlock = HB_GET_LE_UINT32( lpCTX->filesize ); + + if( pIndex->Version != ulVersion || pIndex->NextAvail != ulNext || + !pIndex->Compound ) { - if( !hb_stricmp( current->TagName , lpOrder->item.asString.value ) ) - return current; - current = current->pNext; - } while( current ); + int i; + hb_ntxDiscardBuffers( pIndex ); + pIndex->Version = ulVersion; + pIndex->NextAvail = ulNext; + pIndex->Compound = TRUE; + for( i = 1; i < pIndex->iTags; i++ ) + { + pIndex->lpTags[ i ]->HeadBlock = + hb_ntxIndexTagFind( lpCTX, pIndex->lpTags[ i ]->TagName ); + if( !pIndex->lpTags[ i ]->HeadBlock ) + pIndex->lpTags[ i ]->RootBlock = 0; + } + } +#endif } else { - do + LPNTXHEADER lpNTX = ( LPNTXHEADER ) pIndex->HeaderBuff; + LPTAGINFO pTag; + USHORT usVersion; + ULONG ulRootPage; + + if( pIndex->Compound ) { - if( current->TagRoot == hb_itemGetNI( lpOrder ) ) - return current; - current = current->pNext; - } while( current ); + hb_ntxErrorRT( pIndex->Owner, EG_CORRUPTION, EDBF_CORRUPT, + pIndex->IndexName, hb_fsError(), 0 ); + return FAILURE; + } + pTag = pIndex->iTags ? pIndex->lpTags[0] : NULL; + + usVersion = HB_GET_LE_UINT16( lpNTX->version ); + ulRootPage = HB_GET_LE_UINT32( lpNTX->root ); + pIndex->NextAvail = HB_GET_LE_UINT32( lpNTX->next_page ); + if( pIndex->Version != usVersion || ( pTag && + ( pTag->Signature != type || ulRootPage != pTag->RootBlock ) ) ) + { + hb_ntxDiscardBuffers( pIndex ); + pIndex->Version = usVersion; + if( pTag ) + { + pTag->RootBlock = ulRootPage; + pTag->Signature = type; + hb_ntxTagUpdateFlags( pTag ); + } + } } + return SUCCESS; +} + +/* + * write modified pages to index file + */ +static void hb_ntxIndexFlush( LPNTXINDEX pIndex ) +{ + while( pIndex->pChanged ) + { + LPPAGEINFO pPage = pIndex->pChanged; + pIndex->pChanged = pPage->pNext; + if( pPage->Changed ) + { + hb_ntxPageSave( pIndex, pPage ); + ++pPage->iUsed; + hb_ntxPageRelease( pIndex->lpTags[0], pPage ); + } + else + hb_errInternal( 9999, "hb_ntxIndexFlush: unchaged page in the list.", "", "" ); + } + + if( pIndex->Compound ) + { + int i; + + for( i = 0; i < pIndex->iTags; i++ ) + if( pIndex->lpTags[ i ]->HdrChanged ) + hb_ntxTagHeaderSave( pIndex->lpTags[ i ] ); + if( pIndex->Changed ) + hb_ntxIndexHeaderSave( pIndex ); + } + else + { + if( pIndex->Changed || pIndex->lpTags[ 0 ]->HdrChanged ) + hb_ntxTagHeaderSave( pIndex->lpTags[ 0 ] ); + } +} + +/* + * lock index for reading (shared lock) + */ +static BOOL hb_ntxIndexLockRead( LPNTXINDEX pIndex ) +{ + BOOL fOK; + + if( pIndex->lockRead > 0 || pIndex->lockWrite > 0 || !pIndex->fShared ) + { + fOK = TRUE; + pIndex->lockRead++; + } + else + { + fOK = hb_dbfLockIdxFile( pIndex->DiskFile, pIndex->Owner->bLockType, + FL_LOCK | FLX_SHARED | FLX_WAIT, &pIndex->ulLockPos ); + /* if fOK then check VERSION field in NTXHEADER and + * if it has been changed then discard all page buffers + */ + if( fOK ) + { + pIndex->lockRead++; + if( hb_ntxIndexHeaderRead( pIndex ) != SUCCESS ) + { + pIndex->lockRead--; + hb_dbfLockIdxFile( pIndex->DiskFile, pIndex->Owner->bLockType, + FL_UNLOCK, &pIndex->ulLockPos ); + return FALSE; + } + } + } + if( !fOK ) + hb_ntxErrorRT( pIndex->Owner, EG_LOCK, EDBF_LOCK, pIndex->IndexName, hb_fsError(), 0 ); + + return fOK; +} + +/* + * lock index for writing (exclusive lock) + */ +static BOOL hb_ntxIndexLockWrite( LPNTXINDEX pIndex, BOOL fCheck ) +{ + BOOL fOK; + + if( pIndex->fReadonly ) + hb_errInternal( 9101, "hb_ntxIndexLockWrite: readonly index.", "", "" ); + + if( pIndex->lockRead ) + hb_errInternal( 9105, "hb_ntxIndexLockWrite: writeLock after readLock.", "", "" ); + + if( pIndex->lockWrite > 0 || !pIndex->fShared ) + { + fOK = TRUE; + pIndex->lockWrite++; + } + else + { + fOK = hb_dbfLockIdxFile( pIndex->DiskFile, pIndex->Owner->bLockType, + FL_LOCK | FLX_WAIT, &pIndex->ulLockPos ); + /* if fOK then check VERSION field in NTXHEADER and + * if it has been changed then discard all page buffers + */ + if( fOK ) + { + pIndex->lockWrite++; + if( fCheck && hb_ntxIndexHeaderRead( pIndex ) != SUCCESS ) + { + pIndex->lockWrite--; + hb_dbfLockIdxFile( pIndex->DiskFile, pIndex->Owner->bLockType, + FL_UNLOCK, &pIndex->ulLockPos ); + return FALSE; + } + } + } + if( !fOK ) + hb_ntxErrorRT( pIndex->Owner, EG_LOCK, EDBF_LOCK, pIndex->IndexName, hb_fsError(), 0 ); + + return fOK; +} + +/* + * remove index read lock (shared lock) + */ +static BOOL hb_ntxIndexUnLockRead( LPNTXINDEX pIndex ) +{ + BOOL fOK; + +#ifdef HB_NTX_DEBUG + int i; + for( i = 0; i < pIndex->iTags; i++ ) + hb_ntxTagCheckBuffers( pIndex->lpTags[ i ] ); +#endif + + pIndex->lockRead--; + if( pIndex->lockRead < 0 ) + hb_errInternal( 9106, "hb_ntxIndexUnLockRead: bad count of locks.", "", "" ); + + if( pIndex->lockRead || pIndex->lockWrite || !pIndex->fShared ) + { + fOK = TRUE; + } + else + { + pIndex->fValidHeader = FALSE; + fOK = hb_dbfLockIdxFile( pIndex->DiskFile, pIndex->Owner->bLockType, + FL_UNLOCK, &pIndex->ulLockPos ); + } + if( !fOK ) + hb_errInternal( 9108, "hb_ntxIndexUnLockRead: unlock error.", "", "" ); + + return fOK; +} + +/* + * remove index write lock (exclusive lock) + */ +static BOOL hb_ntxIndexUnLockWrite( LPNTXINDEX pIndex ) +{ + BOOL fOK; + +#ifdef HB_NTX_DEBUG + int i; + for( i = 0; i < pIndex->iTags; i++ ) + hb_ntxTagCheckBuffers( pIndex->lpTags[ i ] ); +#endif + + if( pIndex->lockWrite <= 0 ) + hb_errInternal( 9106, "hb_ntxIndexUnLockWrite: bad count of locks.", "", "" ); + if( pIndex->lockRead ) + hb_errInternal( 9105, "hb_ntxIndexUnLockWrite: writeUnLock before readUnLock.", "", "" ); + + hb_ntxIndexFlush( pIndex ); + pIndex->lockWrite--; + + if( pIndex->lockWrite || !pIndex->fShared ) + { + fOK = TRUE; + } + else + { + pIndex->fValidHeader = FALSE; + fOK = hb_dbfLockIdxFile( pIndex->DiskFile, pIndex->Owner->bLockType, + FL_UNLOCK, &pIndex->ulLockPos ); + } + if( !fOK ) + hb_errInternal( 9108, "hb_ntxIndexUnLockWrite: unlock error.", "", "" ); + + return fOK; +} + +/* + * lock tag for reading (shared lock) + */ +static BOOL hb_ntxTagLockRead( LPTAGINFO pTag ) +{ + BOOL fOK = FALSE; + + if( hb_ntxIndexLockRead( pTag->Owner ) ) + { + fOK = hb_ntxTagHeaderCheck( pTag ); + if( !fOK ) + { + hb_ntxIndexUnLockRead( pTag->Owner ); + hb_ntxErrorRT( pTag->Owner->Owner, EG_CORRUPTION, EDBF_CORRUPT, + pTag->Owner->IndexName, 0, 0 ); + } + } + return fOK; +} + +/* + * lock tag for writing (exclusive lock) + */ +static BOOL hb_ntxTagLockWrite( LPTAGINFO pTag ) +{ + BOOL fOK = FALSE; + + if( hb_ntxIndexLockWrite( pTag->Owner, TRUE ) ) + { + fOK = hb_ntxTagHeaderCheck( pTag ); + if( !fOK ) + { + hb_ntxIndexUnLockWrite( pTag->Owner ); + hb_ntxErrorRT( pTag->Owner->Owner, EG_CORRUPTION, EDBF_CORRUPT, + pTag->Owner->IndexName, 0, 0 ); + } + } + return fOK; +} + +/* + * remove tag read lock (shared lock) + */ +static BOOL hb_ntxTagUnLockRead( LPTAGINFO pTag ) +{ + return hb_ntxIndexUnLockRead( pTag->Owner ); +} + +/* + * remove tag write lock (exclusive lock) + */ +static BOOL hb_ntxTagUnLockWrite( LPTAGINFO pTag ) +{ + return hb_ntxIndexUnLockWrite( pTag->Owner ); +} + +/* + * retrive key from page + */ +static void hb_ntxPageGetKey( LPPAGEINFO pPage, USHORT uiKey, LPKEYINFO pKey, USHORT uiLen ) +{ + if( uiKey < pPage->uiKeys ) + { + memcpy( pKey->key, hb_ntxGetKeyVal( pPage, uiKey ), uiLen ); + pKey->Xtra = hb_ntxGetKeyRec( pPage, uiKey ); + pKey->Tag = pPage->Page; + } + else + { + pKey->Xtra = pKey->Tag = 0; + } +} + +/* + * set next page and key in page path + */ +static void hb_ntxTagSetPageStack( LPTAGINFO pTag, ULONG ulPage, USHORT uiKey ) +{ + if( pTag->stackLevel == pTag->stackSize ) + { + if( pTag->stackSize == 0 ) + { + pTag->stackSize = NTX_STACKSIZE; + pTag->stack = (LPTREESTACK) hb_xgrab( sizeof(TREE_STACK) * NTX_STACKSIZE ); + } + else + { + pTag->stackSize += NTX_STACKSIZE; + pTag->stack = ( LPTREESTACK ) hb_xrealloc( pTag->stack, + sizeof( TREE_STACK ) * pTag->stackSize ); + } + } + pTag->stack[ pTag->stackLevel ].page = ulPage; + pTag->stack[ pTag->stackLevel++ ].ikey = uiKey; +} + +/* + * go down from the given index page to the first key + */ +static LPPAGEINFO hb_ntxPageTopMove( LPTAGINFO pTag, ULONG ulPage ) +{ + LPPAGEINFO pPage = NULL; + + do + { + if( pPage ) + hb_ntxPageRelease( pTag, pPage ); + pPage = hb_ntxPageLoad( pTag, ulPage ); + if( ! pPage ) + return NULL; +#ifdef HB_NTX_DEBUG_EXT + if( pPage->uiKeys == 0 && pTag->stackLevel > 0 ) + { + hb_errInternal( 9201, "hb_ntxPageTopMove: index corrupted.", "", "" ); + return NULL; + } +#endif + ulPage = hb_ntxGetKeyPage( pPage, 0 ); + hb_ntxTagSetPageStack( pTag, pPage->Page, 0 ); + } + while( ulPage ); + + return pPage; +} + +/* + * go down from the given index page to the last key + */ +static LPPAGEINFO hb_ntxPageBottomMove( LPTAGINFO pTag, ULONG ulPage ) +{ + LPPAGEINFO pPage = NULL; + + do + { + if( pPage ) + hb_ntxPageRelease( pTag, pPage ); + pPage = hb_ntxPageLoad( pTag, ulPage ); + if( ! pPage ) + return NULL; +#ifdef HB_NTX_DEBUG_EXT + if( pPage->uiKeys == 0 && pTag->stackLevel > 0 ) + { + hb_errInternal( 9201, "hb_ntxPageBottomMove: index corrupted.", "", "" ); + return NULL; + } +#endif + ulPage = hb_ntxGetKeyPage( pPage, pPage->uiKeys ); + hb_ntxTagSetPageStack( pTag, pPage->Page, pPage->uiKeys - + ( ulPage || pPage->uiKeys == 0 ? 0 : 1 ) ); + } + while( ulPage ); + + return pPage; +} + +/* + * set page path to the first key in tag + */ +static BOOL hb_ntxTagTopKey( LPTAGINFO pTag ) +{ + LPPAGEINFO pPage; + int iKeys; + + pTag->stackLevel = 0; + pPage = hb_ntxPageTopMove( pTag, 0 ); + if( ! pPage ) + return FALSE; + hb_ntxPageGetKey( pPage, 0, pTag->CurKeyInfo, pTag->KeyLength ); + iKeys = pPage->uiKeys; + hb_ntxPageRelease( pTag, pPage ); + return iKeys != 0; +} + +/* + * set page path to the last key in tag + */ +static BOOL hb_ntxTagBottomKey( LPTAGINFO pTag ) +{ + LPPAGEINFO pPage; + int iKeys; + + pTag->stackLevel = 0; + pPage = hb_ntxPageBottomMove( pTag, 0 ); + if( ! pPage ) + return FALSE; + hb_ntxPageGetKey( pPage, pTag->stack[ pTag->stackLevel - 1 ].ikey, + pTag->CurKeyInfo, pTag->KeyLength ); + iKeys = pPage->uiKeys; + hb_ntxPageRelease( pTag, pPage ); + return iKeys != 0; +} + +/* + * update page path to the next key in tag + */ +static BOOL hb_ntxTagNextKey( LPTAGINFO pTag ) +{ + int iLevel = pTag->stackLevel - 1; + LPPAGEINFO pPage; + ULONG ulPage = 0; + + if( iLevel >= 0 ) + { + pPage = hb_ntxPageLoad( pTag, pTag->stack[ iLevel ].page ); + if( ! pPage ) + return FALSE; + if( pTag->stack[ iLevel ].ikey < pPage->uiKeys ) + ulPage = hb_ntxGetKeyPage( pPage, pTag->stack[ iLevel ].ikey + 1 ); + if( ulPage || pTag->stack[ iLevel ].ikey + 1 < pPage->uiKeys ) + { + pTag->stack[ iLevel ].ikey++; + if( ulPage ) + { + hb_ntxPageRelease( pTag, pPage ); + pPage = hb_ntxPageTopMove( pTag, ulPage ); + if( ! pPage ) + return FALSE; + } + } + else + { + while( --iLevel >= 0 ) + { + hb_ntxPageRelease( pTag, pPage ); + pPage = hb_ntxPageLoad( pTag, pTag->stack[ iLevel ].page ); + if( ! pPage ) + return FALSE; + if( pTag->stack[ iLevel ].ikey < pPage->uiKeys ) + break; + } + if( iLevel < 0 ) + { + hb_ntxPageRelease( pTag, pPage ); + return FALSE; + } + pTag->stackLevel = iLevel + 1; + } + hb_ntxPageGetKey( pPage, pTag->stack[ pTag->stackLevel - 1 ].ikey, + pTag->CurKeyInfo, pTag->KeyLength ); + hb_ntxPageRelease( pTag, pPage ); + return TRUE; + } + return FALSE; +} + +/* + * update page path to the previous key in tag + */ +static BOOL hb_ntxTagPrevKey( LPTAGINFO pTag ) +{ + int iLevel = pTag->stackLevel - 1; + LPPAGEINFO pPage; + ULONG ulPage; + + if( iLevel >= 0 ) + { + pPage = hb_ntxPageLoad( pTag, pTag->stack[ iLevel ].page ); + if( ! pPage ) + return FALSE; + ulPage = hb_ntxGetKeyPage( pPage, pTag->stack[ iLevel ].ikey ); + if( ulPage ) + { + hb_ntxPageRelease( pTag, pPage ); + pPage = hb_ntxPageBottomMove( pTag, ulPage ); + if( ! pPage ) + return FALSE; + } + else if( pTag->stack[ iLevel ].ikey ) + { + pTag->stack[ iLevel ].ikey--; + } + else + { + while( --iLevel >= 0 ) + { + hb_ntxPageRelease( pTag, pPage ); + pPage = hb_ntxPageLoad( pTag, pTag->stack[ iLevel ].page ); + if( ! pPage ) + return FALSE; + if( pTag->stack[ iLevel ].ikey ) + { + pTag->stack[ iLevel ].ikey--; + break; + } + } + if( iLevel < 0 ) + { + hb_ntxPageRelease( pTag, pPage ); + return FALSE; + } + pTag->stackLevel = iLevel + 1; + } + hb_ntxPageGetKey( pPage, pTag->stack[ pTag->stackLevel - 1 ].ikey, + pTag->CurKeyInfo, pTag->KeyLength ); + hb_ntxPageRelease( pTag, pPage ); + return TRUE; + } + return FALSE; +} + +/* + * find a key value in page + */ +static int hb_ntxPageKeyFind( LPTAGINFO pTag, LPPAGEINFO pPage, + char* key, SHORT keylen, BOOL fNext, + ULONG ulRecNo, BOOL *fStop ) +{ + SHORT iLast = -1, iBegin = 0, iEnd = pPage->uiKeys - 1, k, i; + + *fStop = FALSE; + while( iBegin <= iEnd ) + { + i = ( iBegin + iEnd ) >> 1; + k = hb_ntxValCompare( pTag, key, keylen, hb_ntxGetKeyVal( pPage, i ), + pTag->KeyLength, FALSE ); + if( k == 0 ) + { + if( ulRecNo != 0 && pTag->fSortRec ) + { + ULONG ulRec = hb_ntxGetKeyRec( pPage, i ); + if( ulRecNo < ulRec ) + k = -1; + else if( ulRecNo > ulRec ) + k = 1; + else + { + *fStop = TRUE; + return i; + } + } + } + else if( !pTag->AscendKey ) + k = -k; + if( fNext ? k >= 0 : k > 0 ) + iBegin = i + 1; + else + { + if( k == 0 && !ulRecNo ) + *fStop = TRUE; + iLast = i; + iEnd = i - 1; + } + } + return iLast >= 0 ? iLast : pPage->uiKeys; +} + +/* + * find a record in page starting from given key + */ +static BOOL hb_ntxPageFindRecNo( LPPAGEINFO pPage, int * iStart, ULONG ulRecno ) +{ + int iKey = *iStart; + while( iKey < pPage->uiKeys ) + { + if( hb_ntxGetKeyRec( pPage, iKey ) == ulRecno ) + { + *iStart = iKey; + return TRUE; + } + iKey++; + } + return FALSE; +} + +/* + * set page path to given key in tag + */ +static BOOL hb_ntxTagKeyFind( LPTAGINFO pTag, LPKEYINFO pKey, USHORT uiLen ) +{ + LPPAGEINFO pPage = NULL; + ULONG ulPage = 0, ulRecNo = 0; + int iKey; + BOOL fStop = FALSE, fNext = FALSE, fPrev = FALSE, fOut = FALSE; + + if( pKey->Tag == NTX_MAX_REC_NUM ) /* for key add */ + { + if( pTag->fSortRec ) + ulRecNo = pKey->Xtra; + else + fNext = TRUE; + } + else if( pKey->Xtra == NTX_MAX_REC_NUM ) /* for seek last */ + fNext = fPrev = TRUE; + else if( pKey->Xtra != NTX_IGNORE_REC_NUM ) /* for key del and current key */ + ulRecNo = pKey->Xtra; + /* else -> normal seek */ + + pTag->stackLevel = 0; + do + { + if( pPage ) + hb_ntxPageRelease( pTag, pPage ); + pPage = hb_ntxPageLoad( pTag, ulPage ); + if( ! pPage ) + return FALSE; + iKey = hb_ntxPageKeyFind( pTag, pPage, pKey->key, uiLen, fNext, ulRecNo, &fStop ); + hb_ntxTagSetPageStack( pTag, pPage->Page, iKey ); + if( fStop && ulRecNo && pTag->fSortRec ) + break; + ulPage = hb_ntxGetKeyPage( pPage, iKey ); + } while( ulPage != 0 ); + + if( ulRecNo && !pTag->fSortRec ) /* small hack - should speedup in some cases */ + { + if( hb_ntxPageFindRecNo( pPage, &iKey, ulRecNo ) ) + pTag->stack[ pTag->stackLevel - 1 ].ikey = iKey; + } + + hb_ntxPageGetKey( pPage, iKey, pTag->CurKeyInfo, pTag->KeyLength ); + hb_ntxPageRelease( pTag, pPage ); + + if( ulRecNo ) + { + if( !pTag->fSortRec ) + { + fStop = TRUE; + while( fStop && ulRecNo != pTag->CurKeyInfo->Xtra ) + { + if( ! hb_ntxTagNextKey( pTag ) ) /* Tag EOF */ + { + fOut = TRUE; + fStop = FALSE; + } + else + { + fStop = hb_ntxValCompare( pTag, pKey->key, uiLen, + pTag->CurKeyInfo->key, pTag->KeyLength, + FALSE ) == 0; + } + } + } + } + else if( fPrev ) + { + if( !hb_ntxTagPrevKey( pTag ) ) + { + fOut = TRUE; + fStop = FALSE; + } + else + { + fStop = hb_ntxValCompare( pTag, pKey->key, uiLen, pTag->CurKeyInfo->key, + pTag->KeyLength, FALSE ) == 0; + } + } + else if( !fNext && !fStop && pTag->CurKeyInfo->Xtra == 0 ) + { + if( ! hb_ntxTagNextKey( pTag ) ) /* Tag EOF */ + { + fOut = TRUE; + fStop = FALSE; + } + else + { + fStop = hb_ntxValCompare( pTag, pKey->key, uiLen, + pTag->CurKeyInfo->key, pTag->KeyLength, + FALSE ) == 0; + } + } + + pTag->TagBOF = pTag->TagEOF = fOut || pTag->CurKeyInfo->Xtra == 0; + + return fStop; +} + +/* + * set key in the given tag page + */ +static void hb_ntxPageKeySet( LPTAGINFO pTag, LPPAGEINFO pPage, USHORT uiPos, + ULONG ulPage, ULONG ulRec, char * keyVal ) +{ + hb_ntxSetKeyPage( pPage, uiPos, ulPage ); + hb_ntxSetKeyRec( pPage, uiPos, ulRec ); + memcpy( hb_ntxGetKeyVal( pPage, uiPos ), keyVal, pTag->KeyLength ); + pPage->Changed = TRUE; +} + +/* + * add key to tag page + */ +static void hb_ntxPageKeyAdd( LPTAGINFO pTag, LPPAGEINFO pPage, USHORT uiPos, + ULONG ulPage, ULONG ulRec, char * keyVal ) +{ + USHORT u, ntmp = hb_ntxGetKeyOffset( pPage, pPage->uiKeys + 1 ); + + /* TODO?: update to keep last key pointer fixed */ + for( u = pPage->uiKeys + 1; u > uiPos; u-- ) + { + hb_ntxSetKeyOffset( pPage, u, hb_ntxGetKeyOffset( pPage, u - 1 ) ); + } + hb_ntxSetKeyOffset( pPage, uiPos, ntmp ); + pPage->uiKeys++; + + hb_ntxPageKeySet( pTag, pPage, uiPos, ulPage, ulRec, keyVal ); +#ifdef HB_NTX_DEBUG + hb_ntxPageCheckKeys( pPage, pTag, uiPos, 41 ); +#endif +} + +/* + * del key from the page + */ +static void hb_ntxPageKeyDel( LPPAGEINFO pPage, USHORT uiPos ) +{ + USHORT u, ntmp = hb_ntxGetKeyOffset( pPage, uiPos ); + + /* TODO?: update to keep last key pointer fixed */ + for( u = uiPos; u < pPage->uiKeys; u++ ) + hb_ntxSetKeyOffset( pPage, u, hb_ntxGetKeyOffset( pPage, u + 1 ) ); + hb_ntxSetKeyOffset( pPage, pPage->uiKeys, ntmp ); + + pPage->uiKeys--; + pPage->Changed = TRUE; +} + +/* + * split single page into two and return key to the new one + */ +static LPKEYINFO hb_ntxPageSplit( LPTAGINFO pTag, LPPAGEINFO pPage, + LPKEYINFO pKey, USHORT uiPos ) +{ + LPPAGEINFO pNewPage = hb_ntxPageNew( pTag, FALSE ); + LPKEYINFO pKeyNew; + USHORT uiKeys = pPage->uiKeys + 1, uiLen = pTag->KeyLength + 8, + i, j, u, uiHalf; + ULONG ulPage; + + if( ! pNewPage ) + return NULL; + pKeyNew = hb_ntxKeyNew( NULL, pTag->KeyLength ); + + uiHalf = uiKeys >> 1; + + j = 0; + while( pNewPage->uiKeys < uiHalf ) + { + if( pNewPage->uiKeys == uiPos ) + { + hb_ntxSetKeyPage( pNewPage, pNewPage->uiKeys, pKey->Tag ); + hb_ntxSetKeyRec( pNewPage, pNewPage->uiKeys, pKey->Xtra ); + memcpy( hb_ntxGetKeyVal( pNewPage, pNewPage->uiKeys ), pKey->key, pTag->KeyLength ); + } + else + { + memcpy( hb_ntxGetKeyPtr( pNewPage, pNewPage->uiKeys ), + hb_ntxGetKeyPtr( pPage, j ), uiLen ); + j++; + } + pNewPage->uiKeys++; + } + + if( uiHalf == uiPos ) + { + pKeyNew->Xtra = pKey->Xtra; + memcpy( pKeyNew->key, pKey->key, pTag->KeyLength ); + hb_ntxSetKeyPage( pNewPage, pNewPage->uiKeys, pKey->Tag ); + } + else + { + pKeyNew->Xtra = hb_ntxGetKeyRec( pPage, j ); + memcpy( pKeyNew->key, hb_ntxGetKeyVal( pPage, j ), pTag->KeyLength ); + hb_ntxSetKeyPage( pNewPage, pNewPage->uiKeys, hb_ntxGetKeyPage( pPage, j ) ); + j++; + } + pKeyNew->Tag = pNewPage->Page; + + i = 0; + while( ++uiHalf < uiKeys ) + { + if( uiHalf == uiPos ) + { + hb_ntxSetKeyPage( pPage, i, pKey->Tag ); + hb_ntxSetKeyRec( pPage, i, pKey->Xtra ); + memcpy( hb_ntxGetKeyVal( pPage, i ), pKey->key, pTag->KeyLength ); + } + else + { + u = hb_ntxGetKeyOffset( pPage, j ); + hb_ntxSetKeyOffset( pPage, j, hb_ntxGetKeyOffset( pPage, i ) ); + hb_ntxSetKeyOffset( pPage, i, u ); + j++; + } + i++; + } + ulPage = hb_ntxGetKeyPage( pPage, pPage->uiKeys ); + hb_ntxSetKeyPage( pPage, pPage->uiKeys, 0 ); + hb_ntxSetKeyPage( pPage, i, ulPage ); + pPage->uiKeys = i; + + pPage->Changed = pNewPage->Changed = TRUE; +#ifdef HB_NTX_DEBUG + hb_ntxPageCheckKeys( pNewPage, pTag, uiPos, 1 ); + hb_ntxPageCheckKeys( pPage, pTag, uiPos - pNewPage->uiKeys, 2 ); +#endif + hb_ntxPageRelease( pTag, pNewPage ); + + return pKeyNew; +} + +/* + * join two neighbour pages and update the parent page key + */ +static void hb_ntxPageJoin( LPTAGINFO pTag, LPPAGEINFO pBasePage, USHORT uiPos, + LPPAGEINFO pFirst, LPPAGEINFO pLast ) +{ + USHORT uiLen = pTag->KeyLength + 8, i; + + hb_ntxSetKeyRec( pFirst, pFirst->uiKeys, hb_ntxGetKeyRec( pBasePage, uiPos ) ); + memcpy( hb_ntxGetKeyVal( pFirst, pFirst->uiKeys ), + hb_ntxGetKeyVal( pBasePage, uiPos ), pTag->KeyLength ); + pFirst->uiKeys++; + hb_ntxPageKeyDel( pBasePage, uiPos ); + hb_ntxSetKeyPage( pBasePage, uiPos, pFirst->Page ); + for( i = 0; i < pLast->uiKeys; i++ ) + { + memcpy( hb_ntxGetKeyPtr( pFirst, pFirst->uiKeys ), + hb_ntxGetKeyPtr( pLast, i ), uiLen ); + pFirst->uiKeys++; + } + hb_ntxSetKeyPage( pFirst, pFirst->uiKeys, hb_ntxGetKeyPage( pLast, pLast->uiKeys ) ); + pLast->uiKeys = 0; + hb_ntxPageFree( pTag, pLast ); + pFirst->Changed = pLast->Changed = TRUE; +#ifdef HB_NTX_DEBUG + hb_ntxPageCheckKeys( pBasePage, pTag, uiPos, 11 ); + hb_ntxPageCheckKeys( pFirst, pTag, 0, 12 ); +#endif +} + +/* + * balance keys in two neighbour pages and update the parent page key + */ +static void hb_ntxBalancePages( LPTAGINFO pTag, LPPAGEINFO pBasePage, USHORT uiPos, + LPPAGEINFO pFirst, LPPAGEINFO pLast ) +{ + USHORT uiLen = pTag->KeyLength + 8, n; + int i, j, iMove = ( ( pFirst->uiKeys + pLast->uiKeys + 1 ) >> 1 ) - pFirst->uiKeys; + + /* + * such situation should not exist even max keys, though it does not cost + * much and I want to be able to call hb_ntxBalancePages in any case for + * some advanced balancing + */ + if( iMove == 0 ) + return; + +#ifdef HB_NTX_DEBUG + hb_ntxPageCheckKeys( pBasePage, pTag, uiPos, 31 ); + hb_ntxPageCheckKeys( pFirst, pTag, iMove, 32 ); + hb_ntxPageCheckKeys( pLast, pTag, iMove, 33 ); +#endif + + if( iMove > 0 ) + { + hb_ntxSetKeyRec( pFirst, pFirst->uiKeys, hb_ntxGetKeyRec( pBasePage, uiPos ) ); + memcpy( hb_ntxGetKeyVal( pFirst, pFirst->uiKeys ), + hb_ntxGetKeyVal( pBasePage, uiPos ), pTag->KeyLength ); + pFirst->uiKeys++; + i = 0; + while( --iMove ) + { + memcpy( hb_ntxGetKeyPtr( pFirst, pFirst->uiKeys ), + hb_ntxGetKeyPtr( pLast, i ), uiLen ); + pFirst->uiKeys++; + i++; + } + hb_ntxSetKeyRec( pBasePage, uiPos, hb_ntxGetKeyRec( pLast, i ) ); + memcpy( hb_ntxGetKeyVal( pBasePage, uiPos ), + hb_ntxGetKeyVal( pLast, i ), pTag->KeyLength ); + hb_ntxSetKeyPage( pFirst, pFirst->uiKeys, hb_ntxGetKeyPage( pLast, i ) ); + i++; + pLast->uiKeys -= i; + /* TODO?: update to keep last key pointer fixed */ + for( j = 0; j <= pLast->uiKeys; j++ ) + { + n = hb_ntxGetKeyOffset( pLast, j ); + hb_ntxSetKeyOffset( pLast, j, hb_ntxGetKeyOffset( pLast, j + i ) ); + hb_ntxSetKeyOffset( pLast, j + i, n ); + } + } + else + { + /* TODO?: update to keep last key pointer fixed */ + for( j = pLast->uiKeys; j >= 0; j-- ) + { + n = hb_ntxGetKeyOffset( pLast, j - iMove ); + hb_ntxSetKeyOffset( pLast, j - iMove, hb_ntxGetKeyOffset( pLast, j ) ); + hb_ntxSetKeyOffset( pLast, j, n ); + } + i = -iMove - 1; + hb_ntxSetKeyRec( pLast, i, hb_ntxGetKeyRec( pBasePage, uiPos ) ); + memcpy( hb_ntxGetKeyVal( pLast, i ), + hb_ntxGetKeyVal( pBasePage, uiPos ), pTag->KeyLength ); + hb_ntxSetKeyPage( pLast, i, hb_ntxGetKeyPage( pFirst, pFirst->uiKeys ) ); + while( --i >= 0 ) + { + pFirst->uiKeys--; + memcpy( hb_ntxGetKeyPtr( pLast, i ), + hb_ntxGetKeyPtr( pFirst, pFirst->uiKeys ), uiLen ); + } + pLast->uiKeys -= iMove; + pFirst->uiKeys--; + hb_ntxSetKeyRec( pBasePage, uiPos, hb_ntxGetKeyRec( pFirst, pFirst->uiKeys ) ); + memcpy( hb_ntxGetKeyVal( pBasePage, uiPos ), + hb_ntxGetKeyVal( pFirst, pFirst->uiKeys ), pTag->KeyLength ); + } + pFirst->Changed = pLast->Changed = pBasePage->Changed = TRUE; +#ifdef HB_NTX_DEBUG + hb_ntxPageCheckKeys( pBasePage, pTag, uiPos, 21 ); + hb_ntxPageCheckKeys( pFirst, pTag, iMove, 22 ); + hb_ntxPageCheckKeys( pLast, pTag, iMove, 23 ); +#endif +} + +/* + * add key to the index at the curret page path + */ +static BOOL hb_ntxTagKeyAdd( LPTAGINFO pTag, LPKEYINFO pKey ) +{ + int iLevel, iKey; + LPPAGEINFO pPage = NULL; + LPKEYINFO pNewKey = NULL; + ULONG ulPage; + BOOL fFound, fBottom = FALSE; + + if( pTag->UniqueKey ) + { + ULONG ulRecNo = pKey->Xtra; + + pKey->Xtra = NTX_IGNORE_REC_NUM; + fFound = hb_ntxTagKeyFind( pTag, pKey, pTag->KeyLength ); + pKey->Xtra = ulRecNo; + if( fFound ) + return FALSE; + fBottom = TRUE; + } + else + { + pKey->Tag = NTX_MAX_REC_NUM; + fFound = hb_ntxTagKeyFind( pTag, pKey, pTag->KeyLength ); + pKey->Tag = 0; + if( fFound ) + { + if( pTag->MultiKey ) + fBottom = TRUE; + else + return FALSE; + } + } + pTag->CurKeyInfo = hb_ntxKeyCopy( pTag->CurKeyInfo, pKey, pTag->KeyLength ); + + iLevel = pTag->stackLevel - 1; + if( fBottom ) + { + pPage = hb_ntxPageLoad( pTag, pTag->stack[ iLevel ].page ); + if( ! pPage ) + return FALSE; + ulPage = hb_ntxGetKeyPage( pPage, pTag->stack[ iLevel ].ikey ); + if( ulPage ) + { + hb_ntxPageRelease( pTag, pPage ); + pPage = hb_ntxPageBottomMove( pTag, ulPage ); + if( ! pPage ) + return FALSE; + iLevel = pTag->stackLevel - 1; + if( pTag->stack[ iLevel ].ikey < pPage->uiKeys ) + pTag->stack[ iLevel ].ikey++; + } + } + + while( iLevel >= 0 && pKey ) + { + if( pPage ) + hb_ntxPageRelease( pTag, pPage ); + pPage = hb_ntxPageLoad( pTag, pTag->stack[ iLevel ].page ); + if( ! pPage ) + return FALSE; + iKey = pTag->stack[ iLevel ].ikey; + if( pPage->uiKeys < pTag->MaxKeys ) + { + hb_ntxPageKeyAdd( pTag, pPage, iKey, pKey->Tag, pKey->Xtra, pKey->key ); + pKey = NULL; + } + else + { + pKey = hb_ntxPageSplit( pTag, pPage, pKey, iKey ); + if( pNewKey ) + hb_ntxKeyFree( pNewKey ); + pNewKey = pKey; + pTag->stackLevel = 0; + } + iLevel--; + } + hb_ntxPageRelease( pTag, pPage ); + if( pKey ) + { + pPage = hb_ntxPageNew( pTag, FALSE ); + if( ! pPage ) + return FALSE; + hb_ntxPageKeyAdd( pTag, pPage, 0, pKey->Tag, pKey->Xtra, pKey->key ); + hb_ntxSetKeyPage( pPage, 1, pTag->RootBlock ); + pTag->RootBlock = pPage->Page; + pTag->HdrChanged = TRUE; + hb_ntxPageRelease( pTag, pPage ); + pTag->stackLevel = 0; + } + if( pNewKey ) + hb_ntxKeyFree( pNewKey ); + return TRUE; +} + +/* + * del key at the curret page path from the index + */ +static BOOL hb_ntxTagKeyDel( LPTAGINFO pTag, LPKEYINFO pKey ) +{ + int iLevel, iBaseKey, iKey; + LPPAGEINFO pBasePage, pPage; + ULONG ulPage; + + pKey->Tag = 0; + if( pTag->stackLevel == 0 || pTag->CurKeyInfo->Xtra != pKey->Xtra || + memcmp( pTag->CurKeyInfo->key, pKey->key, pTag->KeyLength ) != 0 ) + { + if( ! hb_ntxTagKeyFind( pTag, pKey, pTag->KeyLength ) ) + return FALSE; + } + + iLevel = pTag->stackLevel - 1; + + pPage = hb_ntxPageLoad( pTag, pTag->stack[ iLevel ].page ); + if( ! pPage ) + return FALSE; + iKey = pTag->stack[ iLevel ].ikey; + ulPage = hb_ntxGetKeyPage( pPage, iKey ); + + if( ulPage ) + { + pBasePage = pPage; + iBaseKey = iKey; + pPage = hb_ntxPageBottomMove( pTag, ulPage ); + if( ! pPage ) + { + hb_ntxPageRelease( pTag, pBasePage ); + return FALSE; + } + iLevel = pTag->stackLevel - 1; + iKey = pTag->stack[ iLevel ].ikey; + + hb_ntxSetKeyRec( pBasePage, iBaseKey, hb_ntxGetKeyRec( pPage, iKey ) ); + memcpy( hb_ntxGetKeyVal( pBasePage, iBaseKey ), + hb_ntxGetKeyVal( pPage, iKey ), pTag->KeyLength ); + pBasePage->Changed = TRUE; +#ifdef HB_NTX_DEBUG + hb_ntxPageCheckKeys( pBasePage, pTag, iBaseKey, 61 ); +#endif + hb_ntxPageRelease( pTag, pBasePage ); + } + hb_ntxPageKeyDel( pPage, iKey ); + + while( iLevel > 0 ) + { + if( pPage->uiKeys < pTag->MaxKeys >> 1 ) + { + USHORT uiFirst, uiLast, uiBaseKey; + + pBasePage = hb_ntxPageLoad( pTag, pTag->stack[ iLevel -1 ].page ); + if( ! pBasePage ) + { + hb_ntxPageRelease( pTag, pPage ); + return FALSE; + } + uiFirst = uiLast = uiBaseKey = pTag->stack[ iLevel -1 ].ikey; + if( uiLast < pBasePage->uiKeys && hb_ntxGetKeyPage( pBasePage, uiLast + 1 ) != 0 ) + uiLast++; + else if( uiFirst > 0 && hb_ntxGetKeyPage( pBasePage, uiFirst - 1 ) != 0 ) + uiFirst--; + + if( uiFirst == uiLast ) + { + if( pPage->uiKeys == 0 ) + { + hb_ntxSetKeyPage( pBasePage, uiBaseKey, 0 ); + hb_ntxPageFree( pTag, pPage ); + } + hb_ntxPageRelease( pTag, pPage ); + } + else + { + LPPAGEINFO pFirst, pLast; + + if( uiFirst == uiBaseKey ) + { + pFirst = pPage; + pLast = hb_ntxPageLoad( pTag, hb_ntxGetKeyPage( pBasePage, uiLast ) ); + if( ! pLast ) + { + hb_ntxPageRelease( pTag, pPage ); + hb_ntxPageRelease( pTag, pBasePage ); + pTag->stackLevel = 0; + return FALSE; + } + } + else + { + pLast = pPage; + pFirst = hb_ntxPageLoad( pTag, hb_ntxGetKeyPage( pBasePage, uiFirst ) ); + if( ! pFirst ) + { + hb_ntxPageRelease( pTag, pPage ); + hb_ntxPageRelease( pTag, pBasePage ); + pTag->stackLevel = 0; + return FALSE; + } + } + if( pFirst->uiKeys + pLast->uiKeys < pTag->MaxKeys ) + hb_ntxPageJoin( pTag, pBasePage, uiFirst, pFirst, pLast ); + else + hb_ntxBalancePages( pTag, pBasePage, uiFirst, pFirst, pLast ); + hb_ntxPageRelease( pTag, pFirst ); + hb_ntxPageRelease( pTag, pLast ); + } + pPage = pBasePage; + } + else + break; + iLevel--; + } + + if( pPage->uiKeys == 0 && pPage->Page == pTag->RootBlock ) + { + ulPage = hb_ntxGetKeyPage( pPage, 0 ); + if( ulPage != 0 ) + { + pTag->RootBlock = ulPage; + pTag->HdrChanged = TRUE; + hb_ntxPageFree( pTag, pPage ); + } + } + hb_ntxPageRelease( pTag, pPage ); + pTag->stackLevel = 0; + return TRUE; +} + +/* + * refresh CurKey value and set proper path from RootPage to LeafPage + */ +static BOOL hb_ntxCurKeyRefresh( LPTAGINFO pTag ) +{ + NTXAREAP pArea = pTag->Owner->Owner; + + if( pArea->lpdbPendingRel ) + SELF_FORCEREL( ( AREAP ) pArea ); + + if( !pArea->fPositioned ) + { + pTag->stackLevel = 0; + pTag->TagEOF = TRUE; + pTag->CurKeyInfo->Xtra = 0; + return FALSE; + } + else if( pTag->stackLevel == 0 || pTag->CurKeyInfo->Xtra != pArea->ulRecNo ) + { + BYTE buf[ NTX_MAX_KEY ]; + BOOL fBuf = FALSE; + LPKEYINFO pKey = NULL; + /* Try to find previous if it's key for the same record */ + if( pTag->CurKeyInfo->Xtra == pArea->ulRecNo ) + { + fBuf = TRUE; + memcpy( buf, pTag->CurKeyInfo->key, pTag->KeyLength ); + pKey = hb_ntxKeyCopy( pKey, pTag->CurKeyInfo, pTag->KeyLength ); + hb_ntxTagKeyFind( pTag, pKey, pTag->KeyLength ); + } + if( pTag->CurKeyInfo->Xtra != pArea->ulRecNo ) + { + BOOL fValidBuf = pArea->fValidBuffer; + /* not found, create new key from DBF and if differs seek again */ + pKey = hb_ntxEvalKey( pKey, pTag ); + if( !fBuf || memcmp( buf, pKey->key, pTag->KeyLength ) != 0 ) + { + hb_ntxTagKeyFind( pTag, pKey, pTag->KeyLength ); + } + /* not found, if key was generated from DBF buffer then force to + * update it, create the new key and if differs seek again */ + if( pTag->CurKeyInfo->Xtra != pArea->ulRecNo && fValidBuf ) + { + SELF_GOTO( ( AREAP ) pArea, pArea->ulRecNo ); + memcpy( buf, pKey->key, pTag->KeyLength ); + pKey = hb_ntxEvalKey( pKey, pTag ); + if( memcmp( buf, pKey->key, pTag->KeyLength ) != 0 ) + hb_ntxTagKeyFind( pTag, pKey, pTag->KeyLength ); + } + } + hb_ntxKeyFree( pKey ); + return( pTag->CurKeyInfo->Xtra != 0 && pTag->CurKeyInfo->Xtra == pArea->ulRecNo ); + } + return TRUE; +} + +/* + * Skip in tag respecting record filter only + */ +static void hb_ntxTagSkipFilter( LPTAGINFO pTag, BOOL fForward ) +{ + BOOL fBack, fEof = fForward ? pTag->TagEOF : pTag->TagBOF; + + fBack = pTag->fUsrDescend == pTag->AscendKey ? fForward : !fForward; + + while( !fEof && !hb_ntxCheckRecordScope( pTag->Owner->Owner, + pTag->CurKeyInfo->Xtra ) ) + { + if( fBack ) + fEof = !hb_ntxTagPrevKey( pTag ); + else + fEof = !hb_ntxTagNextKey( pTag ); + + if( !fEof && !hb_ntxKeyInScope( pTag, pTag->CurKeyInfo ) ) + { + fEof = TRUE; + } + } + if( fEof ) + { + if( fForward ) + pTag->TagEOF = TRUE; + else + pTag->TagBOF = TRUE; + } +} + +/* + * go to the first visiable record in Tag + */ +static void hb_ntxTagGoTop( LPTAGINFO pTag ) +{ + PHB_NTXSCOPE pScope = pTag->fUsrDescend ? &pTag->bottom : &pTag->top; + + if( pScope->scopeKeyLen ) + hb_ntxTagKeyFind( pTag, pScope->scopeKey, pScope->scopeKeyLen ); + else if( pTag->fUsrDescend == pTag->AscendKey ) + hb_ntxTagBottomKey( pTag ); + else + hb_ntxTagTopKey( pTag ); + + pTag->TagEOF = pTag->CurKeyInfo->Xtra == 0 || + !hb_ntxKeyInScope( pTag, pTag->CurKeyInfo ); + + if( ! pTag->TagEOF && pTag->Owner->Owner->dbfi.fFilter ) + hb_ntxTagSkipFilter( pTag, TRUE ); + + pTag->TagBOF = pTag->TagEOF; +} + +/* + * go to the last visiable record in Tag + */ +static void hb_ntxTagGoBottom( LPTAGINFO pTag ) +{ + PHB_NTXSCOPE pScope = pTag->fUsrDescend ? &pTag->top : &pTag->bottom; + + if( pScope->scopeKeyLen ) + hb_ntxTagKeyFind( pTag, pScope->scopeKey, pScope->scopeKeyLen ); + else if( pTag->fUsrDescend == pTag->AscendKey ) + hb_ntxTagTopKey( pTag ); + else + hb_ntxTagBottomKey( pTag ); + + pTag->TagBOF = pTag->CurKeyInfo->Xtra == 0 || + !hb_ntxKeyInScope( pTag, pTag->CurKeyInfo ); + + if( ! pTag->TagBOF && pTag->Owner->Owner->dbfi.fFilter ) + hb_ntxTagSkipFilter( pTag, FALSE ); + + pTag->TagEOF = pTag->TagBOF; +} + +/* + * skip to Next Key in the Tag + */ +static void hb_ntxTagSkipNext( LPTAGINFO pTag ) +{ + pTag->TagBOF = FALSE; + + if( pTag->stackLevel == 0 ) + pTag->TagEOF = TRUE; + else if( ! hb_ntxInTopScope( pTag, pTag->CurKeyInfo->key ) ) + hb_ntxTagGoTop( pTag ); + else if( pTag->fUsrDescend == pTag->AscendKey ) + pTag->TagEOF = !hb_ntxTagPrevKey( pTag ); + else + pTag->TagEOF = !hb_ntxTagNextKey( pTag ); + + if( ! pTag->TagEOF && ! hb_ntxKeyInScope( pTag, pTag->CurKeyInfo ) ) + pTag->TagEOF = TRUE; + + if( ! pTag->TagEOF && pTag->Owner->Owner->dbfi.fFilter ) + hb_ntxTagSkipFilter( pTag, TRUE ); +} + +/* + * skip to Previous Key in the Tag + */ +static void hb_ntxTagSkipPrev( LPTAGINFO pTag ) +{ + pTag->TagEOF = FALSE; + + if( pTag->stackLevel == 0 ) + /* TODO?: check if this is NTX behavior, + for sure CDX works in such way */ + hb_ntxTagGoBottom( pTag ); + else if( pTag->fUsrDescend == pTag->AscendKey ) + pTag->TagBOF = !hb_ntxTagNextKey( pTag ); + else + pTag->TagBOF = !hb_ntxTagPrevKey( pTag ); + + if( ! pTag->TagBOF && ! hb_ntxKeyInScope( pTag, pTag->CurKeyInfo ) ) + pTag->TagBOF = TRUE; + + if( ! pTag->TagBOF && pTag->Owner->Owner->dbfi.fFilter ) + hb_ntxTagSkipFilter( pTag, FALSE ); +} + +/* + * count keys in the given page and all subpages + */ +static ULONG hb_ntxPageCountKeys( LPTAGINFO pTag, ULONG ulPage ) +{ + LPPAGEINFO pPage = hb_ntxPageLoad( pTag, ulPage ); + ULONG ulKeys; + USHORT u; + + if( ! pPage ) + return 0; + + ulKeys = pPage->uiKeys; + for( u = 0; u <= pPage->uiKeys; u++ ) + { + ulPage = hb_ntxGetKeyPage( pPage, u ); + if( ulPage ) + ulKeys += hb_ntxPageCountKeys( pTag, ulPage ); + } + hb_ntxPageRelease( pTag, pPage ); + + return ulKeys; +} + +/* + * count relative position of current location in page stack + */ +static double hb_ntxTagCountRelKeyPos( LPTAGINFO pTag ) +{ + int iLevel = pTag->stackLevel, iKeys; + double dPos = 1.0; + + while( --iLevel >= 0 ) + { + LPPAGEINFO pPage = hb_ntxPageLoad( pTag, pTag->stack[ iLevel ].page ); + if( ! pPage ) + break; + iKeys = pPage->uiKeys; + if( hb_ntxGetKeyPage( pPage, pPage->uiKeys ) ) + ++iKeys; + else if( iLevel == pTag->stackLevel - 1 ) + dPos = 0.5; + dPos = ( dPos + pTag->stack[ iLevel ].ikey ) / iKeys; + hb_ntxPageRelease( pTag, pPage ); + } + if( pTag->fUsrDescend == pTag->AscendKey ) + dPos = 1.0 - dPos; + return dPos; +} + +static void hb_ntxTagGoToRelKeyPos( LPTAGINFO pTag, double dPos ) +{ + LPPAGEINFO pPage = NULL; + ULONG ulPage = 0; + int iKey, iKeys; + + if( pTag->fUsrDescend == pTag->AscendKey ) + dPos = 1.0 - dPos; + + pTag->stackLevel = 0; + do + { + if( pPage ) + hb_ntxPageRelease( pTag, pPage ); + pPage = hb_ntxPageLoad( pTag, ulPage ); + if( ! pPage ) + { + pTag->stackLevel = 0; + return; + } + if( pPage->uiKeys == 0 ) + iKey = 0; + else + { + iKeys = pPage->uiKeys; + if( hb_ntxGetKeyPage( pPage, pPage->uiKeys ) ) + ++iKeys; + iKey = ( int ) ( dPos * iKeys ); + if( iKey >= iKeys ) + iKey = iKeys - 1; + dPos = dPos * iKeys - iKey; + if( dPos <= 0.0 ) + dPos = 0.0; + else if( dPos >= 1.0 ) + dPos = 1.0; + } + hb_ntxTagSetPageStack( pTag, pPage->Page, iKey ); + ulPage = hb_ntxGetKeyPage( pPage, iKey ); + } while( ulPage != 0 ); + + hb_ntxPageGetKey( pPage, iKey, pTag->CurKeyInfo, pTag->KeyLength ); + hb_ntxPageRelease( pTag, pPage ); + + if( dPos > 0.75 ) + hb_ntxTagNextKey( pTag ); + else if( dPos < 0.25 ) + hb_ntxTagPrevKey( pTag ); +} + +/* + * free pages allocated by tag + */ +static BOOL hb_ntxTagPagesFree( LPTAGINFO pTag, ULONG ulPage ) +{ + LPPAGEINFO pPage = hb_ntxPageLoad( pTag, ulPage ); + BOOL fOK = pPage != NULL; + USHORT u; + + for( u = 0; fOK && u <= pPage->uiKeys; u++ ) + { + ulPage = hb_ntxGetKeyPage( pPage, u ); + if( ulPage ) + fOK = hb_ntxTagPagesFree( pTag, ulPage ); + } + + if( fOK ) + { + pPage->uiKeys = 0; + hb_ntxPageFree( pTag, pPage ); + if( !pPage->pPrev ) + fOK = hb_ntxPageSave( pTag->Owner, pPage ); + } + hb_ntxPageRelease( pTag, pPage ); + + return fOK; +} + +/* + * free space allocated by tag + */ +static ERRCODE hb_ntxTagSpaceFree( LPTAGINFO pTag ) +{ + if( hb_ntxTagHeaderCheck( pTag ) ) + { + if( pTag->RootBlock ) + { + if( ! hb_ntxTagPagesFree( pTag, pTag->RootBlock ) ) + return FAILURE; + } + hb_ntxPageAddFree( pTag, pTag->HeadBlock ); + hb_ntxIndexTagDel( pTag->Owner, pTag->TagName ); + pTag->Owner->Changed = TRUE; + } + hb_ntxTagDelete( pTag ); + return SUCCESS; +} + +/* + * create index file name + */ +static void hb_ntxCreateFName( NTXAREAP pArea, char * szBagName, BOOL * fProd, + char * szFileName, char * szTagName ) +{ + PHB_FNAME pFileName; + PHB_ITEM pExt = NULL; + BOOL fName = szBagName && *szBagName; + + pFileName = hb_fsFNameSplit( fName ? szBagName : pArea->szDataFileName ); + + if( szTagName ) + { + hb_strncpyUpperTrim( szTagName, pFileName->szName, NTX_MAX_TAGNAME ); + } + + if( !pFileName->szExtension || !fName ) + { + DBORDERINFO pExtInfo; + memset( &pExtInfo, 0, sizeof( pExtInfo ) ); + pExt = pExtInfo.itmResult = hb_itemPutC( NULL, "" ); + if( SELF_ORDINFO( ( AREAP ) pArea, DBOI_BAGEXT, &pExtInfo ) == SUCCESS && + hb_itemGetCLen( pExtInfo.itmResult ) > 0 ) + { + pFileName->szExtension = hb_itemGetCPtr( pExtInfo.itmResult ); + } + } + + hb_fsFNameMerge( szFileName, pFileName ); + + if( pExt ) + hb_itemRelease( pExt ); + if( fProd ) + { + if( !fName ) + *fProd = TRUE; + else + { + PHB_FNAME pTableFileName = hb_fsFNameSplit( pArea->szDataFileName ); + *fProd = hb_stricmp( pTableFileName->szName, pFileName->szName ) == 0; + hb_xfree( pTableFileName ); + } + } + hb_xfree( pFileName ); +} + +/* + * find order bag by its name + */ +static LPNTXINDEX hb_ntxFindBag( NTXAREAP pArea, char * szBagName ) +{ + LPNTXINDEX pIndex; + PHB_FNAME pSeek, pName; + BOOL fFound; + + pSeek = hb_fsFNameSplit( szBagName ); + pIndex = pArea->lpIndexes; + while( pIndex ) + { + pName = hb_fsFNameSplit( pIndex->IndexName ); + fFound = !hb_stricmp( pName->szName, pSeek->szName ) && + ( !pSeek->szPath || ( pName->szPath && + !hb_stricmp( pName->szPath, pSeek->szPath ) ) ) && + ( !pSeek->szExtension || ( pName->szExtension && + !hb_stricmp( pName->szExtension, pSeek->szExtension ) ) ); + hb_xfree( pName ); + if( fFound ) + break; + pIndex = pIndex->pNext; + } + hb_xfree( pSeek ); + return pIndex; +} + +/* + * Find tag by name in index bag + */ +static int hb_ntxFindTagByName( LPNTXINDEX pIndex, char * szTag ) +{ + int i; + + for( i = 0; i < pIndex->iTags; i++ ) + { + if( !hb_strnicmp( pIndex->lpTags[ i ]->TagName, szTag, + NTX_MAX_TAGNAME ) ) + return i + 1; + } + return 0; +} + +/* + * Find the tag by its name or number + */ +static LPTAGINFO hb_ntxFindTag( NTXAREAP pArea, PHB_ITEM pTagItem, + PHB_ITEM pBagItem ) +{ + LPNTXINDEX pIndex; + BOOL fBag; + + if( ! pTagItem || + ( hb_itemType( pTagItem ) & ( HB_IT_STRING | HB_IT_NUMERIC ) ) == 0 ) + return pArea->lpCurTag; + + fBag = hb_itemGetCLen( pBagItem ) > 0; + if( fBag ) + { + if( hb_itemType( pTagItem ) & HB_IT_STRING ) + pIndex = hb_ntxFindBag( pArea, hb_itemGetCPtr( pBagItem ) ); + else + pIndex = pArea->lpIndexes; + } + else + { + int iBag = hb_itemGetNI( pBagItem ); + + pIndex = pArea->lpIndexes; + if( iBag > 0 ) + { + fBag = TRUE; + while( pIndex ) + { + if( --iBag == 0 ) + break; + pIndex = pIndex->pNext; + } + } + else if( iBag < 0 ) + { + pIndex = NULL; + } + } + if( pIndex ) + { + if( hb_itemType( pTagItem ) & HB_IT_STRING ) + { + char * szTag = hb_itemGetCPtr( pTagItem ); + int iTag; + + if( fBag ) + iTag = hb_ntxFindTagByName( pIndex, szTag ); + else + { + do + { + iTag = hb_ntxFindTagByName( pIndex, szTag ); + if( iTag ) + break; + pIndex = pIndex->pNext; + } while( pIndex ); + } + if( iTag ) + return pIndex->lpTags[ iTag - 1 ]; + } + else + { + int i = hb_itemGetNI( pTagItem ) - 1; + + if( i >= 0 ) + { + if( fBag ) + { + if( i < pIndex->iTags ) + return pIndex->lpTags[ i ]; + } + else + { + do + { + if( i < pIndex->iTags ) + return pIndex->lpTags[ i ]; + i -= pIndex->iTags; + pIndex = pIndex->pNext; + } while( pIndex ); + } + } + } + } + return NULL; } -static BOOL hb_ntxOrdKeyAdd( LPTAGINFO pTag ) +/* + * find the given tag number + */ +static int hb_ntxFindTagNum( NTXAREAP pArea, LPTAGINFO pTag ) { - LPKEYINFO pKey; - BOOL bResult = FALSE; - - if( !pTag->Custom || pTag->Owner->Owner->fEof || ( pTag->pForItem && - !checkLogicalExpr( pTag->pForItem, NULL ) ) ) - return bResult; - - pKey = hb_ntxKeyNew( NULL,pTag->KeyLength ); - hb_ntxGetCurrentKey( pTag, pKey ); - if( hb_ntxInTopScope( pTag, pTag->CurKeyInfo->key ) && - hb_ntxInBottomScope( pTag, pTag->CurKeyInfo->key ) ) + if( pArea->fSetTagNumbers ) { - pKey->Tag = 0; - if( pTag->Owner->Owner->fShared && !pTag->Memory ) - while( !hb_fsLock( pTag->Owner->DiskFile, NTX_LOCK_OFFSET, 1, FL_LOCK | FLX_WAIT ) ); - hb_ntxTagKeyAdd( pTag, pKey ); - if( pTag->Owner->Owner->fShared && !pTag->Memory ) + LPNTXINDEX pIndex = pArea->lpIndexes; + USHORT uiNum = 0, i; + + pTag->uiNumber = 0; + while( pIndex ) { - hb_ntxPageFree( pTag,FALSE ); - hb_fsLock( pTag->Owner->DiskFile, NTX_LOCK_OFFSET, 1, FL_UNLOCK ); + for( i = 0; i < pIndex->iTags; i++ ) + { + pIndex->lpTags[ i ]->uiNumber = ++uiNum; + } + pIndex = pIndex->pNext; } - bResult = TRUE; + pArea->fSetTagNumbers = FALSE; } - hb_ntxKeyFree( pKey ); - - return bResult; + return pTag->uiNumber; } -static BOOL hb_ntxOrdKeyDel( LPTAGINFO pTag ) +/* + * count number of keys in given tag + */ +static ULONG hb_ntxOrdKeyCount( LPTAGINFO pTag ) { - LPKEYINFO pKey; - BOOL bResult = FALSE; + ULONG ulKeyCount = 0; - if( !pTag->Custom || pTag->Owner->Owner->fEof || ( pTag->pForItem && - !checkLogicalExpr( pTag->pForItem, NULL ) ) ) - return bResult; + if( !pTag->Owner->fShared && pTag->keyCount && + !pTag->Owner->Owner->dbfi.fFilter ) + return pTag->keyCount; - pKey = hb_ntxKeyNew( NULL,pTag->KeyLength ); - hb_ntxGetCurrentKey( pTag, pKey ); - if( pTag->Owner->Owner->fShared && !pTag->Memory ) - while( !hb_fsLock( pTag->Owner->DiskFile, NTX_LOCK_OFFSET, 1, FL_LOCK | FLX_WAIT ) ); - pTag->stackLevel = 0; - if( hb_ntxInTopScope( pTag, pTag->CurKeyInfo->key ) && - hb_ntxInBottomScope( pTag, pTag->CurKeyInfo->key ) && - !hb_ntxTagFindCurrentKey( pTag, hb_ntxPageLoad( pTag,0 ), pKey, (int)pTag->KeyLength, FALSE, 0 ) ) + if( hb_ntxTagLockRead( pTag ) ) { - LPPAGEINFO pPage = hb_ntxPageLoad( pTag,pTag->CurKeyInfo->Tag ); - pPage->CurKey = hb_ntxPageFindCurrentKey( pPage,pTag->CurKeyInfo->Xtra ) - 1; - hb_ntxPageKeyDel( pTag, pPage, pPage->CurKey, 1 ); - if( pTag->stack[0].ikey < 0 ) - hb_ntxTagBalance( pTag,0 ); - bResult = TRUE; + hb_ntxTagRefreshScope( pTag ); + + if( pTag->top.scopeKeyLen || pTag->bottom.scopeKeyLen || + pTag->Owner->Owner->dbfi.fFilter ) + { + hb_ntxTagGoTop( pTag ); + while( !pTag->TagEOF ) + { + ulKeyCount++; + hb_ntxTagSkipNext( pTag ); + } + } + else + { + ulKeyCount = hb_ntxPageCountKeys( pTag, 0 ); + } + if( !pTag->Owner->Owner->dbfi.fFilter ) + pTag->keyCount = ulKeyCount; + hb_ntxTagUnLockRead( pTag ); } - if( pTag->Owner->Owner->fShared && !pTag->Memory ) + return ulKeyCount; +} + +/* + * get the logical key position in the given tag + */ +static ULONG hb_ntxOrdKeyNo( LPTAGINFO pTag ) +{ + ULONG ulKeyNo = 0; + + if( hb_ntxTagLockRead( pTag ) ) { - hb_ntxPageFree( pTag,FALSE ); - hb_fsLock( pTag->Owner->DiskFile, NTX_LOCK_OFFSET, 1, FL_UNLOCK ); + hb_ntxTagRefreshScope( pTag ); + if( hb_ntxCurKeyRefresh( pTag ) ) + { + if( pTag->top.scopeKeyLen || pTag->bottom.scopeKeyLen || + pTag->Owner->Owner->dbfi.fFilter ) + { + if( hb_ntxKeyInScope( pTag, pTag->CurKeyInfo ) ) + { + do + { + ulKeyNo++; + hb_ntxTagSkipPrev( pTag ); + } + while( !pTag->TagBOF ); + } + } + else + { + int iLevel = pTag->stackLevel, iKey, iFirst = 1; + BOOL fBack = pTag->fUsrDescend == pTag->AscendKey; + LPPAGEINFO pPage; + ULONG ulPage; + + while( --iLevel >= 0 ) + { + pPage = hb_ntxPageLoad( pTag, pTag->stack[ iLevel ].page ); + if( ! pPage ) + break; + if( fBack ) + { + iKey = pTag->stack[ iLevel ].ikey; + ulKeyNo += pPage->uiKeys - iKey; + while( ++iKey <= pPage->uiKeys ) + { + ulPage = hb_ntxGetKeyPage( pPage, iKey ); + if( ulPage ) + ulKeyNo += hb_ntxPageCountKeys( pTag, ulPage ); + } + } + else + { + ulKeyNo += iKey = pTag->stack[ iLevel ].ikey + iFirst; + iFirst = 0; + while( --iKey >= 0 ) + { + ulPage = hb_ntxGetKeyPage( pPage, iKey ); + if( ulPage ) + ulKeyNo += hb_ntxPageCountKeys( pTag, ulPage ); + } + } + hb_ntxPageRelease( pTag, pPage ); + } + } + } + hb_ntxTagUnLockRead( pTag ); + } + return ulKeyNo; +} + +/* + * set logical key position in given tag + */ +static BOOL hb_ntxOrdKeyGoto( LPTAGINFO pTag, ULONG ulKeyNo ) +{ + if( ! ulKeyNo || ! hb_ntxTagLockRead( pTag ) ) + return FALSE; + hb_ntxTagRefreshScope( pTag ); + hb_ntxTagGoTop( pTag ); + while( !pTag->TagEOF && --ulKeyNo ); + { + hb_ntxTagSkipNext( pTag ); + } + hb_ntxTagUnLockRead( pTag ); + return TRUE; +} + +/* + * get the relative key position (from 0.0 to 1.0) in the given tag + */ +static double hb_ntxOrdGetRelKeyPos( LPTAGINFO pTag ) +{ + double dPos = 0.0, dStart = 0.0, dStop = 1.0, dFact = 0.0000000000001; + BOOL fOK = TRUE, fFilter = pTag->Owner->Owner->dbfi.fFilter; + + if( ! hb_ntxTagLockRead( pTag ) ) + return FALSE; + + hb_ntxTagRefreshScope( pTag ); + + pTag->Owner->Owner->dbfi.fFilter = FALSE; + if( pTag->fUsrDescend ? pTag->bottom.scopeKeyLen : pTag->top.scopeKeyLen ) + { + hb_ntxTagGoTop( pTag ); + if( pTag->TagEOF ) + fOK = FALSE; + else + dStart = hb_ntxTagCountRelKeyPos( pTag ); + } + if( fOK && ( pTag->fUsrDescend ? pTag->top.scopeKeyLen : pTag->bottom.scopeKeyLen ) ) + { + hb_ntxTagGoBottom( pTag ); + if( pTag->TagBOF ) + fOK = FALSE; + else + dStop = hb_ntxTagCountRelKeyPos( pTag ); + } + pTag->Owner->Owner->dbfi.fFilter = fFilter; + + if( fOK ) + { + if( hb_ntxCurKeyRefresh( pTag ) && + hb_ntxKeyInScope( pTag, pTag->CurKeyInfo ) ) + { + if( dStart >= dStop - dFact ) + dPos = 0.5; + else + { + dPos = hb_ntxTagCountRelKeyPos( pTag ); + dPos = ( dPos - dStart ) / ( dStop - dStart ); + /* fix possible differences in FL representation */ + if( dPos <= 0.0 ) + dPos = 0.0; + else if( dPos >= 1.0 ) + dPos = 1.0; + } + } + } + hb_ntxTagUnLockRead( pTag ); + + return dPos; +} + +/* + * set the relative key position (from 0.0 to 1.0) in the given tag + */ +static void hb_ntxOrdSetRelKeyPos( LPTAGINFO pTag, double dPos ) +{ + if( hb_ntxTagLockRead( pTag ) ) + { + NTXAREAP pArea = pTag->Owner->Owner; + double dStart = 0.0, dStop = 1.0, dFact = 0.0000000000001; + BOOL fOK = TRUE, fFilter = pArea->dbfi.fFilter; + BOOL fForward = TRUE, fTop = FALSE; + + hb_ntxTagRefreshScope( pTag ); + + if( dPos >= 1.0 ) + fForward = FALSE; + else if( dPos <= 0.0 ) + fTop = TRUE; + else + { + pArea->dbfi.fFilter = FALSE; + if( pTag->fUsrDescend ? pTag->bottom.scopeKeyLen : pTag->top.scopeKeyLen ) + { + hb_ntxTagGoTop( pTag ); + if( pTag->TagEOF ) + fOK = FALSE; + else + dStart = hb_ntxTagCountRelKeyPos( pTag ); + } + if( fOK && ( pTag->fUsrDescend ? pTag->top.scopeKeyLen : pTag->bottom.scopeKeyLen ) ) + { + hb_ntxTagGoBottom( pTag ); + if( pTag->TagBOF ) + fOK = FALSE; + else + dStop = hb_ntxTagCountRelKeyPos( pTag ); + } + pArea->dbfi.fFilter = fFilter; + + if( fOK ) + { + if( dStart >= dStop - dFact ) + { + fTop = TRUE; + } + else + { + dPos = dPos * ( dStop - dStart ) + dStart; + hb_ntxTagGoToRelKeyPos( pTag, dPos ); + if( pTag->CurKeyInfo->Xtra == 0 ) + fForward = FALSE; + else if( !hb_ntxInTopScope( pTag, pTag->CurKeyInfo->key ) ) + fTop = TRUE; + else if( !hb_ntxInBottomScope( pTag, pTag->CurKeyInfo->key ) ) + fForward = FALSE; + } + } + } + if( !fOK ) + { + SELF_GOTO( ( AREAP ) pArea, 0 ); + } + else + { + LPTAGINFO pSavedTag = pArea->lpCurTag; + pArea->lpCurTag = pTag; + + pArea->fTop = pArea->fBottom = FALSE; + + if( fForward ) + { + if( fTop ) + hb_ntxTagGoTop( pTag ); + if( pTag->CurKeyInfo->Xtra != 0 ) + { + SELF_GOTO( ( AREAP ) pArea, pTag->CurKeyInfo->Xtra ); + SELF_SKIPFILTER( ( AREAP ) pArea, 1 ); + if( pArea->fEof && !fTop ) + fForward = FALSE; + } + else if( fTop ) + SELF_GOTO( ( AREAP ) pArea, 0 ); + else + fForward = FALSE; + } + if( !fForward ) + { + hb_ntxTagGoBottom( pTag ); + SELF_GOTO( ( AREAP ) pArea, pTag->CurKeyInfo->Xtra ); + if( pTag->CurKeyInfo->Xtra != 0 ) + { + pArea->fBottom = TRUE; + SELF_SKIPFILTER( ( AREAP ) pArea, -1 ); + } + } + pArea->lpCurTag = pSavedTag; + } + hb_ntxTagUnLockRead( pTag ); + } +} + +/* + * skip to next/previous unique key + */ +static BOOL hb_ntxOrdSkipUnique( LPTAGINFO pTag, LONG lDir ) +{ + NTXAREAP pArea = pTag->Owner->Owner; + BOOL fOut = FALSE, fEof = FALSE, fForward = ( lDir >= 0 ); + + if( pArea->lpdbPendingRel ) + SELF_FORCEREL( ( AREAP ) pArea ); + + pArea->fTop = pArea->fBottom = FALSE; + + if( hb_ntxTagLockRead( pTag ) ) + { + LPTAGINFO pSavedTag = pArea->lpCurTag; + pArea->lpCurTag = pTag; + + hb_ntxTagRefreshScope( pTag ); + if( hb_ntxCurKeyRefresh( pTag ) ) + { + char keyVal[ NTX_MAX_KEY ]; + memcpy( keyVal, pTag->CurKeyInfo->key, pTag->KeyLength ); + + do + { + if( fForward ) + hb_ntxTagSkipNext( pTag ); + else + hb_ntxTagSkipPrev( pTag ); + fOut = pTag->TagEOF || pTag->TagBOF; + } + while( !fOut && hb_ntxValCompare( pTag, + pTag->CurKeyInfo->key, pTag->KeyLength, + keyVal, pTag->KeyLength, TRUE ) == 0 ); + } + else if( !fForward && !pArea->fPositioned ) + { + hb_ntxTagGoBottom( pTag ); + fEof = pTag->TagEOF; + } + else + { + fOut = TRUE; + } + if( fOut ) + { + if( fForward ) + fEof = TRUE; + else + { + hb_ntxTagGoTop( pTag ); + fEof = pTag->TagEOF; + } + } + hb_ntxTagUnLockRead( pTag ); + + SELF_GOTO( ( AREAP ) pArea, fEof ? 0 : pTag->CurKeyInfo->Xtra ); + if( !fEof ) + { + SELF_SKIPFILTER( ( AREAP ) pArea, ( fForward || fOut ) ? 1 : -1 ); + if( ! fForward && fOut ) + pArea->fBof = TRUE; + } + + /* Update Bof and Eof flags */ + if( fForward ) + pArea->fBof = FALSE; + else + pArea->fEof = FALSE; + + pArea->lpCurTag = pSavedTag; + return TRUE; + } + return FALSE; +} + +/* + * skip while code block doesn't return TRUE + */ +static BOOL hb_ntxOrdSkipEval( LPTAGINFO pTag, BOOL fForward, PHB_ITEM pEval ) +{ + NTXAREAP pArea = pTag->Owner->Owner; + BOOL fFound = FALSE; + + HB_TRACE(HB_TR_DEBUG, ("hb_ntxOrdSkipEval(%p, %d, %p)", pTag, fForward, pEval)); + + if( ! HB_IS_BLOCK( pEval ) ) + { + if( SELF_SKIP( ( AREAP ) pArea, fForward ? 1 : -1 ) != SUCCESS ) + return FALSE; + return fForward ? !pArea->fEof : !pArea->fBof; + } + + if( pArea->lpdbPendingRel ) + SELF_FORCEREL( ( AREAP ) pArea ); + + pArea->fTop = pArea->fBottom = FALSE; + + if( hb_ntxTagLockRead( pTag ) ) + { + LPTAGINFO pSavedTag = pArea->lpCurTag; + pArea->lpCurTag = pTag; + + hb_ntxTagRefreshScope( pTag ); + if( hb_ntxCurKeyRefresh( pTag ) ) + { + if( fForward ) + hb_ntxTagSkipNext( pTag ); + else + hb_ntxTagSkipPrev( pTag ); + + while( fForward ? !pTag->TagEOF : !pTag->TagBOF ) + { + if( SELF_GOTO( ( AREAP ) pArea, pTag->CurKeyInfo->Xtra ) != SUCCESS ) + break; + if( hb_ntxEvalSeekCond( pTag, pEval ) ) + { + ULONG ulRecNo = pArea->ulRecNo; + SELF_SKIPFILTER( ( AREAP ) pArea, fForward ? 1 : -1 ); + if( pArea->ulRecNo == ulRecNo || hb_ntxEvalSeekCond( pTag, pEval ) ) + { + fFound = TRUE; + break; + } + } + if( fForward ) + hb_ntxTagSkipNext( pTag ); + else + hb_ntxTagSkipPrev( pTag ); + } + if( !fFound ) + { + if( fForward ) + SELF_GOTO( ( AREAP ) pArea, 0 ); + else + { + SELF_GOTOP( ( AREAP ) pArea ); + pArea->fBof = TRUE; + } + } + } + pArea->lpCurTag = pSavedTag; + hb_ntxTagUnLockRead( pTag ); + } + + /* Update Bof and Eof flags */ + if( fForward ) + pArea->fBof = FALSE; + else + pArea->fEof = FALSE; + + return fFound; +} + +/* + * skip while code block doesn't return TRUE + */ +static BOOL hb_ntxOrdSkipWild( LPTAGINFO pTag, BOOL fForward, PHB_ITEM pWildItm ) +{ + NTXAREAP pArea = pTag->Owner->Owner; + char *szPattern = hb_itemGetCPtr( pWildItm ); + BOOL fFound = FALSE; + + HB_TRACE(HB_TR_DEBUG, ("hb_ntxOrdSkipWild(%p, %d, %p)", pTag, fForward, pWildItm)); + + if( pTag->KeyType != 'C' || !szPattern || !*szPattern ) + { + if( SELF_SKIP( ( AREAP ) pArea, fForward ? 1 : -1 ) != SUCCESS ) + return FALSE; + return fForward ? !pArea->fEof : !pArea->fBof; + } + + if( pArea->lpdbPendingRel ) + SELF_FORCEREL( ( AREAP ) pArea ); + + pArea->fTop = pArea->fBottom = FALSE; + + if( hb_ntxTagLockRead( pTag ) ) + { + LPTAGINFO pSavedTag = pArea->lpCurTag; + pArea->lpCurTag = pTag; + + hb_ntxTagRefreshScope( pTag ); + if( hb_ntxCurKeyRefresh( pTag ) ) + { + if( fForward ) + hb_ntxTagSkipNext( pTag ); + else + hb_ntxTagSkipPrev( pTag ); + + while( fForward ? !pTag->TagEOF : !pTag->TagBOF ) + { + if( SELF_GOTO( ( AREAP ) pArea, pTag->CurKeyInfo->Xtra ) != SUCCESS ) + break; + if( hb_strMatchWild( pTag->CurKeyInfo->key, szPattern ) ) + { + ULONG ulRecNo = pArea->ulRecNo; + SELF_SKIPFILTER( ( AREAP ) pArea, fForward ? 1 : -1 ); + if( pArea->ulRecNo == ulRecNo || + hb_strMatchWild( pTag->CurKeyInfo->key, szPattern ) ) + { + fFound = TRUE; + break; + } + } + if( fForward ) + hb_ntxTagSkipNext( pTag ); + else + hb_ntxTagSkipPrev( pTag ); + } + if( !fFound ) + { + if( fForward ) + SELF_GOTO( ( AREAP ) pArea, 0 ); + else + { + SELF_GOTOP( ( AREAP ) pArea ); + pArea->fBof = TRUE; + } + } + } + pArea->lpCurTag = pSavedTag; + hb_ntxTagUnLockRead( pTag ); + } + + /* Update Bof and Eof flags */ + if( fForward ) + pArea->fBof = FALSE; + else + pArea->fEof = FALSE; + + return fFound; +} + +#if defined(__XHARBOUR__) +/* + * skip while regular expression on index key val doesn't return TRUE + */ +static BOOL hb_ntxOrdSkipRegEx( LPTAGINFO pTag, BOOL fForward, PHB_ITEM pRegExItm ) +{ + NTXAREAP pArea = pTag->Owner->Owner; + BOOL fFound = FALSE; + HB_REGEX RegEx; + + HB_TRACE(HB_TR_DEBUG, ("hb_ntxOrdSkipRegEx(%p, %d, %p)", pTag, fForward, pRegExItm)); + + if( pTag->KeyType != 'C' || !hb_regexGet( &RegEx, pRegExItm, 0, 0 ) ) + { + if( SELF_SKIP( ( AREAP ) pArea, fForward ? 1 : -1 ) != SUCCESS ) + return FALSE; + return fForward ? !pArea->fEof : !pArea->fBof; + } + + if( pArea->lpdbPendingRel ) + SELF_FORCEREL( ( AREAP ) pArea ); + + pArea->fTop = pArea->fBottom = FALSE; + + if( hb_ntxTagLockRead( pTag ) ) + { + LPTAGINFO pSavedTag = pArea->lpCurTag; + pArea->lpCurTag = pTag; + + hb_ntxTagRefreshScope( pTag ); + if( hb_ntxCurKeyRefresh( pTag ) ) + { + if( fForward ) + hb_ntxTagSkipNext( pTag ); + else + hb_ntxTagSkipPrev( pTag ); + + while( fForward ? !pTag->TagEOF : !pTag->TagBOF ) + { + if( SELF_GOTO( ( AREAP ) pArea, pTag->CurKeyInfo->Xtra ) != SUCCESS ) + break; + if( hb_regexMatch( &RegEx, (const char *) pTag->CurKeyInfo->key, FALSE ) ) + { + ULONG ulRecNo = pArea->ulRecNo; + SELF_SKIPFILTER( ( AREAP ) pArea, fForward ? 1 : -1 ); + if( pArea->ulRecNo == ulRecNo || + hb_regexMatch( &RegEx, (const char *) pTag->CurKeyInfo->key, FALSE ) ) + { + fFound = TRUE; + break; + } + } + if( fForward ) + hb_ntxTagSkipNext( pTag ); + else + hb_ntxTagSkipPrev( pTag ); + } + if( !fFound ) + { + if( fForward ) + SELF_GOTO( ( AREAP ) pArea, 0 ); + else + { + SELF_GOTOP( ( AREAP ) pArea ); + pArea->fBof = TRUE; + } + } + } + pArea->lpCurTag = pSavedTag; + hb_ntxTagUnLockRead( pTag ); + } + + /* Update Bof and Eof flags */ + if( fForward ) + pArea->fBof = FALSE; + else + pArea->fEof = FALSE; + + hb_regexFree( &RegEx ); + + return fFound; +} +#endif + +/* + * add key to custom tag (ordKeyAdd()) + * user key value is not implemented + */ +static BOOL hb_ntxOrdKeyAdd( LPTAGINFO pTag, PHB_ITEM pItem ) +{ + NTXAREAP pArea = pTag->Owner->Owner; + BOOL fResult = FALSE; + LPKEYINFO pKey; + + if( !pTag->Custom || pArea->fEof || ( pTag->pForItem && + !hb_ntxEvalCond( pArea, pTag->pForItem, TRUE ) ) ) + return FALSE; + + if( pTag->Template && pItem && hb_itemType( pItem ) != HB_IT_NIL ) + { + if( pArea->lpdbPendingRel ) + SELF_FORCEREL( ( AREAP ) pArea ); + pKey = hb_ntxKeyPutItem( NULL, pItem, pArea->ulRecNo, pTag, FALSE, NULL ); + } + else + { + pKey = hb_ntxEvalKey( NULL, pTag ); + } + + if( hb_ntxTagLockWrite( pTag ) ) + { + if( hb_ntxTagKeyAdd( pTag, pKey ) ) + { + fResult = TRUE; + if( !pTag->Owner->fShared && pTag->keyCount && + hb_ntxKeyInScope( pTag, pKey ) ) + pTag->keyCount++; + } + hb_ntxTagUnLockWrite( pTag ); } hb_ntxKeyFree( pKey ); - - return bResult; + return fResult; } +/* + * del key from custom tag (ordKeyDel()) + * user key value is not implemented + */ +static BOOL hb_ntxOrdKeyDel( LPTAGINFO pTag, PHB_ITEM pItem ) +{ + NTXAREAP pArea = pTag->Owner->Owner; + BOOL fResult = FALSE; + LPKEYINFO pKey; + + if( !pTag->Custom || pArea->fEof || ( pTag->pForItem && + !hb_ntxEvalCond( pArea, pTag->pForItem, TRUE ) ) ) + return FALSE; + + if( pTag->Template && pItem && hb_itemType( pItem ) != HB_IT_NIL ) + { + if( pArea->lpdbPendingRel ) + SELF_FORCEREL( ( AREAP ) pArea ); + pKey = hb_ntxKeyPutItem( NULL, pItem, pArea->ulRecNo, pTag, FALSE, NULL ); + } + else + { + pKey = hb_ntxEvalKey( NULL, pTag ); + } + + if( hb_ntxTagLockWrite( pTag ) ) + { + if( hb_ntxTagKeyDel( pTag, pKey ) ) + { + fResult = TRUE; + if( !pTag->Owner->fShared && pTag->keyCount && + hb_ntxKeyInScope( pTag, pKey ) ) + pTag->keyCount--; + } + hb_ntxTagUnLockWrite( pTag ); + } + hb_ntxKeyFree( pKey ); + return fResult; +} + +/* + * DBOI_FINDREC find a specific record in the tag - it's useful for + * custom indexes when the same record can be stored more then once + * or when the used index key is unknown + */ +static BOOL hb_ntxOrdFindRec( LPTAGINFO pTag, ULONG ulRecNo, BOOL fCont ) +{ + NTXAREAP pArea = pTag->Owner->Owner; + BOOL fFound = FALSE; + + if( pTag && ulRecNo ) + { + if( pArea->lpdbPendingRel && pArea->lpdbPendingRel->isScoped ) + SELF_FORCEREL( ( AREAP ) pArea ); + + if( hb_ntxTagLockRead( pTag ) ) + { + hb_ntxTagRefreshScope( pTag ); + if( fCont ) + { + if( ! hb_ntxCurKeyRefresh( pTag ) ) + ulRecNo = 0; + else + hb_ntxTagSkipNext( pTag ); + } + else + { + hb_ntxTagGoTop( pTag ); + } + if( ulRecNo ) + { + while( !pTag->TagEOF ) + { + if( pTag->CurKeyInfo->Xtra == ulRecNo ) + { + fFound = TRUE; + break; + } + hb_ntxTagSkipNext( pTag ); + } + } + hb_ntxTagUnLockRead( pTag ); + } + } + SELF_GOTO( ( AREAP ) pArea, fFound ? ulRecNo : 0 ); + return fFound; +} + +/* + * evaluate given C function in given scope + */ +static ULONG hb_ntxOrdScopeEval( LPTAGINFO pTag, + HB_EVALSCOPE_FUNC pFunc, void *pParam, + PHB_ITEM pItemLo, PHB_ITEM pItemHi ) +{ + ULONG ulCount = 0, ulLen = ( ULONG ) pTag->KeyLength; + PHB_ITEM pItemTop = hb_itemNew( NULL ), pItemBottom = hb_itemNew( NULL ); + + hb_ntxTagGetScope( pTag, 0, pItemTop ); + hb_ntxTagGetScope( pTag, 1, pItemBottom ); + hb_ntxTagSetScope( pTag, 0, pItemLo ); + hb_ntxTagSetScope( pTag, 1, pItemHi ); + + if( hb_ntxTagLockRead( pTag ) ) + { + hb_ntxTagGoTop( pTag ); + while( !pTag->TagEOF ) + { + pFunc( pTag->CurKeyInfo->Xtra, (BYTE *) pTag->CurKeyInfo->key, ulLen, pParam ); + ulCount++; + hb_ntxTagSkipNext( pTag ); + } + hb_ntxTagUnLockRead( pTag ); + } + + hb_ntxTagSetScope( pTag, 0, pItemTop ); + hb_ntxTagSetScope( pTag, 1, pItemBottom ); + hb_itemRelease( pItemTop ); + hb_itemRelease( pItemBottom ); + + return ulCount; +} + +/* ************************************************************************* */ +/* create index: hb_ntxTagCreate() */ +/* ************************************************************************* */ + +static int hb_ntxQuickSortCompare( LPNTXSORTINFO pSort, BYTE * pKey1, BYTE * pKey2 ) +{ + int iLen = pSort->keyLen, i; + + i = hb_ntxValCompare( pSort->pTag, (char *) pKey1, iLen, (char *) pKey2, iLen, TRUE ); + if( i == 0 ) + { + if( pSort->pTag->fSortRec ) + i = ( HB_GET_LE_UINT32( pKey1 + iLen ) < HB_GET_LE_UINT32( pKey2 + iLen ) ) ? -1 : 1; + } + else if( ! pSort->pTag->AscendKey ) + { + i = -i; + } + + return i; +} + +static BOOL hb_ntxQSort( LPNTXSORTINFO pSort, BYTE * pSrc, BYTE * pBuf, LONG lKeys ) +{ + if( lKeys > 1 ) + { + int iLen = pSort->keyLen + 4; + LONG l1, l2; + BYTE * pPtr1, * pPtr2, *pDst; + BOOL f1, f2; + + l1 = lKeys >> 1; + l2 = lKeys - l1; + pPtr1 = &pSrc[ 0 ]; + pPtr2 = &pSrc[ l1 * iLen ]; + + f1 = hb_ntxQSort( pSort, pPtr1, &pBuf[ 0 ], l1 ); + f2 = hb_ntxQSort( pSort, pPtr2, &pBuf[ l1 * iLen ], l2 ); + if( f1 ) + { + pDst = pBuf; + } + else + { + pDst = pSrc; + pPtr1 = &pBuf[ 0 ]; + } + if( !f2 ) + { + pPtr2 = &pBuf[ l1 * iLen ]; + } + while( l1 > 0 && l2 > 0 ) + { + if( hb_ntxQuickSortCompare( pSort, pPtr1, pPtr2 ) <= 0 ) + { + memcpy( pDst, pPtr1, iLen ); + pPtr1 += iLen; + l1--; + } + else + { + memcpy( pDst, pPtr2, iLen ); + pPtr2 += iLen; + l2--; + } + pDst += iLen; + } + if( l1 > 0 ) + { + memcpy( pDst, pPtr1, iLen * l1 ); + } + else if( l2 > 0 && f1 == f2 ) + { + memcpy( pDst, pPtr2, iLen * l2 ); + } + return !f1; + } + return TRUE; +} + +static void hb_ntxSortSortPage( LPNTXSORTINFO pSort ) +{ + ULONG ulSize = pSort->ulKeys * ( pSort->keyLen + 4 ); + if( !hb_ntxQSort( pSort, pSort->pKeyPool, &pSort->pKeyPool[ ulSize ], pSort->ulKeys ) ) + { + pSort->pStartKey = &pSort->pKeyPool[ ulSize ]; + } + else + { + pSort->pStartKey = pSort->pKeyPool; + } +} + +static void hb_ntxSortBufferFlush( LPNTXSORTINFO pSort ) +{ + ULONG ulSize; + if( pSort->ulPagesIO ) + { + LPNTXINDEX pIndex = pSort->pTag->Owner; + hb_fsSeekLarge( pIndex->DiskFile, + hb_ntxFileOffset( pIndex, pSort->ulFirstIO ), FS_SET ); + ulSize = pSort->ulPagesIO * NTXBLOCKSIZE; + if( hb_fsWriteLarge( pIndex->DiskFile, pSort->pBuffIO, ulSize ) != ulSize ) + { + hb_ntxErrorRT( pIndex->Owner, EG_WRITE, EDBF_WRITE, + pIndex->IndexName, hb_fsError(), 0 ); + } + pSort->ulPagesIO = 0; + pIndex->fFlush = TRUE; + if( pIndex->fShared ) + pIndex->Changed = TRUE; + } +} + +static void hb_ntxSortStorePage( LPNTXSORTINFO pSort, LPPAGEINFO pPage ) +{ + LPNTXINDEX pIndex = pSort->pTag->Owner; + if( !pPage->Page ) + { + pPage->Page = hb_ntxPageAlloc( pIndex ); + if( pSort->ulSizeIO ) + { + if( pSort->ulPagesIO == pSort->ulSizeIO ) + hb_ntxSortBufferFlush( pSort ); + if( !pSort->ulPagesIO || + hb_ntxFileOffset( pIndex, pSort->ulLastIO ) + NTXBLOCKSIZE == + hb_ntxFileOffset( pIndex, pPage->Page ) ) + { + hb_ntxSetKeyCount( pPage, pPage->uiKeys ); + memcpy( pSort->pBuffIO + pSort->ulPagesIO * NTXBLOCKSIZE, + hb_ntxPageBuffer( pPage ), NTXBLOCKSIZE ); + pSort->ulLastIO = pPage->Page; + if( !pSort->ulPagesIO++ ) + pSort->ulFirstIO = pPage->Page; + pPage->Changed = FALSE; + return; + } + } + } + if( !pPage->pPrev ) + hb_ntxPageSave( pIndex, pPage ); +} + +static void hb_ntxSortAddNodeKey( LPNTXSORTINFO pSort, BYTE *pKeyVal, ULONG ulRec ) +{ + LPPAGEINFO pPage; + ULONG ulPage = 0; + int iLevel = 0; + + do + { + pPage = pSort->NodeList[ iLevel ]; + if( pPage == NULL ) + { + pPage = pSort->NodeList[ iLevel ] = hb_ntxPageNew( pSort->pTag, TRUE ); + break; + } + else if( pPage->uiKeys >= pSort->pTag->MaxKeys ) + { + hb_ntxSetKeyPage( pPage, pPage->uiKeys, ulPage ); + hb_ntxSortStorePage( pSort, pPage ); + ulPage = pPage->Page; + hb_ntxPageRelease( pSort->pTag, pPage ); + pSort->NodeList[ iLevel++ ] = hb_ntxPageNew( pSort->pTag, TRUE ); + } + else + break; + } + while( TRUE ); + + memcpy( hb_ntxGetKeyVal( pPage, pPage->uiKeys ), pKeyVal, pSort->pTag->KeyLength ); + hb_ntxSetKeyRec( pPage, pPage->uiKeys, ulRec ); + hb_ntxSetKeyPage( pPage, pPage->uiKeys, ulPage ); + pPage->uiKeys++; +} + +static void hb_ntxSortWritePage( LPNTXSORTINFO pSort ) +{ + ULONG ulSize = pSort->ulKeys * ( pSort->keyLen + 4 ); + + hb_ntxSortSortPage( pSort ); + + if( pSort->hTempFile == FS_ERROR ) + { + BYTE szName[ _POSIX_PATH_MAX + 1 ]; + pSort->hTempFile = hb_fsCreateTemp( NULL, NULL, FC_NORMAL, szName ); + if( pSort->hTempFile == FS_ERROR ) + { + hb_errInternal( 9999, "hb_ntxSortWritePage: Can't create temporary file.", "", "" ); + } + pSort->szTempFileName = hb_strdup( ( char * ) szName ); + } + pSort->pSwapPage[ pSort->ulCurPage ].ulKeys = pSort->ulKeys; + pSort->pSwapPage[ pSort->ulCurPage ].nOffset = hb_fsSeekLarge( pSort->hTempFile, 0, FS_END ); + if( hb_fsWriteLarge( pSort->hTempFile, pSort->pStartKey, ulSize ) != ulSize ) + { + hb_errInternal( 9999, "hb_ntxSortWritePage: Write error in temporary file.", "", "" ); + } + pSort->ulKeys = 0; + pSort->ulCurPage++; +} + +static void hb_ntxSortGetPageKey( LPNTXSORTINFO pSort, ULONG ulPage, + BYTE ** pKeyVal, ULONG *pulRec ) +{ + int iLen = pSort->keyLen; + + if( pSort->pSwapPage[ ulPage ].ulKeyBuf == 0 ) + { + ULONG ulKeys = HB_MIN( pSort->ulPgKeys, pSort->pSwapPage[ ulPage ].ulKeys ); + ULONG ulSize = ulKeys * ( iLen + 4 ); + + if( hb_fsSeekLarge( pSort->hTempFile, pSort->pSwapPage[ ulPage ].nOffset, FS_SET ) != pSort->pSwapPage[ ulPage ].nOffset || + hb_fsReadLarge( pSort->hTempFile, pSort->pSwapPage[ ulPage ].pKeyPool, ulSize ) != ulSize ) + { + hb_errInternal( 9999, "hb_ntxSortGetPageKey: Read error from temporary file.", "", "" ); + } + pSort->pSwapPage[ ulPage ].nOffset += ulSize; + pSort->pSwapPage[ ulPage ].ulKeyBuf = ulKeys; + pSort->pSwapPage[ ulPage ].ulCurKey = 0; + } + *pKeyVal = &pSort->pSwapPage[ ulPage ].pKeyPool[ pSort->pSwapPage[ ulPage ].ulCurKey * ( iLen + 4 ) ]; + *pulRec = HB_GET_LE_UINT32( *pKeyVal + iLen ); +} + +static void hb_ntxSortOrderPages( LPNTXSORTINFO pSort ) +{ + int iLen = pSort->keyLen, i; + LONG l, r, m; + ULONG n, ulPage, ulRec; + BYTE *pKey = NULL, *pTmp; + + pSort->ulFirst = 0; + pSort->pSortedPages = ( ULONG * ) hb_xgrab( pSort->ulPages * sizeof( ULONG ) ); + pSort->pSortedPages[ 0 ] = 0; + + if( pSort->ulTotKeys > 0 ) + { + for( n = 0; n < pSort->ulPages; n++ ) + { + hb_ntxSortGetPageKey( pSort, n, &pKey, &ulRec ); + l = 0; + r = n - 1; + while( l <= r ) + { + m = ( l + r ) >> 1; + ulPage = pSort->pSortedPages[ m ]; + pTmp = &pSort->pSwapPage[ ulPage ].pKeyPool[ pSort->pSwapPage[ ulPage ].ulCurKey * ( iLen + 4 ) ]; + i = hb_ntxValCompare( pSort->pTag, (char *) pKey, iLen, (char *) pTmp, iLen, TRUE ); + if( i == 0 ) + { + if( pSort->pTag->fSortRec ) + i = ( ulRec < HB_GET_LE_UINT32( &pTmp[ iLen ] ) ) ? -1 : 1; + } + else if( ! pSort->pTag->AscendKey ) + i = -i; + if( i >= 0 ) + l = m + 1; + else + r = m - 1; + } + for( r = n; r > l; r-- ) + pSort->pSortedPages[ r ] = pSort->pSortedPages[ r - 1 ]; + pSort->pSortedPages[ l ] = n; + } + } +} + +static BOOL hb_ntxSortKeyGet( LPNTXSORTINFO pSort, BYTE ** pKeyVal, ULONG *pulRec ) +{ + int iLen = pSort->keyLen, i; + LONG l, r, m; + ULONG ulPage; + + ulPage = pSort->pSortedPages[ pSort->ulFirst ]; + + /* check if first page has some keys yet */ + if( pSort->pSwapPage[ ulPage ].ulKeys > 0 ) + { + BYTE *pKey, *pTmp; + ULONG ulRec, ulPg; + + /* + * last key was taken from this page - we have to resort it. + * This is done intentionally here to be sure that the key + * value return by this function will not be overwritten by + * next keys in page read from temporary file in function + * hb_ntxSortGetPageKey() - please do not move this part down + * even it seems to be correct + */ + hb_ntxSortGetPageKey( pSort, ulPage, &pKey, &ulRec ); + + l = pSort->ulFirst + 1; + r = pSort->ulPages - 1; + while( l <= r ) + { + m = ( l + r ) >> 1; + ulPg = pSort->pSortedPages[ m ]; + pTmp = &pSort->pSwapPage[ ulPg ].pKeyPool[ pSort->pSwapPage[ ulPg ].ulCurKey * ( iLen + 4 ) ]; + i = hb_ntxValCompare( pSort->pTag, (char *) pKey, iLen, (char *) pTmp, iLen, TRUE ); + if( i == 0 ) + { + if( pSort->pTag->fSortRec ) + i = ( ulRec < HB_GET_LE_UINT32( &pTmp[ iLen ] ) ) ? -1 : 1; + else + i = ( ulPage < ulPg ) ? -1 : 1; + } + else if( ! pSort->pTag->AscendKey ) + i = -i; + if( i > 0 ) + l = m + 1; + else + r = m - 1; + } + if( l > ( LONG ) pSort->ulFirst + 1 ) + { + ulPage = pSort->pSortedPages[ pSort->ulFirst ]; + for( r = pSort->ulFirst + 1; r < l; r++ ) + pSort->pSortedPages[ r - 1 ] = pSort->pSortedPages[ r ]; + pSort->pSortedPages[ l - 1 ] = ulPage; + } + } + else + { + pSort->ulFirst++; + } + if( pSort->ulFirst < pSort->ulPages ) + { + ulPage = pSort->pSortedPages[ pSort->ulFirst ]; + hb_ntxSortGetPageKey( pSort, ulPage, pKeyVal, pulRec ); + pSort->pSwapPage[ ulPage ].ulCurKey++; + pSort->pSwapPage[ ulPage ].ulKeys--; + pSort->pSwapPage[ ulPage ].ulKeyBuf--; + return TRUE; + } + return FALSE; +} + +static void hb_ntxSortKeyAdd( LPNTXSORTINFO pSort, ULONG ulRec, char * pKeyVal, int iKeyLen ) +{ + int iLen = pSort->keyLen; + BYTE *pDst; + + if( pSort->ulKeys >= pSort->ulPgKeys ) + { + hb_ntxSortWritePage( pSort ); + } + pDst = &pSort->pKeyPool[ pSort->ulKeys * ( iLen + 4 ) ]; + + if( iLen > iKeyLen ) + { + memcpy( pDst, pKeyVal, iKeyLen ); + memset( &pDst[ iKeyLen ], ' ', iLen - iKeyLen ); + } + else + { + memcpy( pDst, pKeyVal, iLen ); + } + HB_PUT_LE_UINT32( &pDst[ iLen ], ulRec ); + pSort->ulKeys++; + pSort->ulTotKeys++; +} + +static LPNTXSORTINFO hb_ntxSortNew( LPTAGINFO pTag, ULONG ulRecCount ) +{ + LPNTXSORTINFO pSort; + BYTE * pBuf; + int iLen = pTag->KeyLength; + ULONG ulSize, ulMax, ulMin; + + if( ulRecCount == 0 ) + ulRecCount = 1; + + pSort = ( LPNTXSORTINFO ) hb_xgrab( sizeof( NTXSORTINFO ) ); + memset( pSort, 0, sizeof( NTXSORTINFO ) ); + + ulMin = ( ULONG ) ceil( sqrt( ( double ) ulRecCount ) ); + ulMax = ( ( ULONG ) ceil( sqrt( ( double ) ulRecCount / ( iLen + 4 ) ) ) ) << 7; + /* + * this effectively increase allocated memory buffer for very large files + * moving the maximum to: 270'566'400 for 4'294'967'295 records and 256 + * index key length. + * if you want to force smaller buffer I wrote below then add here: + * ulMax = ulMin; + */ + ulSize = ( 1L << 20 ) / ( iLen + 4 ); + while( ulMax < ulSize ) + ulMax <<= 1; + if( ulMax > ulRecCount ) + ulMax = ulRecCount; + + do + { + ulSize = ulMax * ( iLen + 4 ); + pBuf = ( BYTE * ) hb_xalloc( ulSize << 2 ); + if( pBuf ) + { + hb_xfree( pBuf ); + pBuf = ( BYTE * ) hb_xalloc( ulSize << 1 ); + } + else + { + ulMax >>= 1; + } + } + while( ! pBuf && ulMax >= ulMin ); + + if( ! pBuf ) + { + /* call hb_xgrab() to force out of memory error, + * though in multi process environment this call may return + * with success when other process free some memory + * (also the size of buf is reduced to absolute minimum). + * Sorry but I'm to lazy to implement indexing with smaller + * memory though it's possible - just simply I can even create + * index on-line by key adding like in normal update process. + * The memory necessary to index file is now ~ + * ~ (keySize+4+sizeof(NTXSWAPPAGE)) * sqrt(ulRecCount) * 2 + * so the maximum is for DBF with 2^32 records and keySize 256 ~ + * ~ 2^17 * 284 ~=~ 37 Mb + * this is not a problem for current computers and I do not see + * any way to use DBFs with four billions records and indexes with + * such long (256 bytes) keys on the old ones - they will be simply + * to slow. IMHO it's also better to signal out of memory here and + * force some system upgrades then run process which will have to + * take many hours, Druzus. + */ + ulMax = ulMin; + pBuf = ( BYTE * ) hb_xgrab( ( ulMax << 1 ) * ( iLen + 4 ) ); + } + + pSort->pTag = pTag; + pSort->hTempFile = FS_ERROR; + pSort->keyLen = iLen; + pSort->fUnique = pTag->UniqueKey; + pSort->ulMaxKey = ulMax << 1; + pSort->ulPgKeys = ulMax; + pSort->ulMaxRec = ulRecCount; + pSort->pKeyPool = pBuf; + pSort->ulPages = ( ulRecCount + pSort->ulPgKeys - 1 ) / pSort->ulPgKeys; + /* check for overflow on 32 bit machines when number of records is nearly 2^32 */ + if( !pSort->ulPages ) + pSort->ulPages = ulRecCount / pSort->ulPgKeys + 1; + pSort->pSwapPage = ( LPNTXSWAPPAGE ) hb_xgrab( sizeof( NTXSWAPPAGE ) * pSort->ulPages ); + memset( pSort->pSwapPage, 0, sizeof( NTXSWAPPAGE ) * pSort->ulPages ); + return pSort; +} + +static void hb_ntxSortFree( LPNTXSORTINFO pSort, BOOL fFull ) +{ + if( pSort->hTempFile != FS_ERROR ) + { + hb_fsClose( pSort->hTempFile ); + pSort->hTempFile = FS_ERROR; + } + if( pSort->szTempFileName ) + { + hb_fsDelete( ( BYTE * ) pSort->szTempFileName ); + hb_xfree( pSort->szTempFileName ); + pSort->szTempFileName = NULL; + } + if( pSort->pKeyPool ) + { + hb_xfree( pSort->pKeyPool ); + pSort->pKeyPool = NULL; + } + if( pSort->pSwapPage ) + { + hb_xfree( pSort->pSwapPage ); + pSort->pSwapPage = NULL; + } + if( pSort->pBuffIO ) + { + hb_xfree( pSort->pBuffIO ); + pSort->pBuffIO = NULL; + } + if( pSort->pSortedPages ) + { + hb_xfree( pSort->pSortedPages ); + pSort->pSortedPages = NULL; + } + if( fFull ) + { + hb_xfree( pSort ); + } +} + +static void hb_ntxSortOut( LPNTXSORTINFO pSort ) +{ + BOOL fUnique = pSort->fUnique, fBalance, fNext; + LPTAGINFO pTag = pSort->pTag; + ULONG ulPage, ulRec, ulKey; + USHORT uiHalf; + BYTE * pKeyVal; + int iLen = pSort->keyLen, iLevel; + + pSort->ulPages = pSort->ulCurPage + 1; + pSort->ulPgKeys = pSort->ulMaxKey / pSort->ulPages; + if( pSort->ulPages > 1 ) + { + BYTE * pBuf = pSort->pKeyPool; + hb_ntxSortWritePage( pSort ); + for( ulPage = 0; ulPage < pSort->ulPages; ulPage++ ) + { + pSort->pSwapPage[ ulPage ].ulKeyBuf = 0; + pSort->pSwapPage[ ulPage ].ulCurKey = 0; + pSort->pSwapPage[ ulPage ].pKeyPool = pBuf; + pBuf += pSort->ulPgKeys * ( pSort->keyLen + 4 ); + } + } + else + { + hb_ntxSortSortPage( pSort ); + pSort->pSwapPage[ 0 ].ulKeys = pSort->ulKeys; + pSort->pSwapPage[ 0 ].ulKeyBuf = pSort->ulKeys; + pSort->pSwapPage[ 0 ].ulCurKey = 0; + pSort->pSwapPage[ 0 ].pKeyPool = pSort->pStartKey; + } + /* printf("pSort->ulPages=%ld, pSort->ulPgKeys=%ld", pSort->ulPages, pSort->ulPgKeys);fflush(stdout); */ + + hb_ntxSortOrderPages( pSort ); + + for( ulKey = 0; ulKey < pSort->ulTotKeys; ulKey++ ) + { + if( ! hb_ntxSortKeyGet( pSort, &pKeyVal, &ulRec ) ) + { + hb_errInternal( 9999, "hb_ntxSortOut: memory structure corrupted.", "", "" ); + } + if( fUnique ) + { + if( ulKey != 0 && hb_ntxValCompare( pTag, (char *) pSort->pLastKey, iLen, (char *) pKeyVal, iLen, TRUE ) == 0 ) + { + continue; + } +#ifndef HB_NTX_DEBUG_EXT + else + { + memcpy( pSort->pLastKey, pKeyVal, iLen ); + } +#endif + } +#ifdef HB_NTX_DEBUG_EXT + if( ulKey != 0 ) + { + int i = hb_ntxValCompare( pTag, (char *) pSort->pLastKey, iLen, (char *) pKeyVal, iLen, TRUE ); + if( ! pTag->AscendKey ) + i = -i; + if( i == 0 ) + i = ( pSort->ulLastRec < ulRec ) ? -1 : 1; + if( i > 0 ) + { + printf("\r\nulKey=%ld, pKeyVal=[%s][%ld], pKeyLast=[%s][%ld]\r\n", + ulKey, pKeyVal, ulRec, pSort->pLastKey, pSort->ulLastRec); fflush(stdout); + hb_errInternal( 9999, "hb_ntxSortOut: sorting fails.", "", "" ); + } + } + memcpy( pSort->pLastKey, pKeyVal, iLen ); + pSort->ulLastRec = ulRec; +#endif + hb_ntxSortAddNodeKey( pSort, pKeyVal, ulRec ); + } + +#ifdef HB_NTX_DEBUG + if( hb_ntxSortKeyGet( pSort, &pKeyVal, &ulRec ) ) + { + hb_errInternal( 9999, "hb_ntxSortOut: memory structure corrupted(2).", "", "" ); + } +#endif + + if( pSort->NodeList[ 0 ] == NULL ) + { + pSort->NodeList[ 0 ] = hb_ntxPageNew( pTag, TRUE ); + } + hb_ntxSetKeyPage( pSort->NodeList[ 0 ], pSort->NodeList[ 0 ]->uiKeys, 0 ); + + iLevel = 0; + fNext = TRUE; + fBalance = FALSE; + uiHalf = pTag->MaxKeys >> 1; + do + { + hb_ntxSortStorePage( pSort, pSort->NodeList[ iLevel ] ); + if( iLevel + 1 == NTX_STACKSIZE || pSort->NodeList[ iLevel + 1 ] == NULL ) + { + pTag->RootBlock = pSort->NodeList[ iLevel ]->Page; + fNext = FALSE; + } + else + { + hb_ntxSetKeyPage( pSort->NodeList[ iLevel + 1 ], + pSort->NodeList[ iLevel + 1 ]->uiKeys, + pSort->NodeList[ iLevel ]->Page ); + if( pSort->NodeList[ iLevel ]->uiKeys < uiHalf ) + { + fBalance = TRUE; + } + } + hb_ntxPageRelease( pTag, pSort->NodeList[ iLevel ] ); + iLevel++; + } + while( fNext ); + + hb_ntxSortBufferFlush( pSort ); + hb_ntxSortFree( pSort, FALSE ); + + if( fBalance ) + { + LPPAGEINFO pPage, pFirst, pLast; + + ulPage = pTag->RootBlock; + while( ulPage ) + { + pPage = hb_ntxPageLoad( pTag, ulPage ); + if( ! pPage ) + return; + ulPage = hb_ntxGetKeyPage( pPage, pPage->uiKeys ); + if( ulPage && pPage->uiKeys ) + { + pLast = hb_ntxPageLoad( pTag, ulPage ); + if( ! pLast ) + { + hb_ntxPageRelease( pTag, pPage ); + return; + } + if( pLast->uiKeys < uiHalf ) + { + pFirst = hb_ntxPageLoad( pTag, hb_ntxGetKeyPage( pPage, + pPage->uiKeys - 1 ) ); + if( ! pFirst ) + { + hb_ntxPageRelease( pTag, pPage ); + hb_ntxPageRelease( pTag, pLast ); + return; + } + hb_ntxBalancePages( pTag, pPage, pPage->uiKeys - 1, pFirst, pLast ); + hb_ntxPageRelease( pTag, pFirst ); + } + hb_ntxPageRelease( pTag, pLast ); + } + hb_ntxPageRelease( pTag, pPage ); + } + } +} + +/* + * create tag in index file + */ +static ERRCODE hb_ntxTagCreate( LPTAGINFO pTag, BOOL fReindex ) +{ + LPNTXAREA pArea = pTag->Owner->Owner; + PHB_ITEM pForItem, pWhileItem = NULL, pEvalItem = NULL, pItem = NULL; + ULONG ulRecCount, ulRecNo = pArea->ulRecNo; + LPNTXSORTINFO pSort; + LONG lStep = 0; + ERRCODE errCode = SUCCESS; + + if( pArea->lpdbOrdCondInfo ) + { + pWhileItem = pArea->lpdbOrdCondInfo->itmCobWhile; + lStep = pArea->lpdbOrdCondInfo->lStep; + pEvalItem = pArea->lpdbOrdCondInfo->itmCobEval; + } + + if( pTag->Custom ) + { + ulRecCount = 0; + } + else + { + errCode = SELF_RECCOUNT( ( AREAP ) pArea, &ulRecCount ); + if( errCode != SUCCESS ) + return errCode; + } + pArea->pSort = pSort = hb_ntxSortNew( pTag, ulRecCount ); + pSort->fReindex = fReindex; + + if( ulRecCount == 0 ) + { + LPPAGEINFO pPage = hb_ntxPageNew( pTag, FALSE ); + + if( pPage ) + { + pTag->RootBlock = pPage->Page; + hb_ntxPageRelease( pTag, pPage ); + } + else + { + errCode = FAILURE; + } + } + else + { + LPTAGINFO pSaveTag = pArea->lpCurTag; + ULONG ulStartRec = 0, ulNextCount = 0; + BOOL fDirectRead, fUseFilter = FALSE; + BYTE * pSaveRecBuff = pArea->pRecord; + char szBuffer[ NTX_MAX_KEY ]; + int iRecBuff = 0, iRecBufSize, iRec; +#ifndef HB_CDP_SUPPORT_OFF + /* TODO%: this hack is not thread safe, hb_cdp_page has to be thread specific */ + PHB_CODEPAGE cdpTmp = hb_cdp_page; + hb_cdp_page = pArea->cdPage; +#endif + + pForItem = pTag->pForItem; + if( pTag->nField ) + pItem = hb_itemNew( NULL ); + + if( !pArea->lpdbOrdCondInfo || pArea->lpdbOrdCondInfo->fAll ) + { + pArea->lpCurTag = NULL; + } + else + { + if( pArea->lpdbOrdCondInfo->itmRecID ) + ulStartRec = hb_itemGetNL( pArea->lpdbOrdCondInfo->itmRecID ); + if ( ulStartRec ) + { + ulNextCount = 1; + } + else if( pArea->lpdbOrdCondInfo->fRest || pArea->lpdbOrdCondInfo->lNextCount > 0 ) + { + if( pArea->lpdbOrdCondInfo->itmStartRecID ) + ulStartRec = hb_itemGetNL( pArea->lpdbOrdCondInfo->itmStartRecID ); + if( !ulStartRec ) + ulStartRec = ulRecNo; + if( pArea->lpdbOrdCondInfo->lNextCount > 0 ) + ulNextCount = pArea->lpdbOrdCondInfo->lNextCount; + } + else if( pArea->lpdbOrdCondInfo->fUseFilter ) + { + fUseFilter = TRUE; + } + else if( !pArea->lpdbOrdCondInfo->fUseCurrent ) + { + pArea->lpCurTag = NULL; + } + } + + fDirectRead = !hb_set.HB_SET_STRICTREAD && /* !pArea->lpdbRelations && */ + ( !pArea->lpdbOrdCondInfo || pArea->lpdbOrdCondInfo->fAll || + ( pArea->lpCurTag == NULL && !fUseFilter ) ); + + pSort->ulSizeIO = ( 1 << 16 ) / NTXBLOCKSIZE; + pSort->pBuffIO = (BYTE *) hb_xgrab( pSort->ulSizeIO * NTXBLOCKSIZE ); + iRecBufSize = ( pSort->ulSizeIO * NTXBLOCKSIZE ) / pArea->uiRecordLen; + + if( ulStartRec == 0 && pArea->lpCurTag == NULL ) + ulStartRec = 1; + + if( ulStartRec == 0 ) + { + errCode = SELF_GOTOP( ( AREAP ) pArea ); + } + else + { + errCode = SELF_GOTO( ( AREAP ) pArea, ulStartRec ); + if( fUseFilter && errCode == SUCCESS ) + errCode = SELF_SKIPFILTER( ( AREAP ) pArea, 1 ); + } + + ulRecNo = pArea->ulRecNo; + + if( ulNextCount && ulRecCount >= ulRecNo + ulNextCount ) + ulRecCount = ulRecNo + ulNextCount - 1; + + while( errCode == SUCCESS ) + { + if( ulRecNo > ulRecCount ) + pArea->fEof = TRUE; + + if( pArea->fEof ) + break; + + if( fDirectRead ) + { + if( iRecBuff == 0 || iRecBuff >= iRecBufSize ) + { + if( ulRecCount - ulRecNo >= (ULONG) iRecBufSize ) + iRec = iRecBufSize; + else + iRec = ulRecCount - ulRecNo + 1; + if( iRec <= 0 ) + break; + hb_fsSeekLarge( pArea->hDataFile, + ( HB_FOFFSET ) pArea->uiHeaderLen + + ( HB_FOFFSET ) ( ulRecNo - 1 ) * + ( HB_FOFFSET ) pArea->uiRecordLen, FS_SET ); + hb_fsReadLarge( pArea->hDataFile, pSort->pBuffIO, pArea->uiRecordLen * iRec ); + iRecBuff = 0; + } + pArea->pRecord = pSort->pBuffIO + iRecBuff * pArea->uiRecordLen; + pArea->fValidBuffer = TRUE; + pArea->ulRecNo = ulRecNo; + pArea->fDeleted = ( pArea->pRecord[ 0 ] == '*' ); + /* Force relational movement in child WorkAreas */ + if( pArea->lpdbRelations ) + { + errCode = SELF_SYNCCHILDREN( ( AREAP ) pArea ); + if( errCode != SUCCESS ) + break; + } + iRecBuff++; + } + + if( pWhileItem && !hb_ntxEvalCond( NULL, pWhileItem, FALSE ) ) + break; + + if( pForItem == NULL || hb_ntxEvalCond( pArea, pForItem, FALSE ) ) + { + if( pTag->nField ) + errCode = SELF_GETVALUE( ( AREAP ) pArea, pTag->nField, pItem ); + else + pItem = hb_vmEvalBlockOrMacro( pTag->pKeyItem ); + + switch( hb_itemType( pItem ) ) + { + case HB_IT_STRING: + case HB_IT_STRING | HB_IT_MEMO: + hb_ntxSortKeyAdd( pSort, pArea->ulRecNo, + pItem->item.asString.value, + pItem->item.asString.length ); + break; + + case HB_IT_INTEGER: + case HB_IT_LONG: + case HB_IT_DOUBLE: + hb_ntxNumToStr( pItem, szBuffer, pTag->KeyLength, pTag->KeyDec ); + hb_ntxSortKeyAdd( pSort, pArea->ulRecNo, szBuffer, pTag->KeyLength ); + break; + + case HB_IT_DATE: + hb_itemGetDS( pItem, szBuffer ); + hb_ntxSortKeyAdd( pSort, pArea->ulRecNo, szBuffer, 8 ); + break; + + case HB_IT_LOGICAL: + szBuffer[0] = hb_itemGetL( pItem ) ? 'T' : 'F'; + hb_ntxSortKeyAdd( pSort, pArea->ulRecNo, szBuffer, 1 ); + break; + + default: + hb_ntxErrorRT( pArea, EG_DATATYPE, EDBF_INVALIDKEY, + pTag->Owner->IndexName, 0, 0 ); + errCode = FAILURE; + pTag->Partial = TRUE; + pEvalItem = NULL; + ulNextCount = 1; + break; + } + } + + if( ulNextCount > 0 ) + { + if( --ulNextCount == 0 ) + break; + } + + if( pEvalItem ) + { + if( lStep >= pArea->lpdbOrdCondInfo->lStep ) + { + lStep = 0; + if( !hb_ntxEvalCond( pArea, pEvalItem, FALSE ) ) + { + pTag->Partial = TRUE; + break; + } + } + ++lStep; + } + + if( fDirectRead ) + ulRecNo++; + else if( errCode == SUCCESS ) + { + errCode = SELF_SKIPRAW( ( AREAP ) pArea, 1 ); + if( fUseFilter && errCode == SUCCESS ) + errCode = SELF_SKIPFILTER( ( AREAP ) pArea, 1 ); + ulRecNo = pArea->ulRecNo; + } + } + + if( fDirectRead ) + { + pArea->pRecord = pSaveRecBuff; + pArea->fValidBuffer = FALSE; + if( errCode == SUCCESS ) + errCode = SELF_GOTO( ( AREAP ) pArea, ulRecNo ); + } + + if( errCode == SUCCESS ) + hb_ntxSortOut( pSort ); + + if( pTag->nField ) + hb_itemRelease( pItem ); + + pArea->lpCurTag = pSaveTag; +#ifndef HB_CDP_SUPPORT_OFF + hb_cdp_page = cdpTmp; +#endif + } + + hb_ntxSortFree( pSort, TRUE ); + pArea->pSort = NULL; + + return errCode; +} + +/* + * recreate tags in index file + */ +static ERRCODE hb_ntxReIndex( LPNTXINDEX pIndex ) +{ + ERRCODE errCode = FAILURE; + int i; + + if( hb_ntxIndexLockWrite( pIndex, FALSE ) ) + { + errCode = SUCCESS; + hb_ntxIndexTrunc( pIndex ); + + for( i = 0; i < pIndex->iTags; i++ ) + { + LPTAGINFO pTag = pIndex->lpTags[ i ]; + pTag->HeadBlock = pTag->RootBlock = pTag->keyCount = 0; + pTag->HdrChanged = TRUE; + errCode = hb_ntxTagCreate( pTag, TRUE ); + if( errCode != SUCCESS ) + break; + } + hb_ntxIndexUnLockWrite( pIndex ); + } + return errCode; +} + + +/* ************************************************************************* */ + /* Implementation of exported functions */ static ERRCODE ntxGoBottom( NTXAREAP pArea ) { + ERRCODE retval; + HB_TRACE(HB_TR_DEBUG, ("ntxGoBottom(%p)", pArea)); if( SELF_GOCOLD( ( AREAP ) pArea ) == FAILURE ) return FAILURE; - if ( !pArea->lpCurTag || !pArea->lpNtxTag ) - SUPER_GOBOTTOM( ( AREAP ) pArea ); + + if( !pArea->lpCurTag ) + return SUPER_GOBOTTOM( ( AREAP ) pArea ); + + if( pArea->lpdbPendingRel && pArea->lpdbPendingRel->isScoped ) + SELF_FORCEREL( ( AREAP ) pArea ); + + if( ! hb_ntxTagLockRead( pArea->lpCurTag ) ) + return FAILURE; + hb_ntxTagRefreshScope( pArea->lpCurTag ); + + hb_ntxTagGoBottom( pArea->lpCurTag ); + + pArea->fTop = FALSE; + pArea->fBottom = TRUE; + + if( pArea->lpCurTag->TagEOF ) + retval = SELF_GOTO( ( AREAP ) pArea, 0 ); else { - LPTAGINFO pTag; - - pTag = pArea->lpCurTag; - if( pTag->bottomScope ) - { - ntxSeek( pArea, TRUE, pTag->bottomScope, TRUE ); - if ( pArea->fEof ) - return SUCCESS; - } - else - hb_ntxTagKeyGoTo( pTag, BTTM_RECORD, NULL ); - SELF_GOTO( ( AREAP ) pArea, pTag->CurKeyInfo->Xtra ); + retval = SELF_GOTO( ( AREAP ) pArea, pArea->lpCurTag->CurKeyInfo->Xtra ); + if( retval != FAILURE && pArea->fPositioned ) + retval = SELF_SKIPFILTER( ( AREAP ) pArea, -1 ); } - return SELF_SKIPFILTER( ( AREAP ) pArea, -1 ); -} + hb_ntxTagUnLockRead( pArea->lpCurTag ); -static ERRCODE ntxGoTo( NTXAREAP pArea, ULONG ulRecNo ) -{ - HB_TRACE(HB_TR_DEBUG, ("ntxGoTo(%p, %lu)", pArea, ulRecNo)); - if( pArea->lpCurTag && - (ULONG)pArea->lpCurTag->CurKeyInfo->Xtra != ulRecNo ) - { - pArea->lpCurTag->CurKeyInfo->Tag = 0; - pArea->lpCurTag->CurKeyInfo->Xtra = 0; - pArea->lpCurTag->TagBOF = FALSE; - pArea->lpCurTag->TagEOF = FALSE; - } - return SUPER_GOTO( ( AREAP ) pArea,ulRecNo ); + return retval; } static ERRCODE ntxGoTop( NTXAREAP pArea ) { + ERRCODE retval; + HB_TRACE(HB_TR_DEBUG, ("ntxGoTop(%p)", pArea)); if( SELF_GOCOLD( ( AREAP ) pArea ) == FAILURE ) return FAILURE; - if ( !pArea->lpCurTag || !pArea->lpNtxTag ) - SUPER_GOTOP( ( AREAP ) pArea ); + + if( !pArea->lpCurTag ) + return SUPER_GOTOP( ( AREAP ) pArea ); + + if( pArea->lpdbPendingRel && pArea->lpdbPendingRel->isScoped ) + SELF_FORCEREL( ( AREAP ) pArea ); + + if( ! hb_ntxTagLockRead( pArea->lpCurTag ) ) + return FAILURE; + hb_ntxTagRefreshScope( pArea->lpCurTag ); + + hb_ntxTagGoTop( pArea->lpCurTag ); + + pArea->fTop = TRUE; + pArea->fBottom = FALSE; + + if( pArea->lpCurTag->TagEOF ) + retval = SELF_GOTO( ( AREAP ) pArea, 0 ); else { - LPTAGINFO pTag = pArea->lpCurTag; - - if( pTag->topScope ) - { - ntxSeek( pArea, TRUE, pTag->topScope, FALSE ); - if( pTag->TagEOF ) - { - hb_ntxGoEof( pArea ); - return SUCCESS; - } - } - else - hb_ntxTagKeyGoTo( pTag, TOP_RECORD, NULL ); - SELF_GOTO( ( AREAP ) pArea, pTag->CurKeyInfo->Xtra ); + retval = SELF_GOTO( ( AREAP ) pArea, pArea->lpCurTag->CurKeyInfo->Xtra ); + if( retval != FAILURE && pArea->fPositioned ) + retval = SELF_SKIPFILTER( ( AREAP ) pArea, 1 ); } - return SELF_SKIPFILTER( ( AREAP ) pArea, 1 ); + hb_ntxTagUnLockRead( pArea->lpCurTag ); + + return retval; } -static ERRCODE ntxSeek( NTXAREAP pArea, BOOL bSoftSeek, PHB_ITEM pKey, BOOL bFindLast ) +static ERRCODE ntxSeek( NTXAREAP pArea, BOOL fSoftSeek, PHB_ITEM pItem, BOOL fFindLast ) { - ERRCODE retvalue = 0xFFFF; - BOOL result; - HB_TRACE(HB_TR_DEBUG, ("ntxSeek(%p, %d, %p, %d)", pArea, bSoftSeek, pKey, bFindLast)); + HB_TRACE(HB_TR_DEBUG, ("ntxSeek(%p, %d, %p, %d)", pArea, fSoftSeek, pItem, fFindLast)); if( SELF_GOCOLD( ( AREAP ) pArea ) == FAILURE ) return FAILURE; - if ( ! pArea->lpCurTag ) + + if( ! pArea->lpCurTag ) { - commonError( pArea, EG_NOORDER, 1201, NULL, EF_CANDEFAULT ); - return FAILURE; + hb_ntxErrorRT( pArea, EG_NOORDER, EDBF_NOTINDEXED, NULL, 0, EF_CANDEFAULT ); + return FAILURE; } else { - LONG lRecno; - LPKEYINFO pKey2; - LPTAGINFO pTag; - char szBuffer[ NTX_MAX_KEY ]; - int keylen; + LPKEYINFO pKey; + ERRCODE retval = SUCCESS; + BOOL fEOF = FALSE, fLast; + USHORT uiLen; + ULONG ulRec; - pTag = pArea->lpCurTag; - pKey2 = hb_ntxKeyNew( NULL,pTag->KeyLength ); - keylen = (int)pTag->KeyLength; - switch( hb_itemType( pKey ) ) - { - case HB_IT_STRING: - if( pKey->item.asString.length == 0 ) - { - hb_ntxKeyFree( pKey2 ); - retvalue = SELF_GOTOP( ( AREAP ) pArea ); - pArea->fFound = TRUE; - return retvalue; - } - keylen = ( ((USHORT)pKey->item.asString.length)KeyLength)? pKey->item.asString.length:pTag->KeyLength; - memcpy( pKey2->key, pKey->item.asString.value, keylen ); -#ifndef HB_CDP_SUPPORT_OFF - hb_cdpnTranslate( pKey2->key, hb_cdp_page, pArea->cdPage, keylen ); -#endif - break; - case HB_IT_INTEGER: - case HB_IT_LONG: - case HB_IT_DOUBLE: - strncpy( pKey2->key, numToStr( pKey, szBuffer, pTag->KeyLength, pTag->KeyDec ),pTag->KeyLength ); - break; - case HB_IT_DATE: - hb_itemGetDS( pKey, szBuffer ); - strcpy( pKey2->key,szBuffer ); - break; - case HB_IT_LOGICAL: - szBuffer[0] = ( hb_itemGetL( pKey ) ? 'T' : 'F' ); - szBuffer[1] = 0; - strcpy( pKey2->key, szBuffer ); - break; - } - pKey2->key[ keylen ] = '\0'; - if( !hb_ntxInTopScope( pTag, pKey2->key ) || - !hb_ntxInBottomScope( pTag, pKey2->key ) ) - { - hb_ntxKeyFree( pKey2 ); - return hb_ntxGoEof( pArea ); - } - pKey2->Xtra = 0; + if( pArea->lpdbPendingRel && pArea->lpdbPendingRel->isScoped ) + SELF_FORCEREL( ( AREAP ) pArea ); - if( pArea->fShared && !pTag->Memory ) - { - while( !hb_fsLock( pArea->lpCurTag->Owner->DiskFile, NTX_LOCK_OFFSET, 1, FL_LOCK | FLX_SHARED | FLX_WAIT ) ); - pArea->lpCurTag->Owner->Locked = TRUE; - } - lRecno = hb_ntxTagKeyFind( pTag, pKey2, keylen, &result, bSoftSeek ); - if( bFindLast && lRecno > 0 && result ) - { - LONG lRecnoLast; + pArea->fTop = pArea->fBottom = FALSE; + pArea->fEof = FALSE; - pArea->fEof = pArea->fBof = FALSE; - if( pTag->AscendKey ) - hb_IncString( pArea, pKey2->key, keylen ); - else - hb_DecString( pArea, pKey2->key, keylen ); - lRecnoLast = hb_ntxTagKeyFind( pTag, pKey2, keylen, &result, FALSE ); - if( lRecnoLast > 0 ) - { - BOOL lContinue = FALSE; + fLast = pArea->lpCurTag->fUsrDescend == pArea->lpCurTag->AscendKey ? + !fFindLast : fFindLast; - pArea->ulRecNo = lRecnoLast; - pArea->fValidBuffer = FALSE; - do - hb_ntxTagKeyGoTo( pTag, PREV_RECORD, &lContinue ); - while( hb_ntxIsRecBad( pArea, pTag->CurKeyInfo->Xtra ) ); - retvalue = SELF_GOTO( ( AREAP ) pArea, pTag->CurKeyInfo->Xtra ); - } - else - { - hb_ntxTagKeyGoTo( pTag, BTTM_RECORD, NULL ); - retvalue = SELF_GOTO( ( AREAP ) pArea, pTag->CurKeyInfo->Xtra ); - } - pArea->fFound = TRUE; - } - if( pArea->fShared && !pTag->Memory ) - { - hb_ntxPageFree( pTag,FALSE ); - hb_fsLock( pArea->lpCurTag->Owner->DiskFile, NTX_LOCK_OFFSET, 1, FL_UNLOCK ); - pArea->lpCurTag->Owner->Locked = FALSE; - } - if( retvalue == 0xFFFF ) - { - pArea->fEof = pTag->TagEOF; - pArea->fBof = pTag->TagBOF; - if ( lRecno > 0 && result ) - { - retvalue = SELF_GOTO( ( AREAP ) pArea, lRecno ); - pArea->fFound = TRUE; - } - else - { - pArea->fFound = FALSE; - if ( lRecno > 0 && !result && bSoftSeek && !pTag->TagEOF ) - { - retvalue = SELF_GOTO( ( AREAP ) pArea, lRecno ); - if( pTag->bottomScope ) - { - hb_ntxGetCurrentKey( pTag, pTag->CurKeyInfo ); - if( !hb_ntxInBottomScope( pTag, pTag->CurKeyInfo->key ) ) - { - pArea->fEof = pTag->TagEOF = TRUE; - } - } - } - } - } - if ( retvalue == 0xFFFF ) - { - retvalue = hb_ntxGoEof( pArea ); - } - hb_ntxKeyFree( pKey2 ); - return retvalue; + pKey = hb_ntxKeyPutItem( NULL, pItem, fLast ? NTX_MAX_REC_NUM : + NTX_IGNORE_REC_NUM, pArea->lpCurTag, TRUE, &uiLen ); + + if( ! hb_ntxTagLockRead( pArea->lpCurTag ) ) + { + hb_ntxKeyFree( pKey ); + return FAILURE; + } + hb_ntxTagRefreshScope( pArea->lpCurTag ); + + if( hb_ntxTagKeyFind( pArea->lpCurTag, pKey, uiLen ) ) + ulRec = pArea->lpCurTag->CurKeyInfo->Xtra; + else + ulRec = 0; + + if( ( ulRec == 0 && ! fSoftSeek ) || pArea->lpCurTag->TagEOF ) + fEOF = TRUE; + else + { + if( ! hb_ntxInBottomScope( pArea->lpCurTag, pArea->lpCurTag->CurKeyInfo->key ) ) + fEOF = TRUE; + else if( ! hb_ntxInTopScope( pArea->lpCurTag, pArea->lpCurTag->CurKeyInfo->key ) ) + { + hb_ntxTagGoTop( pArea->lpCurTag ); + if( pArea->lpCurTag->CurKeyInfo->Xtra == 0 || + pArea->lpCurTag->TagEOF ) + fEOF = TRUE; + } + } + hb_ntxTagUnLockRead( pArea->lpCurTag ); + if( !fEOF ) + { + retval = SELF_GOTO( ( AREAP ) pArea, pArea->lpCurTag->CurKeyInfo->Xtra ); + if( retval != FAILURE && pArea->fPositioned ) + { + retval = SELF_SKIPFILTER( ( AREAP ) pArea, fFindLast ? -1 : 1 ); + if( retval != FAILURE && ulRec && pArea->fPositioned ) + { + pArea->fFound = ( ulRec == pArea->ulRecNo || + hb_ntxValCompare( pArea->lpCurTag, pKey->key, uiLen, + pArea->lpCurTag->CurKeyInfo->key, + pArea->lpCurTag->KeyLength, FALSE ) == 0 ); + if( ! pArea->fFound && ! fSoftSeek ) + fEOF = TRUE; + } + } + } + if( retval != FAILURE && ( fEOF || + !hb_ntxKeyInScope( pArea->lpCurTag, pArea->lpCurTag->CurKeyInfo ) ) ) + { + retval = SELF_GOTO( ( AREAP ) pArea, 0 ); + } + if( pArea->fPositioned || pArea->ulRecNo != 1 ) + pArea->fBof = FALSE; + hb_ntxKeyFree( pKey ); + return retval; } } static ERRCODE ntxSkipRaw( NTXAREAP pArea, LONG lToSkip ) { - LPTAGINFO pTag = pArea->lpCurTag; - BOOL lContinue = FALSE; - ULONG ulRecNo = pArea->ulRecNo; + ERRCODE retval; + BOOL fOut = FALSE, fForward; HB_TRACE(HB_TR_DEBUG, ("ntxSkipRaw(%p, %ld)", pArea, lToSkip)); if( SELF_GOCOLD( ( AREAP ) pArea ) == FAILURE ) return FAILURE; - if ( ! pArea->lpCurTag || lToSkip == 0 ) + + if( ! pArea->lpCurTag || lToSkip == 0 ) return SUPER_SKIPRAW( ( AREAP ) pArea, lToSkip ); - if ( lToSkip > 0 ) + if( ! hb_ntxTagLockRead( pArea->lpCurTag ) ) + return FAILURE; + hb_ntxTagRefreshScope( pArea->lpCurTag ); + + fForward = ( lToSkip > 0 ); + + if( ! hb_ntxCurKeyRefresh( pArea->lpCurTag ) ) { - if ( !pArea->fEof ) - { - while ( !pTag->TagEOF && lToSkip-- > 0 ) - { - hb_ntxTagKeyGoTo( pTag, NEXT_RECORD, &lContinue ); - if( !pTag->TagEOF ) - { - if( !hb_ntxInTopScope( pTag, pTag->CurKeyInfo->key ) ) - { - ntxSeek( pArea, 1, pTag->topScope, 0 ); - } - if( !hb_ntxInBottomScope( pTag, pTag->CurKeyInfo->key ) ) - { - pTag->TagEOF = TRUE; - } - } - } - pArea->ulRecNo = ulRecNo; - if ( !pTag->TagEOF ) - { - if( pTag->CurKeyInfo->Tag ) - SELF_GOTO( ( AREAP ) pArea, pTag->CurKeyInfo->Xtra ); - } - else - { - hb_ntxGoEof( pArea ); - } - } - } - else /* ( lToSkip < 0 ) */ - { - if ( pArea->fEof ) - { - SELF_GOBOTTOM( ( AREAP ) pArea ); - lToSkip++; - } - pTag->TagBOF = FALSE; - while ( !pTag->TagBOF && lToSkip++ < 0 ) - { - hb_ntxTagKeyGoTo( pTag, PREV_RECORD, &lContinue ); - if ( !pTag->TagBOF ) - { - if( !hb_ntxInTopScope( pTag, pTag->CurKeyInfo->key ) ) - { - pTag->TagBOF = TRUE; - } - else if( !hb_ntxInBottomScope( pTag, pTag->CurKeyInfo->key ) ) - { - ntxSeek( pArea, 1, pTag->bottomScope, 1 ); - } - } - } - pArea->ulRecNo = ulRecNo; - if ( !pTag->TagBOF ) - { - if( pTag->CurKeyInfo->Tag ) - SELF_GOTO( ( AREAP ) pArea, pTag->CurKeyInfo->Xtra ); - } + if( fForward || pArea->fPositioned ) + fOut = TRUE; else { - pTag->TagBOF = FALSE; - SELF_GOTOP( ( AREAP ) pArea ); - pArea->fBof = pTag->TagBOF = TRUE; + hb_ntxTagGoBottom( pArea->lpCurTag ); + fOut = pArea->lpCurTag->TagEOF; + lToSkip++; } } - return SUCCESS; -} -static ERRCODE ntxGoCold( NTXAREAP pArea ) -{ - LPTAGINFO lpTagTmp; - LPKEYINFO pKey; - LPTAGINFO pTag; - LPPAGEINFO pPage; - BOOL fRecordChanged = pArea->fRecordChanged; - BOOL fAppend = pArea->fAppend; - BOOL InIndex; - - HB_TRACE(HB_TR_DEBUG, ("ntxGoCold(%p)", pArea)); - - if( SUPER_GOCOLD( ( AREAP ) pArea ) == SUCCESS ) + if( fForward ) { - if( fRecordChanged || pArea->fNtxAppend ) + while( !fOut && !pArea->lpCurTag->TagEOF && lToSkip-- > 0 ) { - lpTagTmp = pArea->lpCurTag; - pTag = pArea->lpNtxTag; - if( fAppend && pArea->fShared ) - { - pArea->fNtxAppend = 1; - } - else - { - while( pTag ) - { - pKey = hb_ntxKeyNew( NULL,pTag->KeyLength ); - hb_ntxGetCurrentKey( pTag, pKey ); - if( pTag->pForItem == NULL || checkLogicalExpr( pTag->pForItem, NULL ) ) - InIndex = TRUE; - else - InIndex = FALSE; - - if( pArea->fNtxAppend || fAppend || hb_ntxItemCompare( pKey->key, - pTag->CurKeyInfo->key, - pTag->KeyLength, pTag->KeyLength, TRUE,pArea->cdPage ) - || InIndex != pTag->InIndex ) - { - pArea->lpCurTag = pTag; - if( pArea->fShared && !pTag->Memory ) - while( !hb_fsLock( pTag->Owner->DiskFile, NTX_LOCK_OFFSET, 1, FL_LOCK | FLX_WAIT ) ); - pTag->Owner->Locked = TRUE; - if( !pArea->fNtxAppend && !fAppend && pTag->InIndex ) - { - LPKEYINFO pKeyOld = hb_ntxKeyNew( pTag->CurKeyInfo,pTag->KeyLength ); - - pTag->stackLevel = 0; - if( hb_ntxTagFindCurrentKey( pTag, hb_ntxPageLoad( pTag,0 ), pKeyOld, (int)pTag->KeyLength, FALSE, 0 ) ) - { - printf( "\n\rntxGoCold: Cannot find current key:" ); - pTag = pTag->pNext; - continue; - } - pPage = hb_ntxPageLoad( pTag,pTag->CurKeyInfo->Tag ); - pPage->CurKey = hb_ntxPageFindCurrentKey( pPage,pTag->CurKeyInfo->Xtra ) - 1; - hb_ntxPageKeyDel( pTag, pPage, pPage->CurKey, 1 ); - if( pTag->stack[0].ikey < 0 ) - hb_ntxTagBalance( pTag,0 ); - hb_ntxPageRelease( pTag,pPage ); - if( ( !pArea->fShared || pTag->Memory ) && pTag->keyCount && - hb_ntxInTopScope( pTag, pKeyOld->key ) && - hb_ntxInBottomScope( pTag, pKeyOld->key ) ) - pTag->keyCount --; - hb_ntxKeyFree( pKeyOld ); - } - if( InIndex ) - { - pKey->Tag = 0; - hb_ntxTagKeyAdd( pTag, pKey ); - if( ( !pArea->fShared || pTag->Memory )&& pTag->keyCount && - hb_ntxInTopScope( pTag, pKey->key ) && - hb_ntxInBottomScope( pTag, pKey->key ) ) - pTag->keyCount ++; - } - if( pArea->fShared && !pTag->Memory ) - { - hb_ntxPageFree( pTag,FALSE ); - hb_fsLock( pTag->Owner->DiskFile, NTX_LOCK_OFFSET, 1, FL_UNLOCK ); - pTag->Owner->Locked = FALSE; - } - } - hb_ntxKeyFree( pKey ); - pTag = pTag->pNext; - } - pArea->fNtxAppend = 0; - } - pArea->lpCurTag = lpTagTmp; + hb_ntxTagSkipNext( pArea->lpCurTag ); } - return SUCCESS; + retval = SELF_GOTO( ( AREAP ) pArea, + ( pArea->lpCurTag->TagEOF || fOut ) ? 0 : + pArea->lpCurTag->CurKeyInfo->Xtra ); } - else - return FAILURE; -} - -static ERRCODE ntxGoHot( NTXAREAP pArea ) -{ - LPTAGINFO pTag; - - HB_TRACE(HB_TR_DEBUG, ("ntxGoHot(%p)", pArea)); - - if( SUPER_GOHOT( ( AREAP ) pArea ) == SUCCESS ) + else /* if( lToSkip < 0 ) */ { - if( !pArea->fNtxAppend ) + while( !fOut && !pArea->lpCurTag->TagBOF && lToSkip++ < 0 ) { - pTag = pArea->lpNtxTag; - while( pTag ) - { - hb_ntxGetCurrentKey( pTag, pTag->CurKeyInfo ); - if( pTag->pForItem == NULL || checkLogicalExpr( pTag->pForItem, NULL ) ) - pTag->InIndex = TRUE; - else - pTag->InIndex = FALSE; - pTag = pTag->pNext; - } + hb_ntxTagSkipPrev( pArea->lpCurTag ); } - return SUCCESS; + if( fOut || pArea->lpCurTag->TagBOF ) + { + hb_ntxTagGoTop( pArea->lpCurTag ); + fOut = TRUE; + } + retval = SELF_GOTO( ( AREAP ) pArea, pArea->lpCurTag->TagEOF ? 0 : + pArea->lpCurTag->CurKeyInfo->Xtra ); + pArea->fBof = fOut; } + + hb_ntxTagUnLockRead( pArea->lpCurTag ); + /* Update Bof and Eof flags */ + /* + if( fForward ) + pArea->fBof = FALSE; else - return FAILURE; + pArea->fEof = FALSE; + */ + return retval; } /* @@ -3503,33 +5562,243 @@ static ERRCODE ntxGoHot( NTXAREAP pArea ) */ static ERRCODE ntxFlush( NTXAREAP pArea ) { - LPTAGINFO pTag; ERRCODE uiError; HB_TRACE(HB_TR_DEBUG, ("ntxFlush(%p)", pArea)); - if( SELF_GOCOLD( ( AREAP ) pArea ) == FAILURE ) - return FAILURE; - - uiError = SUPER_FLUSH( ( AREAP ) pArea ); - - if ( hb_set.HB_SET_HARDCOMMIT ) + uiError = SELF_GOCOLD( ( AREAP ) pArea ); + if( uiError == SUCCESS ) { - pTag = pArea->lpNtxTag; - while( pTag ) + uiError = SUPER_FLUSH( ( AREAP ) pArea ); + + if( hb_set.HB_SET_HARDCOMMIT ) { - if( !pTag->Memory && pTag->Owner->fFlush ) + LPNTXINDEX pIndex = pArea->lpIndexes; + while( pIndex ) { - hb_fsCommit( pTag->Owner->DiskFile ); - pTag->Owner->fFlush = FALSE; + if( pIndex->fFlush /* && !pIndex->Temporary */ ) + { + hb_fsCommit( pIndex->DiskFile ); + pIndex->fFlush = FALSE; + } + pIndex = pIndex->pNext; } - pTag = pTag->pNext; } } return uiError; } +/* + * Perform a write of WorkArea memory to the data store. + */ +static ERRCODE ntxGoCold( NTXAREAP pArea ) +{ + BOOL fRecordChanged = pArea->fRecordChanged; + BOOL fAppend = pArea->fAppend; + + HB_TRACE(HB_TR_DEBUG, ("ntxGoCold(%p)", pArea)); + + if( SUPER_GOCOLD( ( AREAP ) pArea ) == SUCCESS ) + { + if( fRecordChanged || pArea->fNtxAppend ) + { + if( fAppend && pArea->fShared ) + { + if( pArea->fNtxAppend ) + hb_errInternal( 9999, "ntxGoCold: multiple appending without GOCOLD.", "", "" ); + pArea->fNtxAppend = TRUE; + } + else + { + LPNTXINDEX pIndex = pArea->lpIndexes; + LPTAGINFO pTag; + LPKEYINFO pKey; + BOOL fAdd, fDel, fLck = FALSE; + int i; + + /* The pending relation may move the record pointer so we should + disable them for KEY/FOR evaluation */ + LPDBRELINFO lpdbPendingRel = pArea->lpdbPendingRel; + pArea->lpdbPendingRel = NULL; + + if( pArea->fShared ) + { + fAppend = pArea->fNtxAppend; + pArea->fNtxAppend = FALSE; + } + + while( pIndex ) + { + for( i = 0; i < pIndex->iTags; i++ ) + { + pTag = pIndex->lpTags[ i ]; + if( pTag->Custom || ( pTag->Owner->Compound && !pTag->HeadBlock ) || + ( fAppend && pTag->ChgOnly ) ) + continue; + + pKey = hb_ntxEvalKey( NULL, pTag ); + + fAdd = ( pTag->pForItem == NULL || + hb_ntxEvalCond( pArea, pTag->pForItem, TRUE ) ); + if( fAppend ) + { + fDel = FALSE; + } + else + { + if( hb_ntxValCompare( pTag, pKey->key, pTag->KeyLength, + pTag->HotKeyInfo->key, pTag->KeyLength, TRUE ) == 0 ) + { + if( pTag->HotFor ? fAdd : !fAdd ) + fAdd = fDel = FALSE; + else + fDel = !fAdd; + } + else + { + fDel = pTag->HotFor || pTag->Partial; + } + } + if( fDel || fAdd ) + { + if( !fLck ) + { + if( !hb_ntxIndexLockWrite( pIndex, TRUE ) ) + { + hb_ntxKeyFree( pKey ); + break; + } + fLck = TRUE; + if( ( pTag->Owner->Compound && !pTag->HeadBlock ) || + !pTag->RootBlock ) + fAdd = fDel = FALSE; + } + if( fDel ) + { + if( hb_ntxTagKeyDel( pTag, pTag->HotKeyInfo ) ) + { + if( !pIndex->fShared && pTag->keyCount && + hb_ntxKeyInScope( pTag, pTag->HotKeyInfo ) ) + pTag->keyCount--; + } + else + { + if( pTag->ChgOnly ) + fAdd = FALSE; + else if( !pTag->Partial ) + hb_ntxErrorRT( pTag->Owner->Owner, + EG_CORRUPTION, EDBF_CORRUPT, + pTag->Owner->IndexName, 0, 0 ); + } + } + if( fAdd ) + { + if( hb_ntxTagKeyAdd( pTag, pKey ) ) + { + if( !pIndex->fShared && pTag->keyCount && + hb_ntxKeyInScope( pTag, pKey ) ) + pTag->keyCount++; + } + } + } + hb_ntxKeyFree( pKey ); + } + if( fLck ) + { + hb_ntxIndexUnLockWrite( pIndex ); + fLck = FALSE; + } + pIndex = pIndex->pNext; + } + + /* Restore disabled pending relation */ + pArea->lpdbPendingRel = lpdbPendingRel; + } + } + return SUCCESS; + } + return FAILURE; +} + +/* + * Mark the WorkArea data buffer as hot. + */ +static ERRCODE ntxGoHot( NTXAREAP pArea ) +{ + ERRCODE errCode; + + HB_TRACE(HB_TR_DEBUG, ("ntxGoHot(%p)", pArea)); + + errCode = SUPER_GOHOT( ( AREAP ) pArea ); + if( errCode == SUCCESS ) + { + if( !pArea->fNtxAppend ) + { + LPNTXINDEX pIndex = pArea->lpIndexes; + LPTAGINFO pTag; + int i; + + while( pIndex ) + { + for( i = 0; i < pIndex->iTags; i++ ) + { + pTag = pIndex->lpTags[ i ]; + if( !pTag->Custom ) + { + pTag->HotKeyInfo = hb_ntxEvalKey( pTag->HotKeyInfo, pTag ); + pTag->HotFor = ( pTag->pForItem == NULL || + hb_ntxEvalCond( pArea, pTag->pForItem, TRUE ) ); + } + } + pIndex = pIndex->pNext; + } + } + return SUCCESS; + } + return errCode; +} + +/* + * Close the table in the WorkArea. + */ +static ERRCODE ntxClose( NTXAREAP pArea ) +{ + ERRCODE errCode; + + HB_TRACE(HB_TR_DEBUG, ("ntxClose(%p)", pArea)); + + if( SELF_GOCOLD( ( AREAP ) pArea ) == FAILURE ) + return FAILURE; + + errCode = SUPER_CLOSE( ( AREAP ) pArea ); + + if( errCode == SUCCESS ) + { + if( pArea->pSort ) + { + hb_ntxSortFree( pArea->pSort, TRUE ); + pArea->pSort = NULL; + } + + SELF_ORDLSTCLEAR( ( AREAP ) pArea ); + + /* close also production indexes if any */ + while( pArea->lpIndexes ) + { + LPNTXINDEX pIndex = pArea->lpIndexes; + pArea->lpIndexes = pIndex->pNext; + hb_ntxIndexFree( pIndex ); + } + +#ifdef HB_NTX_DEBUG_DISP + printf("\r\n#reads=%ld, #writes=%ld\r\n", s_rdNO, s_wrNO ); fflush(stdout); +#endif + } + + return errCode; +} + /* * Retrieve the size of the WorkArea structure. */ @@ -3543,6 +5812,48 @@ static ERRCODE ntxStructSize( NTXAREAP pArea, USHORT * uiSize ) return SUCCESS; } +/* + * Open a data store in the WorkArea. + */ +static ERRCODE ntxOpen( NTXAREAP pArea, LPDBOPENINFO pOpenInfo ) +{ + ERRCODE errCode; + + HB_TRACE(HB_TR_DEBUG, ("ntxOpen(%p, %p)", pArea, pOpenInfo)); + + errCode = SUPER_OPEN( ( AREAP ) pArea, pOpenInfo ); + + if( errCode == SUCCESS && s_fStruct && + ( s_fStrictStruct ? pArea->fHasTags : hb_set.HB_SET_AUTOPEN ) ) + { + char szFileName[ _POSIX_PATH_MAX + 1 ]; + + hb_ntxCreateFName( pArea, NULL, NULL, szFileName, NULL ); + if ( hb_spFile( ( BYTE * ) szFileName, NULL ) ) + { + DBORDERINFO pOrderInfo; + + pOrderInfo.itmResult = hb_itemPutNI( NULL, 0 ); + pOrderInfo.atomBagName = hb_itemPutC( NULL, szFileName ); + pOrderInfo.itmNewVal = NULL; + pOrderInfo.itmOrder = NULL; + errCode = SELF_ORDLSTADD( ( AREAP ) pArea, &pOrderInfo ); + if( errCode == SUCCESS ) + { + pOrderInfo.itmOrder = hb_itemPutNI( NULL, hb_set.HB_SET_AUTORDER ); + errCode = SELF_ORDLSTFOCUS( ( AREAP ) pArea, &pOrderInfo ); + hb_itemRelease( pOrderInfo.itmOrder ); + if( errCode == SUCCESS ) + errCode = SELF_GOTOP( ( AREAP ) pArea ); + } + hb_itemRelease( pOrderInfo.atomBagName ); + hb_itemRelease( pOrderInfo.itmResult ); + } + } + + return errCode; +} + static ERRCODE ntxSysName( NTXAREAP pArea, BYTE * pBuffer ) { HB_TRACE(HB_TR_DEBUG, ("ntxSysName(%p, %p)", pArea, pBuffer)); @@ -3554,349 +5865,508 @@ static ERRCODE ntxSysName( NTXAREAP pArea, BYTE * pBuffer ) static ERRCODE ntxPack( NTXAREAP pArea ) { + ERRCODE errCode; HB_TRACE(HB_TR_DEBUG, ("ntxPack(%p)", pArea )); - if( SUPER_PACK( ( AREAP ) pArea ) == SUCCESS ) - return ntxOrderListRebuild( pArea ); - else - return FAILURE; + errCode = SUPER_PACK( ( AREAP ) pArea ); + if( errCode == SUCCESS ) + return SELF_ORDLSTREBUILD( ( AREAP ) pArea ); + + return errCode; } static ERRCODE ntxZap( NTXAREAP pArea ) { + ERRCODE errCode; + HB_TRACE(HB_TR_DEBUG, ("ntxZap(%p)", pArea )); - if( SUPER_ZAP( ( AREAP ) pArea ) == SUCCESS ) - { - LPTAGINFO pTag, pTagTmp; - char* buffer; - USHORT i; - LPNTXBUFFER itemlist; + errCode = SUPER_ZAP( ( AREAP ) pArea ); + if( errCode == SUCCESS ) + return SELF_ORDLSTREBUILD( ( AREAP ) pArea ); - buffer = (char*) hb_xgrab( NTXBLOCKSIZE ); - pTag = pArea->lpNtxTag; - pTagTmp = pArea->lpCurTag; - while( pTag ) - { - hb_ntxPageFree( pTag,TRUE ); - pTag->RootBlock = pTag->TagBlock = NTXBLOCKSIZE; - pTag->keyCount = pTag->Owner->NextAvail = 0; - hb_ntxHeaderSave( pTag->Owner, FALSE ); - - memset( buffer, 0, NTXBLOCKSIZE ); - itemlist = ( LPNTXBUFFER ) buffer; - itemlist->item_count = 0; - for( i = 0; i < pTag->MaxKeys+1; i++ ) - itemlist->item_offset[i] = 2 + 2 * ( pTag->MaxKeys + 1 ) + - i * ( pTag->KeyLength + 8 ); - - if( pTag->Memory ) - { - pTag->ulPagesDepth = 1; - hb_xfree( pTag->pages ); - pTag->pages = (LPPAGEINFO) hb_xgrab( sizeof(HB_PAGEINFO) ); - memset( pTag->pages , 0 ,sizeof( HB_PAGEINFO ) ); - pTag->pages[0].buffer = (char*) hb_xgrab( NTXBLOCKSIZE ); - } - else - { - hb_fsSeek( pTag->Owner->DiskFile, NTXBLOCKSIZE, FS_SET ); - hb_fsWrite( pTag->Owner->DiskFile, (BYTE *) buffer, NTXBLOCKSIZE ); - hb_fsWrite( pTag->Owner->DiskFile, NULL, 0 ); - pTag->Owner->fFlush = TRUE; - } - - pTag = pTag->pNext; - } - - pArea->lpCurTag = pTagTmp; - hb_xfree( buffer ); - return SELF_GOTOP( ( AREAP ) pArea ); - } - else - return FAILURE; -} - -static ERRCODE ntxOrderCondition( NTXAREAP area, LPDBORDERCONDINFO pOrdCondInfo ) -{ -#ifdef HB_EXTENSION - if( pOrdCondInfo ) - pOrdCondInfo->fNoOptimize = hb_parl( 18 ); -#endif - return SUPER_ORDSETCOND( ( AREAP ) area, pOrdCondInfo ); + return errCode; } static ERRCODE ntxOrderCreate( NTXAREAP pArea, LPDBORDERCREATEINFO pOrderInfo ) { - PHB_ITEM pExpr, pResult; - PHB_ITEM pKeyExp, pForExp; - HB_MACRO_PTR pExpMacro, pForMacro; - USHORT uiType; - int uiLen, uiDec; - char * szFileName, * szTagName; - LPNTXINDEX pIndex; - LPTAGINFO pTag; - PHB_FNAME pFileName; - DBORDERINFO pExtInfo; - BOOL fTagName; + PHB_ITEM pResult, pKeyExp, pForExp = NULL; + int iLen, iDec, iTag, i; + char szFileName[ _POSIX_PATH_MAX + 1 ], szSpFile[ _POSIX_PATH_MAX + 1 ], + szTagName[ NTX_MAX_TAGNAME + 1 ], * szKey, * szFor = NULL; + LPNTXINDEX pIndex, * pIndexPtr; + LPTAGINFO pTag = NULL; + ERRCODE errCode; + ULONG ulRecNo; + BOOL fCompound, fTagName, fBagName, fProd, fLocked = FALSE, + fAscend = TRUE, fCustom = FALSE, fTemporary = FALSE, fExclusive = FALSE; BYTE bType; HB_TRACE(HB_TR_DEBUG, ("ntxOrderCreate(%p, %p)", pArea, pOrderInfo)); - /* printf( "\nntxOrderCreate - 0\n" ); */ - if( SELF_GOCOLD( ( AREAP ) pArea ) == FAILURE ) - return FAILURE; - if( !pArea->lpdbOrdCondInfo || ( pArea->lpdbOrdCondInfo->fAll && - !pArea->lpdbOrdCondInfo->fAdditive ) ) - SELF_ORDLSTCLEAR( ( AREAP ) pArea ); + errCode = SELF_GOCOLD( ( AREAP ) pArea ); + if( errCode != SUCCESS ) + return errCode; + if( pArea->lpdbPendingRel ) + { + errCode = SELF_FORCEREL( ( AREAP ) pArea ); + if( errCode != SUCCESS ) + return errCode; + } + + szKey = hb_itemGetCPtr( pOrderInfo->abExpr ); /* If we have a codeblock for the expression, use it */ if( pOrderInfo->itmCobExpr ) - pExpr = pOrderInfo->itmCobExpr; + pKeyExp = hb_itemNew( pOrderInfo->itmCobExpr ); else /* Otherwise, try compiling the key expression string */ { - if( SELF_COMPILE( ( AREAP ) pArea, ( BYTE * ) pOrderInfo->abExpr->item.asString.value ) == FAILURE ) - return FAILURE; - pExpr = pArea->valResult; - /* pArea->valResult = NULL; */ + errCode = SELF_COMPILE( ( AREAP ) pArea, ( BYTE * ) szKey ); + if( errCode != SUCCESS ) + return errCode; + pKeyExp = pArea->valResult; + pArea->valResult = NULL; } - /* Save for later use */ - pKeyExp = hb_itemNew( NULL ); - hb_itemCopy( pKeyExp, pExpr ); /* Get a blank record before testing expression */ - /* SELF_GOBOTTOM( ( AREAP ) pArea ); - SELF_SKIP( ( AREAP ) pArea, 1 ); */ - pExpMacro = pForMacro = NULL; - if( hb_itemType( pExpr ) == HB_IT_BLOCK ) + ulRecNo = pArea->ulRecNo; + errCode = SELF_GOTO( ( AREAP ) pArea, 0 ); + if( errCode != SUCCESS ) + return errCode; + + errCode = SELF_EVALBLOCK( ( AREAP ) pArea, pKeyExp ); + if( errCode != SUCCESS ) { - if( SELF_EVALBLOCK( ( AREAP ) pArea, pExpr ) == FAILURE ) - { - hb_itemRelease( pKeyExp ); - return FAILURE; - } - pResult = pArea->valResult; - /* pArea->valResult = NULL; */ + hb_ntxDestroyExp( pKeyExp ); + SELF_GOTO( ( AREAP ) pArea, ulRecNo ); + return errCode; } - else + pResult = pArea->valResult; + pArea->valResult = NULL; + + bType = hb_ntxItemType( pResult ); + iLen = iDec = 0; + switch( bType ) { - pExpMacro = ( HB_MACRO_PTR ) hb_itemGetPtr( pExpr ); - hb_macroRun( pExpMacro ); - pResult = pExpr; - hb_itemCopy( pResult, hb_stackItemFromTop( -1 ) ); - hb_stackPop(); - } - - uiType = hb_itemType( pResult ); - uiLen = uiDec = 0; - switch( uiType ) - { - case HB_IT_INTEGER: - case HB_IT_LONG: - case HB_IT_DOUBLE: - bType = 'N'; - hb_itemGetNLen( pResult, (int*) &uiLen, (int*) &uiDec ); - if( uiDec ) - uiLen += uiDec + 1; - /* printf( "\nLength: %d %d",uiLen,uiDec ); */ + case 'N': + hb_itemGetNLen( pResult, &iLen, &iDec ); + if( iDec ) + iLen += iDec + 1; break; - - case HB_IT_DATE: - bType = 'D'; - uiLen = 8; + case 'D': + iLen = 8; break; - - case HB_IT_LOGICAL: - bType = 'C'; - uiLen = 1; + case 'L': + iLen = 1; break; - - case HB_IT_STRING: - bType = 'C'; - uiLen = pResult->item.asString.length > NTX_MAX_KEY ? NTX_MAX_KEY : - pResult->item.asString.length ; + case 'C': + iLen = hb_itemGetCLen( pResult ); + if( iLen > NTX_MAX_KEY ) + iLen = NTX_MAX_KEY; break; - default: - hb_itemRelease( pKeyExp ); - if( pExpMacro != NULL ) - hb_macroDelete( pExpMacro ); - return FAILURE; + bType = 'U'; } + hb_itemRelease( pResult ); - /* Make sure uiLen is not 0 */ - if( !uiLen ) + /* Make sure KEY has proper type and iLen is not 0 */ + if( bType == 'U' || iLen == 0 ) { - hb_itemRelease( pKeyExp ); - commonError( pArea, EG_DATAWIDTH, 1026, NULL, 0 ); - if( pExpMacro != NULL ) - hb_macroDelete( pExpMacro ); + hb_ntxDestroyExp( pKeyExp ); + SELF_GOTO( ( AREAP ) pArea, ulRecNo ); + hb_ntxErrorRT( pArea, bType == 'U' ? EG_DATATYPE : EG_DATAWIDTH, + 1026, NULL, 0, 0 ); return FAILURE; } - /* Check conditional expression */ - pExpr = pForExp = NULL; - if( pArea->lpdbOrdCondInfo && ( pArea->lpdbOrdCondInfo->itmCobFor || pArea->lpdbOrdCondInfo->abFor ) ) + if( pArea->lpdbOrdCondInfo ) { - /* If we have a codeblock for the conditional expression, use it */ + fAscend = !pArea->lpdbOrdCondInfo->fDescending; + fCustom = pArea->lpdbOrdCondInfo->fCustom; + fTemporary = pArea->lpdbOrdCondInfo->fTemporary; + fExclusive = pArea->lpdbOrdCondInfo->fExclusive; + /* Check conditional expression */ + szFor = ( char * ) pArea->lpdbOrdCondInfo->abFor; if( pArea->lpdbOrdCondInfo->itmCobFor ) + /* If we have a codeblock for the conditional expression, use it */ + pForExp = hb_itemNew( pArea->lpdbOrdCondInfo->itmCobFor ); + else if( szFor ) { - pExpr = pArea->lpdbOrdCondInfo->itmCobFor; + /* Otherwise, try compiling the conditional expression string */ + errCode = SELF_COMPILE( ( AREAP ) pArea, ( BYTE * ) szFor ); + if( errCode != SUCCESS ) + { + hb_ntxDestroyExp( pKeyExp ); + SELF_GOTO( ( AREAP ) pArea, ulRecNo ); + return errCode; + } + pForExp = pArea->valResult; + pArea->valResult = NULL; } - else /* Otherwise, try compiling the conditional expression string */ - { - if( SELF_COMPILE( ( AREAP ) pArea, pArea->lpdbOrdCondInfo->abFor ) == FAILURE ) - return FAILURE; - pExpr = pArea->valResult; - } - /* Save for later use */ - pForExp = hb_itemNew( NULL ); - hb_itemCopy( pForExp, pExpr ); } /* Test conditional expression */ - if( pExpr ) + if( pForExp ) { - if( hb_itemType( pExpr ) == HB_IT_BLOCK ) + USHORT uiType; + + errCode = SELF_EVALBLOCK( ( AREAP ) pArea, pForExp ); + if( errCode != SUCCESS ) { - if( SELF_EVALBLOCK( ( AREAP ) pArea, pExpr ) == FAILURE ) - { - hb_itemRelease( pKeyExp ); - hb_itemRelease( pForExp ); - if( pExpMacro != NULL ) - hb_macroDelete( pExpMacro ); - return FAILURE; - } - pResult = pArea->valResult; + hb_ntxDestroyExp( pKeyExp ); + hb_ntxDestroyExp( pForExp ); + SELF_GOTO( ( AREAP ) pArea, ulRecNo ); + return errCode; } - else - { - pForMacro = ( HB_MACRO_PTR ) hb_itemGetPtr( pExpr ); - hb_macroRun( pForMacro ); - pResult = pExpr; - hb_itemCopy( pResult, hb_stackItemFromTop( -1 ) ); - hb_stackPop(); - } - uiType = hb_itemType( pResult ); + uiType = hb_itemType( pArea->valResult ); + hb_itemRelease( pArea->valResult ); + pArea->valResult = NULL; if( uiType != HB_IT_LOGICAL ) { - hb_itemRelease( pKeyExp ); - hb_itemRelease( pForExp ); - if( pExpMacro != NULL ) - hb_macroDelete( pExpMacro ); - if( pForMacro != NULL ) - hb_macroDelete( pForMacro ); + hb_ntxDestroyExp( pKeyExp ); + hb_ntxDestroyExp( pForExp ); + SELF_GOTO( ( AREAP ) pArea, ulRecNo ); + hb_ntxErrorRT( pArea, EG_DATATYPE, EDBF_INVALIDFOR, NULL, 0, 0 ); return FAILURE; } } - /* Check file name */ - szFileName = ( char * ) hb_xgrab( _POSIX_PATH_MAX + 3 ); - szFileName[ 0 ] = '\0'; - if( strlen( ( char * ) pOrderInfo->abBagName ) == 0 ) + SELF_GOTO( ( AREAP ) pArea, ulRecNo ); + + /* + * abBagName -> cBag, atomBagName -> cTag + * The following scheme implemented: + * 1. abBagName == NULL -> add the Tag to the structural index + * if no compound index support then create new separate index + * with atomBagName + * 2. atomBagName == NULL -> overwrite any index file of abBagName + * 3. ads the Tag to index file + */ + fTagName = pOrderInfo->atomBagName && pOrderInfo->atomBagName[0]; + fBagName = pOrderInfo->abBagName && pOrderInfo->abBagName[0]; +#if defined( HB_NTX_NOMULTITAG ) + fCompound = FALSE; +#else + fCompound = fTagName && s_fMultiTag; +#endif + hb_ntxCreateFName( pArea, ( char * ) ( ( fBagName || fCompound ) ? + pOrderInfo->abBagName : pOrderInfo->atomBagName ), + &fProd, szFileName, szTagName ); + if( fTagName ) + hb_strncpyUpperTrim( szTagName, ( char * ) pOrderInfo->atomBagName, NTX_MAX_TAGNAME ); + + pIndex = hb_ntxFindBag( pArea, szFileName ); + if( pIndex && !fCompound ) { - pFileName = hb_fsFNameSplit( pArea->szDataFileName ); - if( pFileName->szDrive ) - strcat( szFileName, pFileName->szDrive ); - if( pFileName->szPath ) - strcat( szFileName, pFileName->szPath ); - strcat( szFileName, pFileName->szName ); - pExtInfo.itmResult = hb_itemPutC( NULL, "" ); - SELF_ORDINFO( ( AREAP ) pArea, DBOI_BAGEXT, &pExtInfo ); - strcat( szFileName, hb_itemGetCPtr( pExtInfo.itmResult ) ); - hb_itemRelease( pExtInfo.itmResult ); - } - else - { - strcpy( szFileName, ( char * ) pOrderInfo->abBagName ); - pFileName = hb_fsFNameSplit( szFileName ); - if( !pFileName->szExtension ) + pIndexPtr = &pArea->lpIndexes; + while( *pIndexPtr ) { - pExtInfo.itmResult = hb_itemPutC( NULL, "" ); - SELF_ORDINFO( ( AREAP ) pArea, DBOI_BAGEXT, &pExtInfo ); - strcat( szFileName, hb_itemGetCPtr( pExtInfo.itmResult ) ); - hb_itemRelease( pExtInfo.itmResult ); - } - } - - if( pOrderInfo->atomBagName && strlen( ( const char * ) pOrderInfo->atomBagName ) > 0 ) - { - int iTagNameLen = strlen( ( const char * ) pOrderInfo->atomBagName ); - if( iTagNameLen > 10 ) - iTagNameLen = 10; - szTagName = ( char * ) hb_xgrab( iTagNameLen + 1 ); - hb_strncpyUpper( szTagName, ( const char * ) pOrderInfo->atomBagName, iTagNameLen ); - fTagName = TRUE; - } - else - { - int iTagNameLen = strlen( pFileName->szName ); - if( iTagNameLen > 10 ) - iTagNameLen = 10; - szTagName = ( char * ) hb_xgrab( iTagNameLen + 1 ); - hb_strncpyUpper( szTagName, pFileName->szName, iTagNameLen ); - fTagName = FALSE; - } - hb_xfree( pFileName ); - - pIndex = hb_ntxIndexNew( pArea ); - pIndex->IndexName = szFileName; - pTag = hb_ntxTagNew( pIndex, szTagName, fTagName, pOrderInfo->abExpr->item.asString.value, - pKeyExp, bType, (USHORT) uiLen, (USHORT) uiDec, (char *) ( pArea->lpdbOrdCondInfo ? pArea->lpdbOrdCondInfo->abFor : NULL ), - pForExp, pArea->lpdbOrdCondInfo ? !pArea->lpdbOrdCondInfo->fDescending : TRUE, - pOrderInfo->fUnique, pArea->lpdbOrdCondInfo ? pArea->lpdbOrdCondInfo->fCustom : FALSE, - pArea->lpdbOrdCondInfo ? pArea->lpdbOrdCondInfo->fNoOptimize : FALSE ); - pIndex->CompoundTag = pTag; - - if( !pTag->Memory ) - { - pIndex->DiskFile = hb_spCreate( ( BYTE * ) szFileName , FC_NORMAL ); - if(pIndex->DiskFile == FS_ERROR) { - hb_xfree( szFileName ); - hb_itemRelease( pKeyExp ); - if( pForExp != NULL ) - hb_itemRelease( pForExp ); - if( pExpMacro != NULL ) - hb_macroDelete( pExpMacro ); - if( pForMacro != NULL ) - hb_macroDelete( pForMacro ); - return FAILURE; - } - } - if( hb_ntxIndexCreate( pIndex ) == FAILURE ) - { - return FAILURE; - } - if( pArea->lpdbOrdCondInfo && !pArea->lpdbOrdCondInfo->fAll && - !pArea->lpdbOrdCondInfo->fAdditive ) - SELF_ORDLSTCLEAR( ( AREAP ) pArea ); - if( pArea->lpdbOrdCondInfo && pArea->lpdbOrdCondInfo->fAdditive ) - { - if( pArea->lpNtxTag ) - { - LPTAGINFO pTagNext = pArea->lpNtxTag; - - pTag->TagRoot++; - while( pTagNext->pNext ) + if( pIndex == *pIndexPtr ) { - pTag->TagRoot++; - pTagNext = pTagNext->pNext; + *pIndexPtr = pIndex->pNext; + hb_ntxIndexFree( pIndex ); + break; + } + pIndexPtr = &(*pIndexPtr)->pNext; + } + pIndex = NULL; + } + + if( pIndex ) + { + if( pIndex->fReadonly ) + { + hb_ntxDestroyExp( pKeyExp ); + if( pForExp != NULL ) + hb_ntxDestroyExp( pForExp ); + hb_ntxErrorRT( pArea, EG_READONLY, EDBF_READONLY, pIndex->IndexName, 0, 0 ); + return FAILURE; + } +#if 0 /* enable this code if you want to forbid tag deleting in shared mode */ + else if( pIndex->fShared ) + { + hb_ntxDestroyExp( pKeyExp ); + if( pForExp != NULL ) + hb_ntxDestroyExp( pForExp ); + hb_ntxErrorRT( pArea, EG_SHARED, EDBF_SHARED, pIndex->IndexName, 0, 0 ); + return FAILURE; + } +#endif + } + else + { + FHANDLE hFile; + BOOL bRetry, fOld, fShared = pArea->fShared && !fTemporary && !fExclusive; + USHORT uiFlags = FO_READWRITE | ( fShared ? FO_DENYNONE : FO_EXCLUSIVE ); + + fOld = fCompound; + do + { + if( fTemporary ) + { + hFile = hb_fsCreateTemp( NULL, NULL, FC_NORMAL, ( BYTE * ) szSpFile ); + fOld = FALSE; + } + else + { + hFile = hb_fsExtOpen( ( BYTE * ) szFileName, NULL, uiFlags | + ( fOld ? FXO_APPEND : FXO_TRUNCATE ) | + FXO_DEFAULTS | FXO_SHARELOCK | FXO_COPYNAME, + NULL, NULL ); + } + if( hFile == FS_ERROR ) + bRetry = ( hb_ntxErrorRT( pArea, EG_CREATE, EDBF_CREATE, szFileName, + hb_fsError(), EF_CANRETRY | EF_CANDEFAULT ) == E_RETRY ); + else + { + bRetry = FALSE; + if( fOld ) + fOld = ( hb_fsSeekLarge( hFile, 0, FS_END ) != 0 ); + } + } while( bRetry ); + + if( hFile == FS_ERROR ) + { + hb_ntxDestroyExp( pKeyExp ); + if( pForExp != NULL ) + hb_ntxDestroyExp( pForExp ); + /* hb_ntxSetTagNumbers() */ + return FAILURE; + } + + pIndex = hb_ntxIndexNew( pArea ); + pIndex->IndexName = hb_strdup( szFileName ); + pIndex->fReadonly = FALSE; + pIndex->fShared = fShared; + pIndex->DiskFile = hFile; + pIndex->fDelete = fTemporary; + if( fTemporary ) + pIndex->RealName = hb_strdup( szSpFile ); + else + pIndex->Production = fProd; + + pIndexPtr = &pArea->lpIndexes; + while( *pIndexPtr ) + pIndexPtr = &(*pIndexPtr)->pNext; + *pIndexPtr = pIndex; + if( fOld ) + { + if( !hb_ntxIndexLockWrite( pIndex, TRUE ) ) + errCode = FAILURE; + else + { + errCode = hb_ntxIndexLoad( pIndex, szTagName ); + if( errCode != SUCCESS ) + hb_ntxIndexUnLockWrite( pIndex ); + else + fLocked = TRUE; + } + if( errCode != SUCCESS ) + { + *pIndexPtr = pIndex->pNext; + hb_ntxIndexFree( pIndex ); + hb_ntxDestroyExp( pKeyExp ); + if( pForExp != NULL ) + hb_ntxDestroyExp( pForExp ); + /* hb_ntxSetTagNumbers() */ + hb_ntxErrorRT( pArea, EG_CORRUPTION, EDBF_CORRUPT, szFileName, 0, 0 ); + return errCode; } - pTagNext->pNext = pTag; } else - pArea->lpNtxTag = pTag; + { + pIndex->LargeFile = ( pIndex->Owner->bLockType == DB_DBFLOCK_XHB64 ); + } + } + + iTag = hb_ntxFindTagByName( pIndex, szTagName ); + fCompound = ( pIndex->iTags > ( iTag ? 1 : 0 ) ); + + if( ! iTag && pIndex->iTags == CTX_MAX_TAGS ) + { + hb_ntxDestroyExp( pKeyExp ); + if( pForExp != NULL ) + hb_ntxDestroyExp( pForExp ); + /* hb_ntxSetTagNumbers() */ + hb_ntxErrorRT( pArea, EG_LIMIT, EDBF_LIMITEXCEEDED, pIndex->IndexName, 0, 0 ); + return FAILURE; + } + + if( !fLocked && !hb_ntxIndexLockWrite( pIndex, fCompound ) ) + { + errCode = FAILURE; } else - pArea->lpNtxTag = pTag; + { + if( pIndex->Compound != fCompound ) + { + pIndex->Compound = fCompound; + if( fCompound ) + { + if( !pIndex->HeaderBuff ) + pIndex->HeaderBuff = ( BYTE * ) hb_xgrab( NTXBLOCKSIZE ); + memset( pIndex->HeaderBuff, 0, NTXBLOCKSIZE ); + pIndex->fValidHeader = TRUE; + } + for( i = 0; i < pIndex->iTags; i++ ) + { + pIndex->lpTags[ i ]->HdrChanged = TRUE; + pIndex->lpTags[ i ]->HeadBlock = 0; + if( fCompound ) + hb_ntxIndexTagAdd( pIndex, pIndex->lpTags[ i ] ); + } + } + pTag = hb_ntxTagNew( pIndex, szTagName, fTagName, + szKey, pKeyExp, bType, (USHORT) iLen, (USHORT) iDec, + szFor, pForExp, + fAscend, pOrderInfo->fUnique, fCustom, s_fSortRecNo ); + pTag->Partial = ( pArea->lpdbOrdCondInfo && !pArea->lpdbOrdCondInfo->fAll ); + + if( ! pIndex->Compound ) + { + while( pIndex->iTags ) + hb_ntxTagDelete( pIndex->lpTags[ 0 ] ); + hb_ntxIndexTrunc( pIndex ); + iTag = 0; + } + + if( iTag ) + { + pTag->HeadBlock = pIndex->lpTags[ iTag - 1 ]->HeadBlock; + if( pIndex->lpTags[ iTag - 1 ]->RootBlock && + ! hb_ntxTagPagesFree( pIndex->lpTags[ iTag - 1 ], + pIndex->lpTags[ iTag - 1 ]->RootBlock ) ) + { + errCode = FAILURE; + } + else + { + hb_ntxTagFree( pIndex->lpTags[ iTag - 1 ] ); + pIndex->lpTags[ iTag - 1 ] = pTag; + } + } + else + { + hb_ntxTagAdd( pIndex, pTag ); + if( pIndex->Compound ) + hb_ntxIndexTagAdd( pIndex, pTag ); + } + + if( errCode == SUCCESS ) + { + pIndex->Update = pIndex->Changed = pTag->HdrChanged = TRUE; + errCode = hb_ntxTagCreate( pTag, FALSE ); + } + hb_ntxIndexUnLockWrite( pIndex ); + } + + pIndexPtr = &pArea->lpIndexes; + while( *pIndexPtr && *pIndexPtr != pIndex ) + pIndexPtr = &(*pIndexPtr)->pNext; + + /* It should not happen, reintrance? */ + if( !*pIndexPtr ) + return FAILURE; + + if( errCode != SUCCESS ) + { + *pIndexPtr = pIndex->pNext; + hb_ntxIndexFree( pIndex ); + /* hb_ntxSetTagNumbers() */ + return errCode; + } + + if( !pArea->lpdbOrdCondInfo || !pArea->lpdbOrdCondInfo->fAdditive ) + { + *pIndexPtr = pIndex->pNext; + pIndex->pNext = NULL; + SELF_ORDLSTCLEAR( ( AREAP ) pArea ); + pIndexPtr = &pArea->lpIndexes; + while( *pIndexPtr ) + pIndexPtr = &(*pIndexPtr)->pNext; + *pIndexPtr = pIndex; + } + if( pIndex->Production && !pArea->fReadonly && !pArea->fHasTags && + s_fStruct && ( s_fStrictStruct || hb_set.HB_SET_AUTOPEN ) ) + { + pArea->fHasTags = TRUE; + SELF_WRITEDBHEADER( ( AREAP ) pArea ); + } + /* hb_ntxSetTagNumbers() */ pArea->lpCurTag = pTag; - hb_ntxHeaderSave( pIndex, TRUE ); - if( !pTag->Memory ) - pTag->TagBlock = hb_fsSeek( pIndex->DiskFile, 0, SEEK_END ) - 1024; SELF_ORDSETCOND( ( AREAP ) pArea, NULL ); return SELF_GOTOP( ( AREAP ) pArea ); } +static ERRCODE ntxOrderDestroy( NTXAREAP pArea, LPDBORDERINFO pOrderInfo ) +{ + ERRCODE errCode; + + HB_TRACE(HB_TR_DEBUG, ("ntxOrderDestroy(%p, %p)", pArea, pOrderInfo)); + + errCode = SELF_GOCOLD( ( AREAP ) pArea ); + if( errCode != SUCCESS ) + return errCode; + + if( pArea->lpdbPendingRel ) + { + errCode = SELF_FORCEREL( ( AREAP ) pArea ); + if( errCode != SUCCESS ) + return errCode; + } + + if( pOrderInfo->itmOrder ) + { + LPTAGINFO pTag = hb_ntxFindTag( pArea, pOrderInfo->itmOrder, pOrderInfo->atomBagName ); + + if( pTag ) + { + LPNTXINDEX pIndex = pTag->Owner, *pIndexPtr; + + if( pIndex->iTags == 1 ) + { + BOOL fProd = pIndex->Production; + pIndexPtr = &pArea->lpIndexes; + while( *pIndexPtr != pIndex ) + pIndexPtr = &(*pIndexPtr)->pNext; + *pIndexPtr = pIndex->pNext; + pIndex->fDelete = TRUE; + hb_ntxIndexFree( pIndex ); + if( fProd && !pArea->fReadonly && pArea->fHasTags && + s_fStruct && ( s_fStrictStruct || hb_set.HB_SET_AUTOPEN ) ) + { + pArea->fHasTags = FALSE; + SELF_WRITEDBHEADER( ( AREAP ) pArea ); + } + } + else if( pIndex->fReadonly ) + { + hb_ntxErrorRT( pArea, EG_READONLY, EDBF_READONLY, pIndex->IndexName, 0, 0 ); + return FAILURE; + } +#if 0 /* enable this code if you want to forbid tag deleting in shared mode */ + else if( pIndex->fShared ) + { + hb_ntxErrorRT( pArea, EG_SHARED, EDBF_SHARED, pIndex->IndexName, 0, 0 ); + return FAILURE; + } +#endif + else if( !hb_ntxIndexLockWrite( pIndex, TRUE ) ) + { + return FAILURE; + } + else + { + errCode = hb_ntxTagSpaceFree( pTag ); + hb_ntxIndexUnLockWrite( pIndex ); + } + /* hb_ntxSetTagNumbers() */ + } + } + + return errCode; +} + static ERRCODE ntxOrderInfo( NTXAREAP pArea, USHORT uiIndex, LPDBORDERINFO pInfo ) { LPTAGINFO pTag; @@ -3905,26 +6375,184 @@ static ERRCODE ntxOrderInfo( NTXAREAP pArea, USHORT uiIndex, LPDBORDERINFO pInfo switch( uiIndex ) { case DBOI_BAGEXT: - hb_itemPutC( pInfo->itmResult, ".ntx" ); + hb_itemClear( pInfo->itmResult ); + return SELF_RDDINFO( SELF_RDDNODE( pArea ), RDDI_ORDBAGEXT, 0, pInfo->itmResult ); + case DBOI_EVALSTEP: + hb_itemPutNL( pInfo->itmResult, + pArea->lpdbOrdCondInfo ? pArea->lpdbOrdCondInfo->lStep : 0 ); return SUCCESS; + case DBOI_KEYSINCLUDED: + hb_itemPutNL( pInfo->itmResult, + pArea->pSort ? pArea->pSort->ulTotKeys : 0 ); + return SUCCESS; + case DBOI_I_TAGNAME: + hb_itemPutC( pInfo->itmResult, + pArea->pSort ? pArea->pSort->pTag->TagName : NULL ); + return SUCCESS; + case DBOI_I_BAGNAME: + hb_itemPutC( pInfo->itmResult, pArea->pSort ? + pArea->pSort->pTag->Owner->IndexName : NULL ); + return SUCCESS; + case DBOI_ISREINDEX: + hb_itemPutL( pInfo->itmResult, + pArea->pSort ? pArea->pSort->fReindex : FALSE ); + return SUCCESS; + case DBOI_LOCKOFFSET: + case DBOI_HPLOCKING: + { + HB_FOFFSET ulPos, ulPool; + hb_dbfLockIdxGetData( pArea->bLockType, &ulPos, &ulPool ); + if( uiIndex == DBOI_LOCKOFFSET ) + hb_itemPutNInt( pInfo->itmResult, ulPos ); + else + hb_itemPutL( pInfo->itmResult, ulPool > 0 ); + return SUCCESS; + } + case DBOI_ORDERCOUNT: + { + int i = 0; + BOOL fBag = hb_itemGetCLen( pInfo->atomBagName ) > 0; + LPNTXINDEX pIndex = fBag ? + hb_ntxFindBag( pArea, hb_itemGetCPtr( pInfo->atomBagName ) ) : + pArea->lpIndexes; + while( pIndex ) + { + i += pIndex->iTags; + if( fBag ) + break; + pIndex = pIndex->pNext; + } + hb_itemPutNI( pInfo->itmResult, i ); + return SUCCESS; + } + case DBOI_BAGCOUNT: + { + int i = 0; + LPNTXINDEX pIndex = pArea->lpIndexes; + while( pIndex ) + { + ++i; + pIndex = pIndex->pNext; + } + hb_itemPutNI( pInfo->itmResult, i ); + return SUCCESS; + } + case DBOI_BAGNUMBER: + { + LPNTXINDEX pIndex = pArea->lpIndexes, pIndexSeek = NULL; + int i = 0; + + if( hb_itemGetCLen( pInfo->atomBagName ) > 0 ) + pIndexSeek = hb_ntxFindBag( pArea, + hb_itemGetCPtr( pInfo->atomBagName ) ); + else if( pArea->lpCurTag ) + pIndexSeek = pArea->lpCurTag->Owner; + + if( pIndexSeek ) + { + do + { + ++i; + if( pIndex == pIndexSeek ) + break; + pIndex = pIndex->pNext; + } + while( pIndex ); + } + hb_itemPutNI( pInfo->itmResult, pIndex ? i : 0 ); + return SUCCESS; + } + case DBOI_BAGORDER: + { + LPNTXINDEX pIndex = pArea->lpIndexes, pIndexSeek; + int i = 0; + + if( hb_itemGetCLen( pInfo->atomBagName ) > 0 ) + pIndexSeek = hb_ntxFindBag( pArea, + hb_itemGetCPtr( pInfo->atomBagName ) ); + else + pIndexSeek = pIndex; + + if( pIndexSeek ) + { + ++i; + do + { + if( pIndex == pIndexSeek ) + break; + i += pIndex->iTags; + pIndex = pIndex->pNext; + } + while( pIndex ); + } + hb_itemPutNI( pInfo->itmResult, pIndex ? i : 0 ); + return SUCCESS; + } } if( SELF_GOCOLD( ( AREAP ) pArea ) == FAILURE ) return FAILURE; - if( pArea->lpNtxTag && - ( pTag = ntxFindIndex( pArea , pInfo->itmOrder ) ) != NULL ) + pTag = hb_ntxFindTag( pArea, pInfo->itmOrder, pInfo->atomBagName ); + + if( pTag ) { switch( uiIndex ) { case DBOI_CONDITION: - if( pTag->ForExpr ) - hb_itemPutC( pInfo->itmResult , pTag->ForExpr ); - else - hb_itemPutC( pInfo->itmResult, "" ); + hb_itemPutC( pInfo->itmResult, pTag->ForExpr ? pTag->ForExpr : "" ); + if( hb_itemType( pInfo->itmNewVal ) & HB_IT_STRING ) + { + char * szForExpr = hb_itemGetCPtr( pInfo->itmNewVal ); + if( pTag->ForExpr ? + strncmp( pTag->ForExpr, szForExpr, NTX_MAX_EXP ) != 0 : + *szForExpr ) + { + PHB_ITEM pForItem = NULL; + BOOL fOK = *szForExpr == 0; + if( !fOK ) + { + if( SELF_COMPILE( ( AREAP ) pArea, ( BYTE *) szForExpr ) == SUCCESS ) + { + pForItem = pArea->valResult; + pArea->valResult = NULL; + if( SELF_EVALBLOCK( ( AREAP ) pArea, pForItem ) == SUCCESS ) + { + fOK = hb_itemType( pArea->valResult ) == HB_IT_LOGICAL; + hb_itemRelease( pArea->valResult ); + pArea->valResult = NULL; + } + } + } + if( fOK && hb_ntxTagLockWrite( pTag ) ) + { + if( pTag->ForExpr ) + hb_xfree( pTag->ForExpr ); + if( pTag->pForItem ) + hb_ntxDestroyExp( pTag->pForItem ); + if( pForItem ) + { + pTag->ForExpr = hb_strndup( szForExpr, NTX_MAX_EXP ); + pTag->pForItem = pForItem; + pForItem = NULL; + } + else + { + pTag->ForExpr = NULL; + pTag->pForItem = NULL; + } + pTag->Partial = TRUE; + pTag->HdrChanged = TRUE; + pTag->Owner->Update = TRUE; + hb_ntxTagUnLockWrite( pTag ); + } + if( pForItem ) + hb_ntxDestroyExp( pForItem ); + } + } break; case DBOI_EXPRESSION: - hb_itemPutC( pInfo->itmResult , pTag->KeyExpr ); + hb_itemPutC( pInfo->itmResult, pTag->KeyExpr ); break; case DBOI_BAGNAME: hb_itemPutC( pInfo->itmResult, pTag->Owner->IndexName ); @@ -3933,315 +6561,594 @@ static ERRCODE ntxOrderInfo( NTXAREAP pArea, USHORT uiIndex, LPDBORDERINFO pInfo hb_itemPutC( pInfo->itmResult, pTag->TagName ); break; case DBOI_NUMBER: - hb_itemPutNI( pInfo->itmResult, pTag->TagRoot ); + hb_itemPutNI( pInfo->itmResult, hb_ntxFindTagNum( pArea, pTag ) ); + break; + case DBOI_FILEHANDLE: + hb_itemPutNInt( pInfo->itmResult, pTag->Owner->DiskFile ); + break; + case DBOI_FULLPATH: + hb_itemPutC( pInfo->itmResult, pTag->Owner->IndexName ); break; case DBOI_KEYCOUNT: - hb_itemPutNL( pInfo->itmResult, hb_ntxTagKeyCount( pTag ) ); + hb_itemPutNL( pInfo->itmResult, hb_ntxOrdKeyCount( pTag ) ); break; case DBOI_POSITION: - hb_itemPutNL( pInfo->itmResult, hb_ntxTagKeyNo( pTag ) ); + if( hb_itemType( pInfo->itmNewVal ) & HB_IT_NUMERIC ) + hb_itemPutL( pInfo->itmResult, + hb_ntxOrdKeyGoto( pTag, hb_itemGetNL( pInfo->itmNewVal ) ) ); + else + hb_itemPutNL( pInfo->itmResult, hb_ntxOrdKeyNo( pTag ) ); + break; + case DBOI_RELKEYPOS: + if( hb_itemType( pInfo->itmNewVal ) & HB_IT_NUMERIC ) + hb_ntxOrdSetRelKeyPos( pTag, hb_itemGetND( pInfo->itmNewVal ) ); + else + hb_itemPutND( pInfo->itmResult, hb_ntxOrdGetRelKeyPos( pTag ) ); break; case DBOI_ISCOND: - hb_itemPutL( pInfo->itmResult, (pTag->ForExpr!=NULL) ); + hb_itemPutL( pInfo->itmResult, pTag->ForExpr != NULL ); break; case DBOI_ISDESC: - hb_itemPutL( pInfo->itmResult, !pTag->AscendKey ); + hb_itemPutL( pInfo->itmResult, pTag->fUsrDescend ); + if( hb_itemType( pInfo->itmNewVal ) == HB_IT_LOGICAL ) + pTag->fUsrDescend = hb_itemGetL( pInfo->itmNewVal ); break; case DBOI_UNIQUE: hb_itemPutL( pInfo->itmResult, pTag->UniqueKey ); break; case DBOI_CUSTOM: + if( hb_itemType( pInfo->itmNewVal ) == HB_IT_LOGICAL ) + { + if( hb_ntxTagLockWrite( pTag ) ) + { + if( !pTag->Template ) + { + BOOL fNewVal = hb_itemGetL( pInfo->itmNewVal ); + if( pTag->Custom ? ! fNewVal : fNewVal ) + { + pTag->Custom = fNewVal; + pTag->Partial = TRUE; + pTag->ChgOnly = FALSE; + pTag->HdrChanged = TRUE; + } + } + hb_ntxTagUnLockWrite( pTag ); + } + } hb_itemPutL( pInfo->itmResult, pTag->Custom ); break; - case DBOI_SCOPETOP : - ntxScopeInfo( pArea, 0, pInfo->itmResult ) ; + case DBOI_CHGONLY: + if( hb_itemType( pInfo->itmNewVal ) == HB_IT_LOGICAL ) + { + if( hb_ntxTagLockWrite( pTag ) ) + { + if( !pTag->Custom ) + { + BOOL fNewVal = hb_itemGetL( pInfo->itmNewVal ); + if( pTag->ChgOnly ? ! fNewVal : fNewVal ) + { + pTag->ChgOnly = fNewVal; + pTag->Partial = TRUE; + pTag->HdrChanged = TRUE; + } + } + hb_ntxTagUnLockWrite( pTag ); + } + } + hb_itemPutL( pInfo->itmResult, pTag->ChgOnly ); break; - case DBOI_SCOPEBOTTOM : - ntxScopeInfo( pArea, 1, pInfo->itmResult ) ; + case DBOI_TEMPLATE: + if( hb_itemType( pInfo->itmNewVal ) == HB_IT_LOGICAL && + hb_itemGetL( pInfo->itmNewVal ) ) + { + if( hb_ntxTagLockWrite( pTag ) ) + { + if( pTag->Custom && !pTag->Template ) + { + pTag->Template = TRUE; + pTag->HdrChanged = TRUE; + } + hb_ntxTagUnLockWrite( pTag ); + } + } + hb_itemPutL( pInfo->itmResult, pTag->Template ); break; - case DBOI_SCOPETOPCLEAR : - ntxScopeInfo( pArea, 0, pInfo->itmResult ) ; - hb_ntxClearScope( pTag, 0 ); + case DBOI_MULTIKEY: + if( hb_itemGetL( pInfo->itmNewVal ) ) + { + if( hb_ntxTagLockWrite( pTag ) ) + { + if( pTag->Custom && !pTag->MultiKey ) + { + pTag->MultiKey = TRUE; + pTag->HdrChanged = TRUE; + } + hb_ntxTagUnLockWrite( pTag ); + } + } + hb_itemPutL( pInfo->itmResult, pTag->MultiKey ); break; - case DBOI_SCOPEBOTTOMCLEAR : - ntxScopeInfo( pArea, 1, pInfo->itmResult ) ; - hb_ntxClearScope( pTag, 1 ); + case DBOI_PARTIAL: + hb_itemPutL( pInfo->itmResult, pTag->Partial ); break; + case DBOI_SCOPETOP: + if( pInfo->itmResult ) + hb_ntxTagGetScope( pTag, 0, pInfo->itmResult ); + if( pInfo->itmNewVal ) + hb_ntxTagSetScope( pTag, 0, pInfo->itmNewVal ); + break; + case DBOI_SCOPEBOTTOM: + if( pInfo->itmResult ) + hb_ntxTagGetScope( pTag, 1, pInfo->itmResult ); + if( pInfo->itmNewVal ) + hb_ntxTagSetScope( pTag, 1, pInfo->itmNewVal ); + break; + case DBOI_SCOPESET: + if( pInfo->itmNewVal ) + { + hb_ntxTagSetScope( pTag, 0, pInfo->itmNewVal ); + hb_ntxTagSetScope( pTag, 1, pInfo->itmNewVal ); + } + if( pInfo->itmResult ) + hb_itemClear( pInfo->itmResult ); + break; + case DBOI_SCOPETOPCLEAR: + if( pInfo->itmResult ) + hb_ntxTagGetScope( pTag, 0, pInfo->itmResult ); + hb_ntxTagClearScope( pTag, 0 ); + break; + case DBOI_SCOPEBOTTOMCLEAR: + if( pInfo->itmResult ) + hb_ntxTagGetScope( pTag, 1, pInfo->itmResult ); + hb_ntxTagClearScope( pTag, 1 ); + break; + case DBOI_SCOPECLEAR: + hb_ntxTagClearScope( pTag, 0 ); + hb_ntxTagClearScope( pTag, 1 ); + if( pInfo->itmResult ) + hb_itemClear( pInfo->itmResult ); case DBOI_KEYADD: - hb_itemPutL( pInfo->itmResult, hb_ntxOrdKeyAdd( pTag ) ); + if ( pTag->Custom ) + { + hb_itemPutL( pInfo->itmResult, + hb_ntxOrdKeyAdd( pTag, pInfo->itmNewVal ) ); + } + else + { + hb_ntxErrorRT( pArea, 0, 1052, NULL, 0, 0 ); + } break; case DBOI_KEYDELETE: - hb_itemPutL( pInfo->itmResult, hb_ntxOrdKeyDel( pTag ) ); + if ( pTag->Custom ) + { + hb_itemPutL( pInfo->itmResult, + hb_ntxOrdKeyDel( pTag, pInfo->itmNewVal ) ); + } + else + { + hb_ntxErrorRT( pArea, 0, 1052, NULL, 0, 0 ); + } + break; + case DBOI_KEYTYPE: + { + char szType[2]; + szType[0] = (char) pTag->KeyType; + szType[1] = 0; + hb_itemPutC( pInfo->itmResult, szType ); + } + break; + case DBOI_KEYSIZE: + hb_itemPutNI( pInfo->itmResult, pTag->KeyLength ); + break; + case DBOI_KEYDEC: + hb_itemPutNI( pInfo->itmResult, pTag->KeyDec ); break; case DBOI_KEYVAL: - if( pTag->CurKeyInfo->Tag ) + if( hb_ntxCurKeyRefresh( pTag ) ) + hb_ntxKeyGetItem( pInfo->itmResult, pTag->CurKeyInfo, pTag, TRUE ); + else + hb_itemClear( pInfo->itmResult ); + break; + case DBOI_SKIPUNIQUE: + hb_itemPutL( pInfo->itmResult, hb_ntxOrdSkipUnique( pTag, + hb_itemGetNL( pInfo->itmNewVal ) ) ); + break; + case DBOI_SKIPEVAL: + case DBOI_SKIPEVALBACK: + hb_itemPutL( pInfo->itmResult, hb_ntxOrdSkipEval( pTag, + uiIndex == DBOI_SKIPEVAL, pInfo->itmNewVal ) ); + break; + case DBOI_SKIPWILD: + case DBOI_SKIPWILDBACK: + hb_itemPutL( pInfo->itmResult, hb_ntxOrdSkipWild( pTag, + uiIndex == DBOI_SKIPWILD, pInfo->itmNewVal ) ); + break; +#if defined(__XHARBOUR__) + case DBOI_SKIPREGEX: + case DBOI_SKIPREGEXBACK: + hb_itemPutL( pInfo->itmResult, hb_ntxOrdSkipRegEx( pTag, + uiIndex == DBOI_SKIPREGEX, pInfo->itmNewVal ) ); + break; +#endif + case DBOI_FINDREC: + case DBOI_FINDRECCONT: + hb_itemPutL( pInfo->itmResult, hb_ntxOrdFindRec( pTag, + hb_itemGetNL( pInfo->itmNewVal ), + uiIndex == DBOI_FINDRECCONT ) ); + break; + case DBOI_SCOPEEVAL: + if( hb_arrayLen( pInfo->itmNewVal ) == DBRMI_SIZE && + hb_arrayGetPtr( pInfo->itmNewVal, DBRMI_FUNCTION ) != NULL ) { + hb_itemPutNL( pInfo->itmResult, hb_ntxOrdScopeEval( pTag, + ( HB_EVALSCOPE_FUNC ) + hb_arrayGetPtr( pInfo->itmNewVal, DBRMI_FUNCTION ), + hb_arrayGetPtr( pInfo->itmNewVal, DBRMI_PARAM ), + hb_arrayGetItemPtr( pInfo->itmNewVal, DBRMI_LOVAL ), + hb_arrayGetItemPtr( pInfo->itmNewVal, DBRMI_HIVAL ) ) ); } else { + hb_itemPutNI( pInfo->itmResult, 0 ); } break; - case DBOI_ORDERCOUNT: - if( pInfo->atomBagName && (char*) hb_itemGetCPtr( pInfo->atomBagName ) ) + case DBOI_UPDATECOUNTER: + /* refresh update counter */ + if( hb_ntxIndexLockRead( pTag->Owner ) ) + hb_ntxIndexUnLockRead( pTag->Owner ); + hb_itemPutNInt( pInfo->itmResult, pTag->Owner->Version ); + break; + case DBOI_READLOCK: + if( hb_itemType( pInfo->itmNewVal ) == HB_IT_LOGICAL ) { - hb_itemPutNL( pInfo->itmResult, 1 ); + hb_itemPutL( pInfo->itmResult, + hb_itemGetL( pInfo->itmNewVal ) ? + hb_ntxIndexLockRead( pTag->Owner ) : + hb_ntxIndexUnLockRead( pTag->Owner ) ); } else { - LPTAGINFO current = pArea->lpNtxTag; - int i = 0; - do - { - i ++; - current = current->pNext; - } while( current ); - hb_itemPutNL( pInfo->itmResult, i ); + hb_itemPutL( pInfo->itmResult, pTag->Owner->lockRead > 0 ); } break; + case DBOI_WRITELOCK: + if( hb_itemType( pInfo->itmNewVal ) == HB_IT_LOGICAL ) + { + hb_itemPutL( pInfo->itmResult, + hb_itemGetL( pInfo->itmNewVal ) ? + hb_ntxIndexLockWrite( pTag->Owner, TRUE ) : + hb_ntxIndexUnLockWrite( pTag->Owner ) ); + } + else + { + hb_itemPutL( pInfo->itmResult, pTag->Owner->lockWrite > 0 ); + } + break; + case DBOI_ISSORTRECNO: + hb_itemPutL( pInfo->itmResult, pTag->fSortRec ); + break; + case DBOI_ISMULTITAG: +#if defined( HB_NTX_NOMULTITAG ) + hb_itemPutL( pInfo->itmResult, FALSE ); +#else + hb_itemPutL( pInfo->itmResult, pTag->Owner->Compound ); +#endif + break; + case DBOI_LARGEFILE: + hb_itemPutL( pInfo->itmResult, pTag->Owner->LargeFile ); + break; + case DBOI_SHARED: + hb_itemPutL( pInfo->itmResult, pTag->Owner->fShared ); + if( hb_itemType( pInfo->itmNewVal ) == HB_IT_LOGICAL ) + pTag->Owner->fShared = hb_itemGetL( pInfo->itmNewVal ); + break; + case DBOI_ISREADONLY: + hb_itemPutL( pInfo->itmResult, pTag->Owner->fReadonly ); + break; } } - else + else if( pInfo->itmResult ) + { switch( uiIndex ) { case DBOI_KEYCOUNT: { ULONG ulRecCount = 0; SELF_RECCOUNT( ( AREAP ) pArea, &ulRecCount ); - hb_itemPutND( pInfo->itmResult,ulRecCount ); + hb_itemPutNInt( pInfo->itmResult, ulRecCount ); break; } case DBOI_POSITION: - { - hb_itemPutND( pInfo->itmResult,0 ); - SELF_RECNO( ( AREAP ) pArea, pInfo->itmResult ); + if( pInfo->itmNewVal && hb_itemType( pInfo->itmNewVal ) & HB_IT_NUMERIC ) + hb_itemPutL( pInfo->itmResult, SELF_GOTO( ( AREAP ) pArea, + hb_itemGetNL( pInfo->itmNewVal ) ) == SUCCESS ); + else + SELF_RECID( ( AREAP ) pArea, pInfo->itmResult ); + break; + case DBOI_RELKEYPOS: + if( hb_itemType( pInfo->itmNewVal ) & HB_IT_NUMERIC ) + { + double dPos = hb_itemGetND( pInfo->itmNewVal ); + LPTAGINFO pSavedTag = pArea->lpCurTag; + pArea->lpCurTag = NULL; + if( dPos >= 1.0 ) + { + SELF_GOBOTTOM( ( AREAP ) pArea ); + } + else if( dPos <= 0.0 ) + { + SELF_GOTOP( ( AREAP ) pArea ); + } + else + { + ULONG ulRecCount, ulRecNo; + SELF_RECCOUNT( ( AREAP ) pArea, &ulRecCount ); + ulRecNo = ( ULONG ) dPos * ulRecCount + 1; + if( ulRecNo >= ulRecCount ) + ulRecNo = ulRecCount; + SELF_GOTO( ( AREAP ) pArea, ulRecNo ); + SELF_SKIPFILTER( ( AREAP ) pArea, 1 ); + if( pArea->fEof ) + SELF_GOTOP( ( AREAP ) pArea ); + } + pArea->lpCurTag = pSavedTag; + } + else + { + ULONG ulRecNo = 0, ulRecCount = 0; + double dPos = 0.0; + /* resolve any pending relations */ + SELF_RECNO( ( AREAP ) pArea, &ulRecNo ); + if( !pArea->fPositioned ) + { + if( ulRecNo > 1 ) + dPos = 1.0; + } + else + { + SELF_RECCOUNT( ( AREAP ) pArea, &ulRecCount ); + if( ulRecCount != 0 ) + dPos = ( 0.5 + ulRecNo ) / ulRecCount; + } + hb_itemPutND( pInfo->itmResult, dPos ); + } + break; + case DBOI_SKIPUNIQUE: + hb_itemPutL( pInfo->itmResult, SELF_SKIP( ( AREAP ) pArea, + hb_itemGetNL( pInfo->itmNewVal ) >= 0 ? 1 : -1 ) == SUCCESS ); + break; + case DBOI_SKIPEVAL: + case DBOI_SKIPEVALBACK: + case DBOI_SKIPWILD: + case DBOI_SKIPWILDBACK: + case DBOI_SKIPREGEX: + case DBOI_SKIPREGEXBACK: + case DBOI_FINDREC: + case DBOI_FINDRECCONT: + SELF_GOTO( ( AREAP ) pArea, 0 ); + hb_itemPutL( pInfo->itmResult, FALSE ); break; - } case DBOI_ISCOND: case DBOI_ISDESC: case DBOI_UNIQUE: case DBOI_CUSTOM: case DBOI_KEYADD: case DBOI_KEYDELETE: - hb_itemPutL( pInfo->itmResult, 0 ); + + case DBOI_ISSORTRECNO: + case DBOI_ISMULTITAG: + case DBOI_LARGEFILE: + case DBOI_TEMPLATE: + case DBOI_MULTIKEY: + case DBOI_PARTIAL: + case DBOI_CHGONLY: + case DBOI_SHARED: + case DBOI_ISREADONLY: + case DBOI_WRITELOCK: + case DBOI_READLOCK: + hb_itemPutL( pInfo->itmResult, FALSE ); break; case DBOI_KEYVAL: - case DBOI_SCOPETOP : - case DBOI_SCOPEBOTTOM : - case DBOI_SCOPETOPCLEAR : - case DBOI_SCOPEBOTTOMCLEAR : + case DBOI_SCOPETOP: + case DBOI_SCOPEBOTTOM: + case DBOI_SCOPESET: + case DBOI_SCOPETOPCLEAR: + case DBOI_SCOPEBOTTOMCLEAR: + case DBOI_SCOPECLEAR: hb_itemClear( pInfo->itmResult ); break; + case DBOI_KEYSIZE: + case DBOI_KEYDEC: case DBOI_NUMBER: case DBOI_ORDERCOUNT: - hb_itemPutNL( pInfo->itmResult, 0 ); + case DBOI_SCOPEEVAL: + case DBOI_UPDATECOUNTER: + hb_itemPutNI( pInfo->itmResult, 0 ); + break; + case DBOI_FILEHANDLE: + hb_itemPutNInt( pInfo->itmResult, FS_ERROR ); break; default: hb_itemPutC( pInfo->itmResult, "" ); } - return SUCCESS; -} - -static ERRCODE ntxClearScope( NTXAREAP pArea ) -{ - HB_TRACE(HB_TR_DEBUG, ("ntxClearScope(%p)", pArea )); - if( pArea->lpCurTag ) - { - hb_ntxClearScope( pArea->lpCurTag, 0 ); - hb_ntxClearScope( pArea->lpCurTag, 1 ); } return SUCCESS; } -static ERRCODE ntxScopeInfo( NTXAREAP pArea, USHORT nScope, PHB_ITEM pItem ) +static ERRCODE ntxCountScope( NTXAREAP pArea, void * pPtr, LONG * plRecNo ) { - USHORT nKeyType; + HB_TRACE(HB_TR_DEBUG, ("ntxCountScope(%p, %p, %p)", pArea, pPtr, plRecNo)); - HB_TRACE(HB_TR_DEBUG, ("ntxScopeInfo(%p, %hu, %p)", pArea, nScope, pItem)); - - if( !pArea->lpCurTag || ( (nScope) ? !pArea->lpCurTag->bottomScope : - !pArea->lpCurTag->topScope ) ) - hb_itemClear( pItem ); - else + if ( pPtr == NULL ) { - LPTAGINFO pTag = pArea->lpCurTag; - - nKeyType = hb_ntxGetKeyType( pTag ); - switch( nKeyType ) - { - case HB_IT_STRING: - hb_itemCopy( pItem, (nScope)? pTag->bottomScope:pTag->topScope ); - break; - case HB_IT_INTEGER: - case HB_IT_LONG: - case HB_IT_DOUBLE: - if ( nScope ) - hb_itemPutND( pItem, hb_strVal( pTag->bottomScope->item.asString.value, - pTag->bottomScope->item.asString.length ) ); - else - hb_itemPutND( pItem, hb_strVal( pTag->topScope->item.asString.value, - pTag->topScope->item.asString.length ) ); - break; - case HB_IT_DATE: - hb_itemPutDS( pItem, (nScope)? pTag->bottomScope->item.asString.value:pTag->topScope->item.asString.value ); - break; - } + return SUCCESS; } - return SUCCESS; + return SUPER_COUNTSCOPE( ( AREAP ) pArea, pPtr, plRecNo ); } static ERRCODE ntxOrderListAdd( NTXAREAP pArea, LPDBORDERINFO pOrderInfo ) { USHORT uiFlags; - char * szFileName; - PHB_FNAME pFileName; - DBORDERINFO pExtInfo; - LPNTXINDEX pIndex; - LPTAGINFO pTagNext; - PHB_ITEM pError = NULL; - BOOL bRetry; + FHANDLE hFile; + char szFileName[ _POSIX_PATH_MAX + 1 ], szTagName[ NTX_MAX_TAGNAME + 1 ]; + LPNTXINDEX pIndex, *pIndexPtr; + ERRCODE errCode; + BOOL fRetry, fReadonly, fShared, fProd; HB_TRACE(HB_TR_DEBUG, ("ntxOrderListAdd(%p, %p)", pArea, pOrderInfo)); - if( SELF_GOCOLD( ( AREAP ) pArea ) == FAILURE ) + errCode = SELF_GOCOLD( ( AREAP ) pArea ); + if( errCode != SUCCESS ) + return errCode; + + if( hb_itemGetCLen( pOrderInfo->atomBagName ) == 0 ) return FAILURE; - szFileName = ( char * ) hb_xgrab( _POSIX_PATH_MAX + 1 ); - hb_strncpy( szFileName, hb_itemGetCPtr( pOrderInfo->atomBagName ), _POSIX_PATH_MAX ); - if( strlen( szFileName ) == 0 ) - { - hb_xfree( szFileName ); + hb_ntxCreateFName( pArea, hb_itemGetCPtr( pOrderInfo->atomBagName ), + &fProd, szFileName, szTagName ); + + if( ! szTagName[0] ) return FAILURE; - } - pFileName = hb_fsFNameSplit( szFileName ); - if( !pFileName->szExtension ) - { - pExtInfo.itmResult = hb_itemPutC( NULL, "" ); - SELF_ORDINFO( ( AREAP ) pArea, DBOI_BAGEXT, &pExtInfo ); - hb_strncat( szFileName, hb_itemGetCPtr( pExtInfo.itmResult ), _POSIX_PATH_MAX ); - hb_itemRelease( pExtInfo.itmResult ); - } - pIndex = hb_ntxIndexNew( pArea ); - /* Index file could be opened with FO_READ only in exclusive readonly mode - to allow locking in other modes - Alexander, it's not proper solution. It will cause that you cannot open - readonly files in exclusive mode. Shared locks should be used instead - this hack for readonly mode. - */ - uiFlags = ( pArea->fReadonly ? FO_READ : FO_READWRITE ) | - ( pArea->fShared ? FO_DENYNONE : FO_EXCLUSIVE ); + pIndex = hb_ntxFindBag( pArea, szFileName ); - do + if( ! pIndex ) { - pIndex->DiskFile = hb_spOpen( ( BYTE * ) szFileName, uiFlags ); - if( pIndex->DiskFile == FS_ERROR ) - { - if( !pError ) - { - pError = hb_errNew(); - hb_errPutGenCode( pError, EG_OPEN ); - hb_errPutSubCode( pError, 1003 ); - hb_errPutOsCode( pError, hb_fsError() ); - hb_errPutDescription( pError, hb_langDGetErrorDesc( EG_OPEN ) ); - hb_errPutFileName( pError, szFileName ); - hb_errPutFlags( pError, EF_CANRETRY | EF_CANDEFAULT ); - } - bRetry = ( SELF_ERROR( ( AREAP ) pArea, pError ) == E_RETRY ); - } - else - bRetry = FALSE; - } while( bRetry ); - if( pError ) - hb_errRelease( pError ); - - if( pIndex->DiskFile == FS_ERROR ) - { - ntxOrderListClear( pArea ); - hb_xfree( pIndex ); - hb_xfree( szFileName ); - hb_xfree( pFileName ); - return FAILURE; - } - - if( hb_ntxHeaderLoad( pIndex, pFileName->szName ) == FAILURE ) - { - hb_xfree( pIndex ); - hb_xfree( szFileName ); - hb_xfree( pFileName ); - hb_fsClose( pIndex->DiskFile ); - return FAILURE; - } - pIndex->IndexName = ( char * ) hb_xgrab( _POSIX_PATH_MAX + 1 ); - pIndex->IndexName[0] = '\0'; - strncat( pIndex->IndexName, szFileName, _POSIX_PATH_MAX ); - - if( !pArea->lpCurTag ) - pArea->lpCurTag = pIndex->CompoundTag; - if( pArea->lpNtxTag ) - { - pIndex->CompoundTag->TagRoot++; - pTagNext = pArea->lpNtxTag; - while( pTagNext->pNext ) + fReadonly = pArea->fReadonly; + fShared = pArea->fShared; + uiFlags = ( fReadonly ? FO_READ : FO_READWRITE ) | + ( fShared ? FO_DENYNONE : FO_EXCLUSIVE ); + do { - pIndex->CompoundTag->TagRoot++; - pTagNext = pTagNext->pNext; + fRetry = FALSE; + hFile = hb_fsExtOpen( ( BYTE * ) szFileName, NULL, uiFlags | + FXO_DEFAULTS | FXO_SHARELOCK | FXO_COPYNAME, + NULL, NULL ); + if( hFile == FS_ERROR ) + { + fRetry = ( hb_ntxErrorRT( pArea, EG_OPEN, EDBF_OPEN_INDEX, szFileName, + hb_fsError(), EF_CANRETRY | EF_CANDEFAULT ) == E_RETRY ); + } } - pTagNext->pNext = pIndex->CompoundTag; - } - else - { - pArea->lpNtxTag = pIndex->CompoundTag; - SELF_GOTOP( ( AREAP ) pArea ); + while( fRetry ); + + if( hFile == FS_ERROR ) + return FAILURE; + + pIndex = hb_ntxIndexNew( pArea ); + pIndex->IndexName = hb_strdup( szFileName ); + pIndex->fReadonly = fReadonly; + pIndex->fShared = fShared; + pIndex->DiskFile = hFile; + + pIndexPtr = &pArea->lpIndexes; + while( *pIndexPtr ) + pIndexPtr = &(*pIndexPtr)->pNext; + *pIndexPtr = pIndex; + + if( hb_ntxIndexLockRead( pIndex ) ) + { + errCode = hb_ntxIndexLoad( pIndex, szTagName ); + hb_ntxIndexUnLockRead( pIndex ); + } + else + errCode = FAILURE; + + if( errCode != SUCCESS ) + { + *pIndexPtr = pIndex->pNext; + hb_ntxIndexFree( pIndex ); + hb_ntxErrorRT( pArea, EG_CORRUPTION, EDBF_CORRUPT, szFileName, 0, 0 ); + return errCode; + } + /* hb_ntxSetTagNumbers() */ } - hb_xfree( szFileName ); - hb_xfree( pFileName ); - return SUCCESS; + if( !pArea->lpCurTag && pIndex->iTags ) + { + pArea->lpCurTag = pIndex->lpTags[0]; + errCode = SELF_GOTOP( ( AREAP ) pArea ); + } + return errCode; } static ERRCODE ntxOrderListClear( NTXAREAP pArea ) { - LPTAGINFO pTag, pTagNext; + LPNTXINDEX *pIndexPtr, pIndex; HB_TRACE(HB_TR_DEBUG, ("ntxOrderListClear(%p)", pArea)); if( SELF_GOCOLD( ( AREAP ) pArea ) == FAILURE ) return FAILURE; - pTag = pArea->lpNtxTag; - while( pTag ) - { - pTagNext = pTag->pNext; - hb_ntxIndexFree( pTag->Owner ); - pTag = pTagNext; - } - pArea->lpNtxTag = NULL; pArea->lpCurTag = NULL; + pIndexPtr = &pArea->lpIndexes; + while( *pIndexPtr ) + { + pIndex = *pIndexPtr; + if( s_fStruct && pIndex->Production && + ( s_fStrictStruct ? pArea->fHasTags : hb_set.HB_SET_AUTOPEN ) ) + { + pIndexPtr = &pIndex->pNext; + } + else + { + *pIndexPtr = pIndex->pNext; + hb_ntxIndexFree( pIndex ); + } + } + /* hb_ntxSetTagNumbers() */ + return SUCCESS; +} + +static ERRCODE ntxOrderListDelete( NTXAREAP pArea, LPDBORDERINFO pOrderInfo ) +{ + char szTagName[ NTX_MAX_TAGNAME + 1 ]; + char szFileName[ _POSIX_PATH_MAX + 1 ]; + LPNTXINDEX pIndex = NULL, * pIndexPtr; + BOOL fProd; + + HB_TRACE(HB_TR_DEBUG, ("ntxOrderListDelete(%p, %p)", pArea, pOrderInfo)); + + if( SELF_GOCOLD( ( AREAP ) pArea ) == FAILURE ) + return FAILURE; + + hb_ntxCreateFName( pArea, hb_itemGetCPtr( pOrderInfo->atomBagName ), &fProd, + szFileName, szTagName ); + + if( szTagName[0] ) + pIndex = hb_ntxFindBag( pArea, szFileName ); + + if( pIndex ) + { + pIndexPtr = &pArea->lpIndexes; + while( *pIndexPtr ) + { + if( pIndex == *pIndexPtr ) + { + *pIndexPtr = pIndex->pNext; + hb_ntxIndexFree( pIndex ); + /* hb_ntxSetTagNumbers() */ + break; + } + pIndexPtr = &(*pIndexPtr)->pNext; + } + } return SUCCESS; } static ERRCODE ntxOrderListFocus( NTXAREAP pArea, LPDBORDERINFO pOrderInfo ) { - LPTAGINFO pTag; - HB_TRACE(HB_TR_DEBUG, ("ntxOrderListFocus(%p, %p)", pArea, pOrderInfo)); pOrderInfo->itmResult = hb_itemPutC( pOrderInfo->itmResult, - (pArea->lpCurTag) ? pArea->lpCurTag->TagName : "" ); + pArea->lpCurTag ? pArea->lpCurTag->TagName : "" ); if( pOrderInfo->itmOrder ) { - if( hb_itemType( pOrderInfo->itmOrder ) != HB_IT_STRING && - hb_itemGetNI( pOrderInfo->itmOrder ) == 0 ) - { - pArea->lpCurTag = NULL; - } - else - { - pTag = ntxFindIndex( pArea, pOrderInfo->itmOrder ); - if( pTag ) - pArea->lpCurTag = pTag; - } + /* TODO: In Clipper tag is not changed when bad name is given */ + pArea->lpCurTag = hb_ntxFindTag( pArea, pOrderInfo->itmOrder, + pOrderInfo->atomBagName ); } return SUCCESS; @@ -4249,110 +7156,134 @@ static ERRCODE ntxOrderListFocus( NTXAREAP pArea, LPDBORDERINFO pOrderInfo ) static ERRCODE ntxOrderListRebuild( NTXAREAP pArea ) { - LPTAGINFO pTag, pTagTmp; + LPTAGINFO pCurrTag; + LPNTXINDEX pIndex; + ERRCODE errCode; HB_TRACE(HB_TR_DEBUG, ("ntxOrderListRebuild(%p)", pArea)); - if( SELF_GOCOLD( ( AREAP ) pArea ) == FAILURE ) - return FAILURE; + errCode = SELF_GOCOLD( ( AREAP ) pArea ); + if( errCode != SUCCESS ) + return errCode; - pTag = pArea->lpNtxTag; - pTagTmp = pArea->lpCurTag; - pArea->fValidBuffer = TRUE; - while( pTag ) + if( pArea->fShared ) { - hb_ntxPageFree( pTag,TRUE ); - if( pTag->Memory ) - { - pTag->ulPagesDepth = 0; - hb_xfree( pTag->pages ); - } - else - { - hb_fsSeek( pTag->Owner->DiskFile, NTXBLOCKSIZE, FS_SET ); - hb_fsWrite( pTag->Owner->DiskFile, NULL, 0 ); - pTag->Owner->fFlush = TRUE; - } - pTag->RootBlock = 0; - pTag->keyCount = pTag->Owner->NextAvail = 0; - hb_ntxIndexCreate( pTag->Owner ); - - if( !pTag->Memory ) - { - hb_ntxHeaderSave( pTag->Owner, TRUE ); - hb_fsSeek( pTag->Owner->DiskFile , 0 , 0 ); - pTag->TagBlock = hb_fsSeek( pTag->Owner->DiskFile, 0, SEEK_END ) - 1024; - } - - pTag = pTag->pNext; + hb_ntxErrorRT( pArea, EG_SHARED, EDBF_SHARED, pArea->szDataFileName, 0, 0 ); + return FAILURE; } - pArea->lpCurTag = pTagTmp; - return SELF_GOTOP( ( AREAP ) pArea ); -} - -static ERRCODE ntxClose( NTXAREAP pArea ) -{ - HB_TRACE(HB_TR_DEBUG, ("ntxClose(%p)", pArea)); - - if( SELF_GOCOLD( ( AREAP ) pArea ) == FAILURE ) - return FAILURE; - ntxOrderListClear( pArea ); - return SUPER_CLOSE( ( AREAP ) pArea ); -} - -static ERRCODE ntxSetScope( NTXAREAP pArea, LPDBORDSCOPEINFO sInfo ) -{ - if( pArea->lpCurTag ) + if( pArea->fReadonly ) { - LPTAGINFO pTag = pArea->lpCurTag; - USHORT nKeyType = hb_ntxGetKeyType( pTag ); - PHB_ITEM *ppItem; - USHORT nScope = sInfo->nScope; - char szBuffer[ NTX_MAX_KEY ]; + hb_ntxErrorRT( pArea, EG_READONLY, EDBF_READONLY, pArea->szDataFileName, 0, 0 ); + return FAILURE; + } - ppItem = (nScope) ? &(pTag->bottomScope) : &(pTag->topScope); + if( pArea->lpdbPendingRel ) + { + errCode = SELF_FORCEREL( ( AREAP ) pArea ); + if( errCode != SUCCESS ) + return errCode; + } + pCurrTag = pArea->lpCurTag; + pArea->lpCurTag = NULL; + pIndex = pArea->lpIndexes; + while( pIndex && errCode == SUCCESS ) + { + errCode = hb_ntxReIndex( pIndex ); + pIndex = pIndex->pNext; + } + if( errCode == SUCCESS ) + { + pArea->lpCurTag = pCurrTag; + errCode = SELF_GOTOP( ( AREAP ) pArea ); + } + return errCode; +} - pTag->keyCount = 0; - if( !sInfo->scopeValue ) +static ERRCODE ntxRddInfo( LPRDDNODE pRDD, USHORT uiIndex, ULONG ulConnect, PHB_ITEM pItem ) +{ + LPDBFDATA pData; + + HB_TRACE(HB_TR_DEBUG, ("ntxRddInfo(%p, %hu, %lu, %p)", pRDD, uiIndex, ulConnect, pItem)); + + pData = ( LPDBFDATA ) pRDD->lpvCargo; + + switch( uiIndex ) + { + case RDDI_ORDBAGEXT: + case RDDI_ORDEREXT: + case RDDI_ORDSTRUCTEXT: { - hb_itemRelease( *ppItem ); - *ppItem = NULL; - } - else - switch( nKeyType ) + char * szNew = hb_itemGetCPtr( pItem ); + + if( szNew[0] == '.' && szNew[1] ) + szNew = hb_strdup( szNew ); + else + szNew = NULL; + + hb_itemPutC( pItem, pData->szIndexExt[ 0 ] ? pData->szIndexExt : NTX_INDEXEXT ); + if( szNew ) { - case HB_IT_STRING: - if ( sInfo->scopeValue->type == HB_IT_STRING ) - { - if( *ppItem == NULL ) - *ppItem = hb_itemNew( NULL ); - hb_itemCopy( *ppItem, sInfo->scopeValue ); -#ifndef HB_CDP_SUPPORT_OFF - hb_cdpnTranslate( (*ppItem)->item.asString.value, hb_cdp_page, pArea->cdPage, (*ppItem)->item.asString.length ); -#endif - } - break; - case HB_IT_INTEGER: - case HB_IT_LONG: - case HB_IT_DOUBLE: - if ( sInfo->scopeValue->type & HB_IT_NUMERIC ) - { - if( *ppItem == NULL ) - *ppItem = hb_itemNew( NULL ); - hb_itemPutC( *ppItem, numToStr( sInfo->scopeValue, szBuffer, pTag->KeyLength, pTag->KeyDec ) ); - } - break; - case HB_IT_DATE: - if ( sInfo->scopeValue->type == HB_IT_DATE ) - { - if( *ppItem == NULL ) - *ppItem = hb_itemNew( NULL ); - hb_itemGetDS( sInfo->scopeValue, szBuffer ); - hb_itemPutC( *ppItem,szBuffer ); - } - break; + hb_strncpy( pData->szIndexExt, szNew, HB_MAX_FILE_EXT ); + hb_xfree( szNew ); } + break; + } + + case RDDI_MULTITAG: + { +#if defined( HB_NTX_NOMULTITAG ) + hb_itemPutL( pItem, FALSE ); +#else + BOOL fMultiTag = s_fMultiTag; + if( hb_itemType( pItem ) == HB_IT_LOGICAL ) + s_fMultiTag = hb_itemGetL( pItem ); + hb_itemPutL( pItem, fMultiTag ); +#endif + break; + } + + case RDDI_SORTRECNO: + { + BOOL fSortRecNo = s_fSortRecNo; + if( hb_itemType( pItem ) == HB_IT_LOGICAL ) + s_fSortRecNo = hb_itemGetL( pItem ); + hb_itemPutL( pItem, fSortRecNo ); + break; + } + + case RDDI_STRUCTORD: + { + BOOL fStruct = s_fStruct; + if( hb_itemType( pItem ) == HB_IT_LOGICAL ) + s_fStruct = hb_itemGetL( pItem ); + hb_itemPutL( pItem, fStruct ); + break; + } + + case RDDI_STRICTSTRUCT: + { + BOOL fStrictStruct = s_fStrictStruct; + if( hb_itemType( pItem ) == HB_IT_LOGICAL ) + s_fStrictStruct = hb_itemGetL( pItem ); + hb_itemPutL( pItem, fStrictStruct ); + break; + } + + case RDDI_MULTIKEY: + { + BOOL fMultiKey = s_fMultiKey; + if( hb_itemType( pItem ) == HB_IT_LOGICAL ) + s_fMultiKey = hb_itemGetL( pItem ); + hb_itemPutL( pItem, fMultiKey ); + break; + } + + + default: + return SUPER_RDDINFO( pRDD, uiIndex, ulConnect, pItem ); + } + return SUCCESS; } @@ -4360,7 +7291,7 @@ static RDDFUNCS ntxTable = { ntxBof, ntxEof, ntxFound, ( DBENTRYP_V ) ntxGoBottom, - ( DBENTRYP_UL ) ntxGoTo, + ntxGoTo, ntxGoToId, ( DBENTRYP_V ) ntxGoTop, ( DBENTRYP_BIB ) ntxSeek, @@ -4388,13 +7319,14 @@ static RDDFUNCS ntxTable = { ntxBof, ntxRecCount, ntxRecInfo, ntxRecNo, + ntxRecId, ntxSetFieldsExtent, ntxAlias, ( DBENTRYP_V ) ntxClose, ntxCreate, ntxInfo, ntxNewArea, - ntxOpen, + ( DBENTRYP_VP ) ntxOpen, ntxRelease, ( DBENTRYP_SP ) ntxStructSize, ( DBENTRYP_P ) ntxSysName, @@ -4417,23 +7349,24 @@ static RDDFUNCS ntxTable = { ntxBof, ntxsetRel, ( DBENTRYP_OI ) ntxOrderListAdd, ( DBENTRYP_V ) ntxOrderListClear, - ntxOrderListDelete, + ( DBENTRYP_OI ) ntxOrderListDelete, ( DBENTRYP_OI ) ntxOrderListFocus, ( DBENTRYP_V ) ntxOrderListRebuild, - ( DBENTRYP_VOI ) ntxOrderCondition, + ntxOrderCondition, ( DBENTRYP_VOC ) ntxOrderCreate, - ntxOrderDestroy, + ( DBENTRYP_OI ) ntxOrderDestroy, ( DBENTRYP_OII ) ntxOrderInfo, ntxClearFilter, ntxClearLocate, - ( DBENTRYP_V ) ntxClearScope, - ntxCountScope, + ntxClearScope, + ( DBENTRYP_VPLP ) ntxCountScope, ntxFilterText, - ( DBENTRYP_SI ) ntxScopeInfo, + ntxScopeInfo, ntxSetFilter, ntxSetLocate, - ( DBENTRYP_VOS ) ntxSetScope, + ntxSetScope, ntxSkipScope, + ntxLocate, ntxCompile, ntxError, ntxEvalBlock, @@ -4447,9 +7380,11 @@ static RDDFUNCS ntxTable = { ntxBof, ntxPutValueFile, ntxReadDBHeader, ntxWriteDBHeader, + ntxInit, ntxExit, ntxDrop, ntxExists, + ( DBENTRYP_RSLV ) ntxRddInfo, ntxWhoCares }; @@ -4458,22 +7393,32 @@ HB_FUNC(_DBFNTX ) {;} HB_FUNC( DBFNTX_GETFUNCTABLE ) { RDDFUNCS * pTable; - USHORT * uiCount; + USHORT * uiCount, uiRddId; uiCount = ( USHORT * ) hb_itemGetPtr( hb_param( 1, HB_IT_POINTER ) ); pTable = ( RDDFUNCS * ) hb_itemGetPtr( hb_param( 2, HB_IT_POINTER ) ); + uiRddId = hb_parni( 4 ); + if( pTable ) { - SHORT iRet; + ERRCODE errCode; - if ( uiCount ) + if( uiCount ) * uiCount = RDDFUNCSCOUNT; - iRet = hb_rddInherit( pTable, &ntxTable, &ntxSuper, ( BYTE * ) "DBFDBT" ); - if ( iRet == FAILURE ) - iRet = hb_rddInherit( pTable, &ntxTable, &ntxSuper, ( BYTE * ) "DBFFPT" ); - if ( iRet == FAILURE ) - iRet = hb_rddInherit( pTable, &ntxTable, &ntxSuper, ( BYTE * ) "DBF" ); - hb_retni( iRet ); + errCode = hb_rddInherit( pTable, &ntxTable, &ntxSuper, ( BYTE * ) "DBFFPT" ); + if( errCode != SUCCESS ) + errCode = hb_rddInherit( pTable, &ntxTable, &ntxSuper, ( BYTE * ) "DBFDBT" ); + if( errCode != SUCCESS ) + errCode = hb_rddInherit( pTable, &ntxTable, &ntxSuper, ( BYTE * ) "DBF" ); + if( errCode == SUCCESS ) + { + /* + * we successfully register our RDD so now we can initialize it + * You may think that this place is RDD init statement, Druzus + */ + s_uiRddId = uiRddId; + } + hb_retni( errCode ); } else { diff --git a/harbour/source/rdd/dbtotal.prg b/harbour/source/rdd/dbtotal.prg index 97d1020270..2b7287c066 100644 --- a/harbour/source/rdd/dbtotal.prg +++ b/harbour/source/rdd/dbtotal.prg @@ -280,11 +280,13 @@ RETURN nil STATIC FUNCTION DbRead() LOCAL cAlias := Alias() - LOCAL aRec := Array( Fcount() ) + LOCAL aRec := {} LOCAL nCount - FOR nCount := 1 TO Fcount() - aRec[ nCount ] := Fieldget( nCount ) + FOR nCount := 1 TO FCount() + IF ( FieldType( nCount ) != "M" ) + AAdd( aRec, Fieldget( nCount ) ) + ENDIF NEXT RETURN aRec diff --git a/harbour/source/rdd/delim0.prg b/harbour/source/rdd/delim0.prg index bca59ce8a6..5fe8f5fd42 100644 --- a/harbour/source/rdd/delim0.prg +++ b/harbour/source/rdd/delim0.prg @@ -52,11 +52,11 @@ #include "rddsys.ch" -ANNOUNCE _DELIM +ANNOUNCE DELIM init procedure DELIMInit - REQUEST _DELIMC + REQUEST _DELIM rddRegister( "DELIM", RDT_TRANSFER ) diff --git a/harbour/source/rdd/delim1.c b/harbour/source/rdd/delim1.c index 53733e7a14..420f75304b 100644 --- a/harbour/source/rdd/delim1.c +++ b/harbour/source/rdd/delim1.c @@ -59,20 +59,20 @@ #define __PRG_SOURCE__ __FILE__ -HB_FUNC( _DELIMC ); +HB_FUNC( _DELIM ); HB_FUNC( DELIM_GETFUNCTABLE ); #undef HB_PRG_PCODE_VER #define HB_PRG_PCODE_VER HB_PCODE_VER HB_INIT_SYMBOLS_BEGIN( delim1__InitSymbols ) -{ "_DELIMC", HB_FS_PUBLIC, {HB_FUNCNAME( _DELIMC )}, NULL }, +{ "_DELIM", HB_FS_PUBLIC, {HB_FUNCNAME( _DELIM )}, NULL }, { "DELIM_GETFUNCTABLE", HB_FS_PUBLIC, {HB_FUNCNAME( DELIM_GETFUNCTABLE )}, NULL } HB_INIT_SYMBOLS_END( delim1__InitSymbols ) -#if defined(HB_STATIC_STARTUP) +#if defined(HB_PRAGMA_STARTUP) #pragma startup delim1__InitSymbols -#elif defined(_MSC_VER) +#elif defined(HB_MSC_STARTUP) #if _MSC_VER >= 1010 #pragma data_seg( ".CRT$XIY" ) #pragma comment( linker, "/Merge:.CRT=.data" ) @@ -81,8 +81,6 @@ HB_INIT_SYMBOLS_END( delim1__InitSymbols ) #endif static HB_$INITSYM hb_vm_auto_delim1__InitSymbols = delim1__InitSymbols; #pragma data_seg() -#elif ! defined(__GNUC__) - #pragma startup delim1__InitSymbols #endif static RDDFUNCS delimSuper; @@ -118,6 +116,7 @@ static RDDFUNCS delimTable = { hb_delimBof, hb_delimRecCount, hb_delimRecInfo, hb_delimRecNo, + hb_delimRecId, hb_delimSetFieldExtent, hb_delimAlias, hb_delimClose, @@ -164,6 +163,7 @@ static RDDFUNCS delimTable = { hb_delimBof, hb_delimSetLocate, hb_delimSetScope, hb_delimSkipScope, + hb_delimLocate, hb_delimCompile, hb_delimError, hb_delimEvalBlock, @@ -177,9 +177,11 @@ static RDDFUNCS delimTable = { hb_delimBof, hb_delimPutValueFile, hb_delimReadDBHeader, hb_delimWriteDBHeader, + hb_delimInit, hb_delimExit, hb_delimDrop, hb_delimExists, + hb_delimRddInfo, hb_delimWhoCares }; @@ -189,9 +191,7 @@ static RDDFUNCS delimTable = { hb_delimBof, */ -HB_FUNC( _DELIMC ) -{ -} +HB_FUNC( _DELIM ) { ; } HB_FUNC( DELIM_GETFUNCTABLE ) { diff --git a/harbour/source/rdd/hbsix/Makefile b/harbour/source/rdd/hbsix/Makefile new file mode 100644 index 0000000000..80ecee79e2 --- /dev/null +++ b/harbour/source/rdd/hbsix/Makefile @@ -0,0 +1,18 @@ +# +# $Id$ +# + +ROOT = ../../../ + +C_SOURCES=\ + sxcompr.c \ + sxcrypt.c \ + sxdate.c \ + +LIBNAME=hbsix + +ifeq ($(HB_MT),MT) + MT_LIBNAME=$(LIBNAME)mt +endif + +include $(TOP)$(ROOT)config/lib.cf diff --git a/harbour/source/rdd/hbsix/sxcompr.c b/harbour/source/rdd/hbsix/sxcompr.c new file mode 100644 index 0000000000..10a80ec7ce --- /dev/null +++ b/harbour/source/rdd/hbsix/sxcompr.c @@ -0,0 +1,733 @@ +/* + * $Id$ + */ + +/* + * xHarbour Project source code: + * SIX compatible functions: + * hb_LZSSxCompressMem() + * hb_LZSSxDecompressMem() + * hb_LZSSxCompressFile() + * hb_LZSSxDecompressFile() + * + * SX_FCOMPRESS + * SX_FDECOMPRESS + * _SX_STRDECOMPRESS + * _SX_STRCOMPRESS + * + * Copyright 2005 Przemyslaw Czerpak + * www - http://www.xharbour.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/). + * + * As a special exception, the Harbour Project gives permission for + * additional uses of the text contained in its release of Harbour. + * + * The exception is that, if you link the Harbour libraries with other + * files to produce an executable, this does not by itself cause the + * resulting executable to be covered by the GNU General Public License. + * Your use of that executable is in no way restricted on account of + * linking the Harbour library code into it. + * + * This exception does not however invalidate any other reasons why + * the executable file might be covered by the GNU General Public License. + * + * This exception applies only to the code released by the Harbour + * Project under the name Harbour. If you copy code from other + * Harbour Project or Free Software Foundation releases into a copy of + * Harbour, as the General Public License permits, the exception does + * not apply to the code that you add in this way. To avoid misleading + * anyone as to the status of such modified files, you must delete + * this exception notice from them. + * + * If you write modifications of your own for Harbour, it is your choice + * whether to permit this exception to apply to your modifications. + * If you do not wish that, delete this exception notice. + * + */ + +/* + SIX uses modified version of LZSS algorithm. + It uses 12 bits for position offset in ring buffer and 4 bits for the + match length. LZSS is modified version of LZ77 algorithm which can store + original bytes from input string instead of position and match length in + the ring buffer when the match length does not reach some limit. In SIX + the minimum match length is 3 and it is used to increase to match length + in 4 bit offset by adding 3 also so the efective maximum match length is + 18. Of course we have to store the information about the type of item in + compressed data to know it is (offset+length) pair or simple byte. + SIX put 1 byte in compressed data which inform about the type of next + 8 items: bit set to 1 means normal byte, 0 means item pair. + The funny thing is that SIX seems to effectively use only 11 bits ring + buffer (2048 bytes size). I still do not know why. Maybe it was a hack + for some problems with implementation of encoding or work around for + a bug in some signed/unsigned value conversions? Or maybe someone + wanted to reduce memory overhead in used algorithm for finding the + longest match? The SIX was written for 16-bit DOS and the memory + consumption was important though it should not be too much. They + documented ~9KB increasing the ring buffer size should be linear to + other used (helper) structures. + The next interesting thing is that it dynamically overwrites the ring + buffer with stream data and does not use any separate look ahead buffers. + This fact suggests that SIX uses some simple implementation with + greedy early parsing and does not look for optimal matches. + Our algorithm has to make the same with the ring buffer to be compatible. + UPDATE: Using smaller ring buffer without increasing the match pointer + suggested me that it is possible that someone didn't understand it fully + and modified already existing algorithm. I spend a while with a google + looking for old LZSS implementations and I've found it. IMHO in 99% + this code is used in SIX. This is lzss.c file written by Haruhiko Okumura + with the following note in header: + ,--------------------------------------------------------- + | Use, distribute, and modify this program freely. + | Please send me your improved versions. + `--------------------------------------------------------- + This LZSS implementation gives exactly the same results as SIX when we + change the ring buffer size (#define N 4096 //in the head of this file) + to 2048. So I used exactly the same algorithm with binary tree for + finding the longest match. The code may looks a little bit differ then + in lzss.c because I've already implement most of it before I found + this file and I didn't want to remove it but the original author is + Haruhiko Okumura. The text above allow us use it in [x]Harbour. + This version isn't for sure improved due to SIX modifications so I do + not think I should send it to him. IMHO it is also less usable for + other things then strict SIX compatibility - we already have much + stronger compressions in ZLIB. + After the LZSS compression the result could be longer then original + strings. It looks that SIX return original string when the compressed + one is longer then original + 253. I do not like it because there is + no marker which informs if string was compressed or not and calling + decompression procedure for uncompressed data gives broken results. + I do not want to make the same. + When file is compressed then SIX put the uncompressed file size in + first four bytes. Similar situation is with string returned by + sx_compress() - first four bytes is uncompressed size in little + endian order. This has to be done in upper level functions, + hb_LZSSxCompressMem() and hb_LZSSxCompressFile() intentionally + do not do that. + +*/ + +#include "hbsxfunc.h" + +/* number of bits for encoded item (position,length) */ +#define ITEMBITS 16 +/* unused DUMMY bits - who does know why SIX has it? */ +#define DUMMYBITS 1 +/* number of bits for position offset */ +#define OFFSETBITS (12 - DUMMYBITS) +/* the minimum match length to encode as new position */ +#define MINLENGTH 3 + +/* number of bits for match length, 1 bit reserved for ITEM type */ +#define LENGTHBITS ( ITEMBITS - OFFSETBITS - DUMMYBITS ) +/* the maximum match length we can encode in LENGTHBITS */ +#define MAXLENGTH ( ( 1 << LENGTHBITS ) + MINLENGTH - 1 ) +/* size of ring buffer */ +#define RBUFLENGTH ( 1 << OFFSETBITS ) +/* the bit mask for ring buffer */ +#define RBUFMASK ( ( 1 << OFFSETBITS ) - 1 ) +/* the bit mask for match length */ +#define MATCHMASK ( ( 1 << LENGTHBITS ) - 1 ) +/* get ringbuffer index */ +#define RBUFINDEX(i) ( ( i ) & RBUFMASK ) + +/* get ring buffer offset position from low and high bytes */ +#define LZSS_OFFSET(l, h) ( (l) | ( (h & ~MATCHMASK) << ( 8 - LENGTHBITS ) ) ) +/* get match length from low and high byte */ +#define LZSS_LENGTH(l, h) ( ( (h) & MATCHMASK ) + MINLENGTH ) + +/* create compressed item from match position and length */ +#define LZSS_ITEM(o, l) ( ( (o) << LENGTHBITS ) | ( (l) - MINLENGTH ) ) +/* create low byte of compressed item */ +#define LZSS_ITMLO(o, l) ( ( BYTE ) (o) ) +/* create high byte of compressed item */ +#define LZSS_ITMHI(o, l) ( ( BYTE ) ( ( ( (o) >> ( 8 - LENGTHBITS ) ) & ~MATCHMASK ) | \ + ( (l) - MINLENGTH ) ) ) +/* maximum size of item set: byte with item type bits plus 8 items */ +#define ITEMSETSIZE ( ( ITEMBITS << 3 ) + 1 ) + +/* the size of IO buffer for file (de)compression */ +#define LZSS_IOBUFLEN 8192 + +/* uninitialized (dummy) node in compression trees */ +#define DUMMYNODE RBUFLENGTH + + +typedef struct _HB_LZSSX_COMPR +{ + FHANDLE hInput; + BYTE * inBuffer; + ULONG inBuffSize; + ULONG inBuffPos; + ULONG inBuffRead; + BOOL fInFree; + + FHANDLE hOutput; + BYTE * outBuffer; + ULONG outBuffSize; + ULONG outBuffPos; + BOOL fOutFree; + + ULONG ulMaxSize; + ULONG ulOutSize; + BOOL fResult; + BOOL fContinue; + + BYTE ring_buffer[ RBUFLENGTH + MAXLENGTH - 1 ]; + + SHORT match_offset; + SHORT match_length; + SHORT parent[ RBUFLENGTH + 1 ]; + SHORT left [ RBUFLENGTH + 1 ]; + SHORT right [ RBUFLENGTH + 257 ]; +} +HB_LZSSX_COMPR; +typedef HB_LZSSX_COMPR * PHB_LZSSX_COMPR; + +void hb_LZSSxExit( PHB_LZSSX_COMPR pCompr ) +{ + if( pCompr->fInFree ) + hb_xfree( pCompr->inBuffer ); + if( pCompr->fOutFree ) + hb_xfree( pCompr->outBuffer ); + hb_xfree( pCompr ); +} + +static PHB_LZSSX_COMPR hb_LZSSxInit( + FHANDLE hInput, BYTE * pSrcBuf, ULONG ulSrcBuf, + FHANDLE hOutput, BYTE * pDstBuf, ULONG ulDstBuf ) +{ + PHB_LZSSX_COMPR pCompr = ( PHB_LZSSX_COMPR ) hb_xgrab( sizeof( HB_LZSSX_COMPR ) ); + + if( hInput != FS_ERROR && ulSrcBuf == 0 ) + ulSrcBuf = LZSS_IOBUFLEN; + if( hOutput != FS_ERROR && ulDstBuf == 0 ) + ulDstBuf = LZSS_IOBUFLEN; + + pCompr->hInput = hInput; + pCompr->inBuffer = pSrcBuf; + pCompr->inBuffSize = ulSrcBuf; + pCompr->inBuffPos = 0; + pCompr->inBuffRead = ( hInput == FS_ERROR ) ? ulSrcBuf : 0; + pCompr->fInFree = ( hInput != FS_ERROR && pSrcBuf == NULL ); + pCompr->hOutput = hOutput; + pCompr->outBuffer = pDstBuf; + pCompr->outBuffSize = ulDstBuf; + pCompr->outBuffPos = 0; + pCompr->fOutFree = ( hOutput != FS_ERROR && pDstBuf == NULL ); + + pCompr->ulMaxSize = 0; + pCompr->ulOutSize = 0; + pCompr->fResult = TRUE; + pCompr->fContinue = FALSE; + + if( pCompr->fInFree ) + pCompr->inBuffer = ( BYTE * ) hb_xgrab( ulDstBuf ); + if( pCompr->fOutFree ) + pCompr->outBuffer = ( BYTE * ) hb_xgrab( ulDstBuf ); + + /* initialize the ring buffer with spaces, because SIX uses + dynamic ring buffer then we do not have to fill last MAXLENGTH + characters */ + memset( pCompr->ring_buffer, ' ', RBUFLENGTH - MAXLENGTH ); + + return pCompr; +} + +static BOOL hb_LZSSxFlush( PHB_LZSSX_COMPR pCompr ) +{ + if( pCompr->fResult && pCompr->hOutput != FS_ERROR ) + { + if( hb_fsWriteLarge( pCompr->hOutput, pCompr->outBuffer, + pCompr->outBuffPos ) != pCompr->outBuffPos ) + { + pCompr->fResult = FALSE; + } + else + { + pCompr->ulOutSize += pCompr->outBuffPos; + pCompr->outBuffPos = 0; + } + } + return pCompr->fResult; +} + +static BOOL hb_LZSSxWrite( PHB_LZSSX_COMPR pCompr, BYTE bVal ) +{ + if( pCompr->fResult ) + { + if( pCompr->outBuffPos == pCompr->outBuffSize ) + hb_LZSSxFlush( pCompr ); + if( pCompr->outBuffPos < pCompr->outBuffSize ) + pCompr->outBuffer[pCompr->outBuffPos] = bVal; + else + pCompr->fResult = FALSE; + } + pCompr->outBuffPos++; + return pCompr->fResult || pCompr->fContinue; +} + +static int hb_LZSSxRead( PHB_LZSSX_COMPR pCompr ) +{ + if( pCompr->inBuffPos < pCompr->inBuffRead ) + return pCompr->inBuffer[ pCompr->inBuffPos++ ]; + + if( pCompr->hInput != FS_ERROR ) + { + pCompr->inBuffRead = hb_fsReadLarge( pCompr->hInput, pCompr->inBuffer, + pCompr->inBuffSize ); + pCompr->inBuffPos = 0; + if( pCompr->inBuffPos < pCompr->inBuffRead ) + return pCompr->inBuffer[ pCompr->inBuffPos++ ]; + } + return -1; +} + +static BOOL hb_LZSSxDecode( PHB_LZSSX_COMPR pCompr ) +{ + BOOL fResult = TRUE; + USHORT itemMask; + int offset, length, index, c, h; + + index = RBUFLENGTH - MAXLENGTH; + itemMask = 0; + + do + { + itemMask >>= 1; + /* Is the next character bitfield with type of next 8 items ? */ + if( ( itemMask & 0x0100 ) == 0 ) + { + if( ( c = hb_LZSSxRead( pCompr ) ) == -1 ) + break; + /* simple trick to reduce number of shift operations */ + itemMask = c | 0xff00; + } + if( ( c = hb_LZSSxRead( pCompr ) ) == -1 ) + break; + + if( itemMask & 1 ) /* Is the next character normal byte ? */ + { + if( ! hb_LZSSxWrite( pCompr, ( BYTE ) c ) ) + { + fResult = FALSE; + break; + } + pCompr->ring_buffer[ index ] = ( BYTE ) c; + index = RBUFINDEX( index + 1 ); + } + else /* we have an item pair (ring buffer offset : match length) */ + { + if( ( h = hb_LZSSxRead( pCompr ) ) == -1 ) + { + /* fResult = FALSE; */ + break; + } + offset = LZSS_OFFSET( c, h ); /* get offset to ring buffer */ + length = LZSS_LENGTH( c, h ); /* get match length */ + for( h = 0; h < length; h++ ) + { + c = pCompr->ring_buffer[ RBUFINDEX( offset + h ) ]; + if( ! hb_LZSSxWrite( pCompr, ( BYTE ) c ) ) + { + fResult = FALSE; + break; + } + /* SIX does not use additional buffers and dynamically + overwrite the ring buffer - we have to make exactly + the same or our results will be differ when + abs( offset - index ) < length */ + pCompr->ring_buffer[ index ] = ( BYTE ) c; + index = RBUFINDEX( index + 1 ); + } + } + } + while( fResult ); + + if( fResult ) + fResult = hb_LZSSxFlush( pCompr ); + return fResult; +} + +static void hb_LZSSxNodeInsert( PHB_LZSSX_COMPR pCompr, int r ) +{ + int i, p, cmp; + unsigned char *key; + + cmp = 1; + key = &pCompr->ring_buffer[ r ]; + p = RBUFLENGTH + 1 + key[ 0 ]; + pCompr->right[ r ] = pCompr->left[ r ] = DUMMYNODE; + pCompr->match_length = 0; + + for( ; ; ) + { + if( cmp >= 0 ) + { + if( pCompr->right[ p ] != DUMMYNODE ) + p = pCompr->right[ p ]; + else + { + pCompr->right[ p ] = r; + pCompr->parent[ r ] = p; + return; + } + } + else + { + if( pCompr->left[ p ] != DUMMYNODE ) + p = pCompr->left[ p ]; + else + { + pCompr->left[ p ] = r; + pCompr->parent[ r ] = p; + return; + } + } + for( i = 1; i < MAXLENGTH; i++ ) + { + if( ( cmp = key[ i ] - pCompr->ring_buffer[ p + i ] ) != 0 ) + break; + } + if( i > pCompr->match_length ) + { + pCompr->match_offset = p; + pCompr->match_length = i; + if( i >= MAXLENGTH ) + break; + } + } + pCompr->parent[ r ] = pCompr->parent[ p ]; + pCompr->left[ r ] = pCompr->left[ p ]; + pCompr->right[ r ] = pCompr->right[ p ]; + pCompr->parent[ pCompr->left[ p ] ] = r; + pCompr->parent[ pCompr->right[ p ] ] = r; + if( pCompr->right[ pCompr->parent[ p ] ] == p ) + pCompr->right[ pCompr->parent[ p ] ] = r; + else + pCompr->left[ pCompr->parent[ p ] ] = r; + pCompr->parent[ p ] = DUMMYNODE; +} + +static void hb_LZSSxNodeDelete( PHB_LZSSX_COMPR pCompr, int p ) +{ + if( pCompr->parent[ p ] != DUMMYNODE ) + { + int q; + if( pCompr->right[ p ] == DUMMYNODE ) + q = pCompr->left[ p ]; + else if( pCompr->left[ p ] == DUMMYNODE ) + q = pCompr->right[ p ]; + else + { + q = pCompr->left[ p ]; + if( pCompr->right[ q ] != DUMMYNODE ) + { + do + { + q = pCompr->right[ q ]; + } + while( pCompr->right[ q ] != DUMMYNODE ); + pCompr->right[ pCompr->parent[ q ] ] = pCompr->left[ q ]; + pCompr->parent[ pCompr->left[ q ] ] = pCompr->parent[ q ]; + pCompr->left[ q ] = pCompr->left[ p ]; + pCompr->parent[ pCompr->left[ p ] ] = q; + } + pCompr->right[ q ] = pCompr->right[ p ]; + pCompr->parent[ pCompr->right[ p ] ] = q; + } + pCompr->parent[ q ] = pCompr->parent[ p ]; + if( pCompr->right[ pCompr->parent[ p ] ] == p ) + pCompr->right[ pCompr->parent[ p ] ] = q; + else + pCompr->left[ pCompr->parent[ p ] ] = q; + pCompr->parent[ p ] = DUMMYNODE; + } +} + +static ULONG hb_LZSSxEncode( PHB_LZSSX_COMPR pCompr ) +{ + BYTE itemSet[ITEMSETSIZE]; + BYTE itemMask; + ULONG ulSize = 0; + int iItem; + short int i, c, len, r, s, last_match_length; + + for( i = RBUFLENGTH + 1; i < RBUFLENGTH + 257; i++ ) + pCompr->right[i] = DUMMYNODE; + for( i = 0; i < RBUFLENGTH; i++ ) + pCompr->parent[ i ] = DUMMYNODE; + + itemSet[ 0 ] = 0; + iItem = itemMask = 1; + s = 0; + r = RBUFLENGTH - MAXLENGTH; + + for( len = 0; len < MAXLENGTH; len++ ) + { + if( ( c = hb_LZSSxRead( pCompr ) ) == -1 ) + break; + pCompr->ring_buffer[ r + len ] = c; + } + if( len == 0 ) + return ulSize; + + for( i = 1; i <= MAXLENGTH; i++ ) + hb_LZSSxNodeInsert( pCompr, r - i ); + hb_LZSSxNodeInsert( pCompr, r ); + + do + { + if( pCompr->match_length > len ) + pCompr->match_length = len; + if( pCompr->match_length < MINLENGTH ) + { + pCompr->match_length = 1; + itemSet[ 0 ] |= itemMask; + itemSet[ iItem++ ] = pCompr->ring_buffer[ r ]; + } + else + { + itemSet[iItem++] = LZSS_ITMLO( pCompr->match_offset, + pCompr->match_length ); + itemSet[iItem++] = LZSS_ITMHI( pCompr->match_offset, + pCompr->match_length ); + } + if( ( itemMask <<= 1 ) == 0 ) + { + for( i = 0; i < iItem; i++ ) + { + if( !hb_LZSSxWrite( pCompr, itemSet[ i ] ) ) + return ( ULONG ) -1; + } + ulSize += iItem; + itemSet[ 0 ] = 0; + iItem = itemMask = 1; + } + last_match_length = pCompr->match_length; + for( i = 0; i < last_match_length && + ( c = hb_LZSSxRead( pCompr ) ) != -1; i++ ) + { + hb_LZSSxNodeDelete( pCompr, s ); + pCompr->ring_buffer[ s ] = c; + if( s < MAXLENGTH - 1 ) + pCompr->ring_buffer[ s + RBUFLENGTH ] = c; + s = RBUFINDEX( s + 1 ); + r = RBUFINDEX( r + 1 ); + hb_LZSSxNodeInsert( pCompr, r ); + } + while( i++ < last_match_length ) + { + hb_LZSSxNodeDelete( pCompr, s ); + s = RBUFINDEX( s + 1 ); + r = RBUFINDEX( r + 1 ); + if( --len ) + hb_LZSSxNodeInsert( pCompr, r ); + } + } while( len > 0 ); + + if( iItem > 1 ) + { + for( i = 0; i < iItem; i++ ) + { + if( !hb_LZSSxWrite( pCompr, itemSet[ i ] ) ) + return ( ULONG ) -1; + } + ulSize += iItem; + } + + if( !hb_LZSSxFlush( pCompr ) ) + return ( ULONG ) -1; + + return ulSize; +} + + +BOOL hb_LZSSxCompressMem( BYTE * pSrcBuf, ULONG ulSrcLen, + BYTE * pDstBuf, ULONG ulDstLen, + ULONG * pulSize ) +{ + PHB_LZSSX_COMPR pCompr; + ULONG ulSize; + + pCompr = hb_LZSSxInit( FS_ERROR, pSrcBuf, ulSrcLen, + FS_ERROR, pDstBuf, ulDstLen ); + ulSize = hb_LZSSxEncode( pCompr ); + hb_LZSSxExit( pCompr ); + if( pulSize ) + *pulSize = ulSize; + return ( ulSize <= ulDstLen ); +} + +BOOL hb_LZSSxDecompressMem( BYTE * pSrcBuf, ULONG ulSrcLen, + BYTE * pDstBuf, ULONG ulDstLen ) +{ + PHB_LZSSX_COMPR pCompr; + BOOL fResult; + + pCompr = hb_LZSSxInit( FS_ERROR, pSrcBuf, ulSrcLen, + FS_ERROR, pDstBuf, ulDstLen ); + fResult = hb_LZSSxDecode( pCompr ); + hb_LZSSxExit( pCompr ); + return fResult; +} + +BOOL hb_LZSSxCompressFile( FHANDLE hInput, FHANDLE hOutput, ULONG * pulSize ) +{ + PHB_LZSSX_COMPR pCompr; + ULONG ulSize; + + pCompr = hb_LZSSxInit( hInput, NULL, 0, hOutput, NULL, 0 ); + ulSize = hb_LZSSxEncode( pCompr ); + hb_LZSSxExit( pCompr ); + if( pulSize ) + *pulSize = ulSize; + return ulSize != ( ULONG ) -1; +} + +BOOL hb_LZSSxDecompressFile( FHANDLE hInput, FHANDLE hOutput ) +{ + PHB_LZSSX_COMPR pCompr; + BOOL fResult; + + pCompr = hb_LZSSxInit( hInput, NULL, 0, hOutput, NULL, 0 ); + fResult = hb_LZSSxDecode( pCompr ); + hb_LZSSxExit( pCompr ); + return fResult; +} + +HB_FUNC( SX_FCOMPRESS ) +{ + BOOL fRet = FALSE; + FHANDLE hInput, hOutput; + char * szSource = hb_parc( 1 ), * szDestin = hb_parc( 2 ); + BYTE buf[ 4 ]; + ULONG ulSize; + + if( szSource && *szSource && szDestin && *szDestin ) + { + hInput = hb_fsExtOpen( ( BYTE * ) szSource, NULL, FO_READ | FO_DENYNONE | + FXO_DEFAULTS | FXO_SHARELOCK, NULL, NULL ); + if( hInput != FS_ERROR ) + { + hOutput = hb_fsExtOpen( ( BYTE * ) szDestin, NULL, FO_READWRITE | + FO_EXCLUSIVE | FXO_TRUNCATE | + FXO_DEFAULTS | FXO_SHARELOCK, NULL, NULL ); + if( hOutput != FS_ERROR ) + { + /* store uncompressed file size in first 4 bytes of destination + * file in little endian order - for SIX3 compatibility + */ + ulSize = hb_fsSeek( hInput, 0, FS_END ); + if( hb_fsSeek( hInput, 0, FS_SET ) == 0 ) + { + HB_PUT_LE_UINT32( buf, ulSize ); + if( hb_fsWrite( hOutput, buf, 4 ) == 4 ) + fRet = hb_LZSSxCompressFile( hInput, hOutput, NULL ); + } + hb_fsClose( hOutput ); + } + hb_fsClose( hInput ); + } + } + hb_retl( fRet ); +} + +HB_FUNC( SX_FDECOMPRESS ) +{ + BOOL fRet = FALSE; + FHANDLE hInput, hOutput; + char * szSource = hb_parc( 1 ), * szDestin = hb_parc( 2 ); + + if( szSource && *szSource && szDestin && *szDestin ) + { + hInput = hb_fsExtOpen( ( BYTE * ) szSource, NULL, FO_READ | FO_DENYNONE | + FXO_DEFAULTS | FXO_SHARELOCK, NULL, NULL ); + if( hInput != FS_ERROR ) + { + hOutput = hb_fsExtOpen( ( BYTE * ) szDestin, NULL, FO_READWRITE | + FO_EXCLUSIVE | FXO_TRUNCATE | + FXO_DEFAULTS | FXO_SHARELOCK, NULL, NULL ); + if( hOutput != FS_ERROR ) + { + /* skip the four bytes with original file length */ + if( hb_fsSeek( hInput, 4, FS_SET ) == 4 ) + fRet = hb_LZSSxDecompressFile( hInput, hOutput ); + hb_fsClose( hOutput ); + } + hb_fsClose( hInput ); + } + } + hb_retl( fRet ); +} + +HB_FUNC( _SX_STRCOMPRESS ) +{ + BOOL fOK = FALSE; + BYTE * pStr = ( BYTE * ) hb_parc( 1 ), * pBuf; + + if( pStr ) + { + ULONG ulLen = hb_parclen( 1 ), ulBuf, ulDst; + + /* this is for strict SIX compatibility - in general very bad idea */ + ulBuf = ulLen + 257; + pBuf = ( BYTE * ) hb_xgrab( ulBuf ); + HB_PUT_LE_UINT32( pBuf, ulLen ); + fOK = hb_LZSSxCompressMem( pStr, ulLen, pBuf + 4, ulBuf - 4, &ulDst ); + if( fOK ) + hb_retclen( ( char * ) pBuf, ulDst + 4 ); + hb_xfree( pBuf ); + } + + if( !fOK ) + hb_itemReturn( hb_param( 1, HB_IT_ANY ) ); +} + +HB_FUNC( _SX_STRDECOMPRESS ) +{ + BOOL fOK = FALSE; + BYTE * pStr = ( BYTE * ) hb_parc( 1 ), * pBuf; + + if( pStr ) + { + ULONG ulLen = hb_parclen( 1 ), ulBuf; + + if( ulLen >= 4 ) + { + ulBuf = HB_GET_LE_UINT32( pStr ); + pBuf = ( BYTE * ) hb_xalloc( ulBuf ); + if( pBuf ) + { + fOK = hb_LZSSxDecompressMem( pStr + 4, ulLen - 4, pBuf, ulBuf ); + if( fOK ) + hb_retclen( ( char * ) pBuf, ulBuf ); + hb_xfree( pBuf ); + } + else + { + PHB_ITEM pItem = hb_errRT_SubstParams( "SIXCOMPRESS", EG_MEM, 0, "possible compressed string corruption", "_SX_STRDECOMPRESS" ); + hb_itemReturn( pItem ); + hb_itemRelease( pItem ); + return; + } + } + } + + if( !fOK ) + hb_itemReturn( hb_param( 1, HB_IT_ANY ) ); +} diff --git a/harbour/source/rdd/hbsix/sxcrypt.c b/harbour/source/rdd/hbsix/sxcrypt.c new file mode 100644 index 0000000000..69de957c21 --- /dev/null +++ b/harbour/source/rdd/hbsix/sxcrypt.c @@ -0,0 +1,211 @@ +/* + * $Id$ + */ + +/* + * xHarbour Project source code: + * SIX compatible functions: + * hb_sxEnCrypt() + * hb_sxDeCrypt() + * + * SX_ENCRYPT() + * SX_DECRYPT() + * + * Copyright 2005 Przemyslaw Czerpak + * www - http://www.xharbour.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/). + * + * As a special exception, the Harbour Project gives permission for + * additional uses of the text contained in its release of Harbour. + * + * The exception is that, if you link the Harbour libraries with other + * files to produce an executable, this does not by itself cause the + * resulting executable to be covered by the GNU General Public License. + * Your use of that executable is in no way restricted on account of + * linking the Harbour library code into it. + * + * This exception does not however invalidate any other reasons why + * the executable file might be covered by the GNU General Public License. + * + * This exception applies only to the code released by the Harbour + * Project under the name Harbour. If you copy code from other + * Harbour Project or Free Software Foundation releases into a copy of + * Harbour, as the General Public License permits, the exception does + * not apply to the code that you add in this way. To avoid misleading + * anyone as to the status of such modified files, you must delete + * this exception notice from them. + * + * If you write modifications of your own for Harbour, it is your choice + * whether to permit this exception to apply to your modifications. + * If you do not wish that, delete this exception notice. + * + */ + +#include "hbsxfunc.h" + +#define rnd_mul1 0x0de6d +#define rnd_mul2 0x0278D + +static UINT32 hb_sxInitSeed( BYTE * pKeyVal, UINT16 * puiKey ) +{ + UINT32 ulSeed = 0; + int i; + + for( i = 0; i < 7 ; i++ ) + { + ulSeed = ( ( ( ulSeed >> 16 ) + ( ulSeed << 16 ) ) * 17 ) + + HB_GET_LE_UINT16( &pKeyVal[i] ); + } + ulSeed |= 1; + *puiKey = ( UINT16 ) ulSeed; + return ( ulSeed << 16 ) + ( ulSeed >> 16 ); +} + +static UINT32 hb_sxNextSeed( UINT32 ulSeed, BYTE * pKeyVal, UINT16 * puiKey ) +{ + UINT32 ulTemp1, ulTemp2; + UINT16 uiSeedLo, uiSeedHi; + + uiSeedLo = ( UINT16 ) ulSeed; + ulTemp1 = ( UINT32 ) rnd_mul1 * ( UINT32 ) uiSeedLo; + ulTemp2 = ( UINT32 ) rnd_mul2 * ( UINT32 ) uiSeedLo + ( ulTemp1 >> 16 ); + uiSeedLo = ( UINT16 ) ulTemp1; + ulTemp1 = ( UINT32 ) rnd_mul1 * ( ulSeed >> 16 ); + uiSeedHi = ( UINT16 ) ( ulTemp1 + ulTemp2 ); + ulSeed = ( ( UINT32 ) uiSeedHi << 16 ) + ( UINT32 ) uiSeedLo; + uiSeedHi |= 1; + *puiKey = uiSeedHi + HB_GET_LE_UINT16( pKeyVal ); + return ulSeed; +} + +void hb_sxEnCrypt( BYTE * pSrc, BYTE * pDst, BYTE * pKeyVal, ULONG ulLen ) +{ + UINT32 ulSeed; + UINT16 uiKey; + BYTE uChar, uShft; + ULONG ul; + int i; + + ulSeed = hb_sxInitSeed( pKeyVal, &uiKey ); + for( ul = 0, i = 0 ; ul < ulLen ; ul++ ) + { + uChar = pSrc[ul]; + uShft = uiKey & 0x07; + pDst[ul] = ( uChar >> uShft ) + ( uChar << ( 8 - uShft ) ) + + ( uiKey & 0xFF ); + ulSeed = hb_sxNextSeed( ulSeed, &pKeyVal[i], &uiKey ); + if( ++i == 7 ) + i = 0; + } +} + +void hb_sxDeCrypt( BYTE * pSrc, BYTE * pDst, BYTE * pKeyVal, ULONG ulLen ) +{ + UINT32 ulSeed; + UINT16 uiKey; + BYTE uChar, uShft; + ULONG ul; + int i; + + ulSeed = hb_sxInitSeed( pKeyVal, &uiKey ); + for( ul = 0, i = 0 ; ul < ulLen ; ul++ ) + { + uChar = pSrc[ul] - ( uiKey & 0xFF ); + uShft = uiKey & 0x07; + pDst[ul] = ( uChar << uShft ) + ( uChar >> ( 8 - uShft ) ); + ulSeed = hb_sxNextSeed( ulSeed, &pKeyVal[i], &uiKey ); + if( ++i == 7 ) + i = 0; + } +} + +static BOOL _hb_sxGetKey( PHB_ITEM pKeyItem, BYTE * pKeyVal ) +{ + BOOL fResult = FALSE; + PHB_ITEM pItem = NULL; + ULONG ulKey; + + if( ! ( hb_itemType( pKeyItem ) & HB_IT_STRING ) ) + { + AREAP pArea = ( AREAP ) hb_rddGetCurrentWorkAreaPointer(); + + if( pArea ) + { + pItem = hb_itemNew( NULL ); + if( SELF_INFO( pArea, DBI_PASSWORD, pItem ) == SUCCESS ) + pKeyItem = pItem; + } + } + if( hb_itemType( pKeyItem ) & HB_IT_STRING ) + { + ulKey = hb_itemGetCLen( pKeyItem ); + if( ulKey ) + memcpy( pKeyVal, hb_itemGetCPtr( pKeyItem ), HB_MIN( ulKey, 8 ) ); + if( ulKey < 8 ) + memset( pKeyVal + ulKey, 0, 8 - ulKey ); + fResult = TRUE; + } + if( pItem ) + hb_itemRelease( pItem ); + return fResult; +} + +HB_FUNC( SX_ENCRYPT ) +{ + if( hb_pcount() > 0 ) + { + BYTE keyBuf[ 8 ]; + ULONG ulLen = hb_parclen( 1 ); + + if( ulLen > 0 && _hb_sxGetKey( hb_param( 2, HB_IT_ANY ), keyBuf ) ) + { + BYTE * pDst = ( BYTE * ) hb_xgrab( ulLen + 1 ); + hb_sxEnCrypt( ( BYTE * ) hb_parc( 1 ), pDst, keyBuf, ulLen ); + pDst[ ulLen ] = 0; + hb_retclen_buffer( ( char * ) pDst, ulLen ); + } + else + { + hb_itemReturn( hb_param( 1, HB_IT_ANY ) ); + } + } + else + hb_ret(); +} + +HB_FUNC( SX_DECRYPT ) +{ + if( hb_pcount() > 0 ) + { + BYTE keyBuf[ 8 ]; + ULONG ulLen = hb_parclen( 1 ); + + if( ulLen > 0 && _hb_sxGetKey( hb_param( 2, HB_IT_ANY ), keyBuf ) ) + { + BYTE * pDst = ( BYTE * ) hb_xgrab( ulLen + 1 ); + hb_sxDeCrypt( ( BYTE * ) hb_parc( 1 ), pDst, keyBuf, ulLen ); + pDst[ ulLen ] = 0; + hb_retclen_buffer( ( char * ) pDst, ulLen ); + } + else + { + hb_itemReturn( hb_param( 1, HB_IT_ANY ) ); + } + } + else + hb_ret(); +} diff --git a/harbour/source/rdd/hbsix/sxdate.c b/harbour/source/rdd/hbsix/sxdate.c new file mode 100644 index 0000000000..fad9244bf8 --- /dev/null +++ b/harbour/source/rdd/hbsix/sxdate.c @@ -0,0 +1,103 @@ +/* + * $Id$ + */ + +/* + * xHarbour Project source code: + * SIX compatible functions: + * hb_sxDtoP() + * hb_sxPtoD() + * + * SX_DTOP() + * SX_PTOD() + * + * Copyright 2005 Przemyslaw Czerpak + * www - http://www.xharbour.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/). + * + * As a special exception, the Harbour Project gives permission for + * additional uses of the text contained in its release of Harbour. + * + * The exception is that, if you link the Harbour libraries with other + * files to produce an executable, this does not by itself cause the + * resulting executable to be covered by the GNU General Public License. + * Your use of that executable is in no way restricted on account of + * linking the Harbour library code into it. + * + * This exception does not however invalidate any other reasons why + * the executable file might be covered by the GNU General Public License. + * + * This exception applies only to the code released by the Harbour + * Project under the name Harbour. If you copy code from other + * Harbour Project or Free Software Foundation releases into a copy of + * Harbour, as the General Public License permits, the exception does + * not apply to the code that you add in this way. To avoid misleading + * anyone as to the status of such modified files, you must delete + * this exception notice from them. + * + * If you write modifications of your own for Harbour, it is your choice + * whether to permit this exception to apply to your modifications. + * If you do not wish that, delete this exception notice. + * + */ + +#include "hbsxfunc.h" + +char * hb_sxDtoP( char * pDate, LONG lJulian ) +{ + int iYear, iMonth, iDay; + LONG lPDate; + + HB_TRACE(HB_TR_DEBUG, ("hb_sxDtoP(%p, %ld)", pDate, lJulian)); + + hb_dateDecode( lJulian, &iYear, &iMonth, &iDay ); + lPDate = ( ( ( iYear << 1 ) | ( iMonth >> 3 ) ) << 8 ) | + ( ( iMonth & 7 ) << 5 ) | iDay; + HB_PUT_BE_UINT24( pDate, lPDate ); + + return pDate; +} + +LONG hb_sxPtoD( char * pDate ) +{ + int iYear, iMonth, iDay; + LONG lPDate; + + HB_TRACE(HB_TR_DEBUG, ("hb_sxPtoD(%p)", pDate)); + + if( pDate ) + { + lPDate = HB_GET_BE_UINT24( pDate ); + iDay = lPDate & 0x1f; + iMonth = ( lPDate >> 5 ) & 0x0f; + iYear = ( lPDate >> 9 ); + + return hb_dateEncode( iYear, iMonth, iDay ); + } + return 0; +} + +HB_FUNC( SX_DTOP ) +{ + char pDate[ 3 ]; + hb_retclen( hb_sxDtoP( pDate, hb_pardl( 1 ) ), 3 ); +} + +HB_FUNC( SX_PTOD ) +{ + hb_retdl( hb_sxPtoD( hb_parclen( 1 ) < 3 ? NULL : hb_parc( 1 ) ) ); +} diff --git a/harbour/source/rdd/hsx/Makefile b/harbour/source/rdd/hsx/Makefile new file mode 100644 index 0000000000..dc960d4968 --- /dev/null +++ b/harbour/source/rdd/hsx/Makefile @@ -0,0 +1,13 @@ +# +# $Id$ +# + +ROOT = ../../../ + +C_SOURCES=\ + hsx.c \ + cftsfunc.c \ + +LIBNAME=hsx + +include $(TOP)$(ROOT)config/lib.cf diff --git a/harbour/source/rdd/hsx/cftsfunc.c b/harbour/source/rdd/hsx/cftsfunc.c new file mode 100644 index 0000000000..5b7d965dd6 --- /dev/null +++ b/harbour/source/rdd/hsx/cftsfunc.c @@ -0,0 +1,139 @@ +/* + * $Id$ + */ + +/* + * xHarbour Project source code: + * HiPer-SEEK / CFTS compatible library + * Cfts*() functions + * + * Copyright 2005 Przemyslaw Czerpak + * www - http://www.xharbour.org + * + * Credits: + * Many thanks for Mindaugas Kavaliauskas for his assistance, + * informations about HSX internals, code checking and general + * helping in many things when this library was written. + * Przemek. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/). + * + * As a special exception, the Harbour Project gives permission for + * additional uses of the text contained in its release of Harbour. + * + * The exception is that, if you link the Harbour libraries with other + * files to produce an executable, this does not by itself cause the + * resulting executable to be covered by the GNU General Public License. + * Your use of that executable is in no way restricted on account of + * linking the Harbour library code into it. + * + * This exception does not however invalidate any other reasons why + * the executable file might be covered by the GNU General Public License. + * + * This exception applies only to the code released by the Harbour + * Project under the name Harbour. If you copy code from other + * Harbour Project or Free Software Foundation releases into a copy of + * Harbour, as the General Public License permits, the exception does + * not apply to the code that you add in this way. To avoid misleading + * anyone as to the status of such modified files, you must delete + * this exception notice from them. + * + * If you write modifications of your own for Harbour, it is your choice + * whether to permit this exception to apply to your modifications. + * If you do not wish that, delete this exception notice. + * + */ + +#include "hbapi.h" + +HB_FUNC_EXTERN( HS_ADD ); +HB_FUNC_EXTERN( HS_CLOSE ); +HB_FUNC_EXTERN( HS_CREATE ); +HB_FUNC_EXTERN( HS_DELETE ); +HB_FUNC_EXTERN( HS_IFDEL ); +HB_FUNC_EXTERN( HS_NEXT ); +HB_FUNC_EXTERN( HS_OPEN ); +HB_FUNC_EXTERN( HS_KEYCOUNT ); +HB_FUNC_EXTERN( HS_REPLACE ); +HB_FUNC_EXTERN( HS_SET ); +HB_FUNC_EXTERN( HS_UNDELETE ); +HB_FUNC_EXTERN( HS_VERIFY ); +HB_FUNC_EXTERN( HS_VERSION ); + +HB_FUNC( CFTSADD ) +{ + HB_FUNCNAME( HS_ADD )(); +} + +HB_FUNC( CFTSCLOSE ) +{ + HB_FUNCNAME( HS_CLOSE )(); +} + +HB_FUNC( CFTSCREA ) +{ + HB_FUNCNAME( HS_CREATE )(); +} + +HB_FUNC( CFTSDELETE ) +{ + HB_FUNCNAME( HS_DELETE )(); +} + +HB_FUNC( CFTSIFDEL ) +{ + HB_FUNCNAME( HS_IFDEL )(); +} + +HB_FUNC( CFTSNEXT ) +{ + HB_FUNCNAME( HS_NEXT )(); +} + +HB_FUNC( CFTSOPEN ) +{ + HB_FUNCNAME( HS_OPEN )(); +} + +HB_FUNC( CFTSRECN ) +{ + HB_FUNCNAME( HS_KEYCOUNT )(); +} + +HB_FUNC( CFTSREPLAC ) +{ + HB_FUNCNAME( HS_REPLACE )(); +} + +HB_FUNC( CFTSSET ) +{ + HB_FUNCNAME( HS_SET )(); +} + +HB_FUNC( CFTSUNDEL ) +{ + HB_FUNCNAME( HS_UNDELETE )(); +} + +HB_FUNC( CFTSVERI ) +{ + HB_FUNCNAME( HS_VERIFY )(); +} + +HB_FUNC( CFTSVERS ) +{ + HB_FUNCNAME( HS_VERSION )(); +} diff --git a/harbour/source/rdd/hsx/hsx.c b/harbour/source/rdd/hsx/hsx.c new file mode 100644 index 0000000000..7053971fea --- /dev/null +++ b/harbour/source/rdd/hsx/hsx.c @@ -0,0 +1,1966 @@ +/* + * $Id$ + */ + +/* + * xHarbour Project source code: + * HiPer-SEEK / CFTS compatible library + * + * Copyright 2005 Przemyslaw Czerpak + * www - http://www.xharbour.org + * + * Credits: + * Many thanks for Mindaugas Kavaliauskas for his assistance, + * informations about HSX internals, code checking and general + * helping in many things when this library was written. + * Przemek. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/). + * + * As a special exception, the Harbour Project gives permission for + * additional uses of the text contained in its release of Harbour. + * + * The exception is that, if you link the Harbour libraries with other + * files to produce an executable, this does not by itself cause the + * resulting executable to be covered by the GNU General Public License. + * Your use of that executable is in no way restricted on account of + * linking the Harbour library code into it. + * + * This exception does not however invalidate any other reasons why + * the executable file might be covered by the GNU General Public License. + * + * This exception applies only to the code released by the Harbour + * Project under the name Harbour. If you copy code from other + * Harbour Project or Free Software Foundation releases into a copy of + * Harbour, as the General Public License permits, the exception does + * not apply to the code that you add in this way. To avoid misleading + * anyone as to the status of such modified files, you must delete + * this exception notice from them. + * + * If you write modifications of your own for Harbour, it is your choice + * whether to permit this exception to apply to your modifications. + * If you do not wish that, delete this exception notice. + * + */ + + +/* + LOCKING/IO operations done by HiPpe-SEEK/CFTS library: + A. in exclusive mode: + Unimportant. Thogugh tests shows that CFTS uses buffers + only in ADD and NEXT operations. Other causes immediate + IO call + B. in shared mode + OPEN: + 1. Test for lock existing - (open file, check length, + lock one byte at offset equal to file size multiple + by three, unlock it and close the file) + 2. Open file + 3. Check file length + 4. lock header area (@0:512) + 5. read header + 6. unlock header area (@0:512) + KEYCOUNT: + 1. Lock header area (@0:512) + 2. read 4 bytes with record count from header (@0:4) + 3. unlock header area (@0:512) + ADD: + 1. lock header area (@0:512) + 2. check file length + 3. lock the new record area (@file_length:record_size) + 4. read 4 bytes with record count from header (@0:4) + 5. write 4 bytes with record count from header (@0:4) + 6. write new records (@file_length:record_size) + 7. flush system buffers (COMMIT) + !!! write 4096 bytes at offset 0 (I guess it's system call, + result of calling FLUSH function because file size is not + increased, so it's simple disk cluster/inode update) + 8. unlock header area (@0:512) + 9. unlock record area + IFDEL: + 1. lock header area (@0:512) + 2. read 4 bytes with record count from header (@0:4) + 3. unlock header area (@0:512) + 4. read first byte of record (to check DELETED bit) + DELETE(/UNDELETE): + 1. lock header area (@0:512) + 2. read 4 bytes with record count from header (@0:4) + 3. unlock header area (@0:512) + 4. read first byte of record (to check DELETED bit) + if record not deleted (/is deleted) stop here + 5. lock the record area (@record_offset:record_size) + 6. write first byte to record (the values read in 4 + with updated DELETE flag + 7. flush system buffers (COMMIT) - the same effect as in ADD + 8. unlock the record area (@record_offset:record_size) + REPLACE: + 1. lock header area (@0:512) + 2. read 4 bytes with record count from header (@0:4) + 3. unlock header area (@0:512) + 4. write the new record value (DELETE flag is not set) + 5. flush system buffers (COMMIT) - the same effect as in ADD + 6. unlock the record area (@record_offset:record_size) + SET: nothing + NEXT: + 1. if there is no record in the buffer read records to + fill buffer size (1024 bytes by default) + + + It's very complicated and I do not see big sense in all + this operations - because the following scheme is enough + for secure ADD operation. + 1. LOCK THE HEADER AREA (@x0000:0x0200) + 2. SEEK FROM EOF TO CHECK FILE SIZE AND COUNT THE RECORDS + 3. WRITE NEW RECORD (@RECOFFST:RECSIZE) + 4. WRITE NEW RECORD COUNTER TO HEADER (@0x0000:0x0004) + 5. UNLOCK THE HEADER AREA (@x0000:0x0200) + Even the point 4 can be eliminated because the new record + number is counted from file size. + REPLACE does not need any locks because the whole record is + overwritten with new value in single IO operation + IFDEL also does not need any locks. + DELETE and UNDELETE are not safe operation in HiPer-SEEK/CFTS. + There is a race condition which may cause that the first byte + of new record value set by other station will be overwritten + by the old one with changed DELETED flag. TO make it really + safe the whole operation should be covered by lock and the same + lock should be used also by replace. The question is if this + is really important. So we have to decide here if we should + use exclusive lock on record area kept for whole: DELETE/UNDELETE/ + REPLACE operations or to not use any locks at all. + The last important notice is that if we set that automatic HSX + index update by RDD which uses exclusive record locking for update + (f.e. DBF and related) then we do not have to set _any_ locks at + all and we can use _only_ the REPLACE operation hacked to not + check file size so the index will be automatically growing up by + writing in the new offset related to appended records. + Conclusion: it's enough to add single call to hb_hsxReplace() + in GOCOLD() RDD method. + + Collecting the above information I do not see big sense to implement + exact HiPer-SEEK/CFTS locking. They does not give anything (I could + accept them only if they pass mandatory locking scheme) - the race + conditions still exists and they causes very big general slowness. + So I'm dropping it. If someone wants to implement it then please go + on - IMHO it's a waste of time. + For sure we need lock in ADD operation when HSX is not updated + automatically by RDD and it is discussable if we should cover by common + record lock updating the record area (ADD/REPLACE/DELETE/UNDELETE) + due to possible race condition in DELETE/UNDELETE operations. It will + have to cause noticeable speed reducing but makes these operations + always safe though it's very seldom that it can happen in real + application so maybe we should left it for user. Also there is a side + effect of settings exclusive locks on non POSIX systems (DOS/Windows) + They blocks other stations against reading from the locked region. It + means that the original HS/CFTS locking schemes is buggy because it can + cause unexpected errors in NEXT operation. To avoid this problem many + systems use "phantom locking" (f.e. DBF/CDX/NTX locks). If we want to + use locks we should care about it. Now I made it safe by setting + exclusive lock on the header area for each (whole to eliminate race + condition) update operation and shared lock for header reading. + The results gives working and really network (concurrent access) safe + HSX access in all operations though when the file is shared with program + which uses original HiPer-SEEK/CFTS library some HSX_BADREAD errors can + be returned by HS_NEXT and HS_IFDEL functions and should be served by + user. The same effect appears if the file is shared only by original + HiPer-SEEK/CFTS programs and it's a side effect of badly designed + locking scheme. When only xHarbour application access the file this + problem does not exist. +*/ + +/* DIFFs: + 1. HS_INDEX copy deleted flag from DBF to HSX index and ignores + any filters (standard and MachSIX ones) + 2. HS_INDEX accepts as key parameter also code block. + Given key expression is remembered and later can be used by + HS_ADD, HS_REPLACE, HS_FILTER and HS_VERIFY when this functions + are called without key expression. When the key expression is + set as string then it is also stored in HSX header and later + is automatically retrieve by HS_OPEN. + 3. HS_CREATE has optional 6-th parameter with key expression. It works + in the same way as key parameter in HS_INDEX. + 4. other functions which accept the index key can receive it as + direct the key value (string item) or codeblock + 5. I introduced two new error codes: HSX_NOTABLE, HSX_RDDFAILURE + which are related to workarea errors + 6. The literal version passed to HS_SET is remembered and can be + later used by HS_VERIFY if not given explicitly. + 7. HS_VERIFY respects the lCase flag (fixed SIX bug) and also CftsVeri() + syntax (first parameter in numeric indicating the HSX handler) + See also the note about HS_SET. + 8. HS_FILTER respects the filter flags in verification process, it + also can accept handle to already open HSX index as first parameter + instead of file name. This function needs RDD with record map (RM) + functionality + 8. HS_ADD and HS_REPLACE have optional additional logical parameter + which allow to set DELETE flag in new/modified record + 9. Mindaugas noticed me that tests shows CFTS effectively + uses only the part of string to first chr(0) byte. + In first version this behavior was emulated but later I read + in CFTS documentation that behavior for strings with + embedded 0 is undefined (so it was not intentionally designed) + and I decided to make it independent of embedded '0' and removed + this limitation. + 10.SET DEFAULT and SET PATH is respected by xHarbour when in SIX doesn't. + 11.xHarbour accepts nFilterType == 3 what means that national characters + in VM codepage are respected and lCase switch works properly +*/ + +#include "hbapi.h" +#include "hbapifs.h" +#include "hbapirdd.h" +#include "hbapierr.h" +#include "hbvm.h" +#include "hbset.h" +#ifndef HB_CDP_SUPPORT_OFF +#include "hbapicdp.h" +#endif + +/* error codes */ +#define HSX_SUCCESSFALSE 0 /* operation finished successfully with false value */ +#define HSX_SUCCESS 1 /* operation finished successfully with true value */ +#define HSX_CREATEFAIL -1 /* unable to create the file specified */ +#define HSX_MEMERR -2 /* unable to allocate the memory */ +#define HSX_BADHDRWRITE -3 /* write error while writing the index file header */ +#define HSX_BADSEEK -4 /* Error while attempting seek during buffer flushing */ +#define HSX_BADREAD -5 /* read error while reading */ +#define HSX_BADWRITE -6 /* Error while attempting write during buffer flush */ +#define HSX_RECBOUND -7 /* record number is not valid */ +#define HSX_ISDELETED -8 /* record number is already marked as deleted */ +#define HSX_NOTDELETED -9 /* record number is not marked as deleted */ +#define HSX_OPENERR -10 /* unable to open the file */ +#define HSX_INTERR -11 /* Internal Error */ +#define HSX_NORECS -13 /* index file empty */ +#define HSX_BADPARMS -16 /* Invalid parameters were passed to the function */ +#define HSX_NOMOREHANDLES -17 /* Ran out of HiPer-SEEK handles */ +#define HSX_BADHANDLE -18 /* Invalid handle was passed to the function */ +#define HSX_BADIHANDLE -19 /* Invalid internal handle */ +#define HSX_LOCKFAILED -20 /* Unable to lock file */ +#define HSX_NOMORELOCKS -21 /* Lock table exhausted */ +#define HSX_CANNOTUNLOCK -22 /* Unable to unlock file */ +#define HSX_BADCOMMIT -23 /* Unable to flush disk buffers */ +#define HSX_NOTABLE -24 /* no open table */ +#define HSX_RDDFAILURE -25 /* RDD error */ + +#define HSX_FILEEXT ".hsx" + +#define HSXMAXKEY_SIZE 3 /* maximum key size */ +#define HSXDEFKEY_SIZE 2 /* default key size */ +#define HSXDEFOPENMODE 2 /* default open mode 2=SHARED+READONLY */ + +#define HSXDEFFILTER 1 /* default character filter */ + +#define HSXHEADER_LEN 512L +#define HSXKEYEXP_LEN ( 512 - sizeof( HSXHEADER ) ) +#define HSXMINBUF_LEN 512L /* minimum buffer size */ +#define HSXMAXBUF_LEN 64536L /* maximum buffer size */ +#define HSXDEFBUF_LEN 16384L /* default buffer size */ +#define HSX_HALLOC 64 /* the handles' array resize factor - unlike + in SIX number of handles isn't limited */ + +#define HSX_VERIFY_BEGIN 1 +#define HSX_VERIFY_END 2 +#define HSX_VERIFY_AND 3 +#define HSX_VERIFY_PHRASE 4 + +#define HSX_HDRLOCKPOS 0 +#define HSX_HDRLOCKSIZE HSXHEADER_LEN + +#define HSX_READLOCK 1 +#define HSX_WRITELOCK 2 +#define HSX_UPDATELOCK 3 +#define HSX_APPENDLOCK 4 +#define HSX_HDRREADLOCK 5 +#define HSX_HDRWRITELOCK 6 +#define HSX_READUNLOCK 7 +#define HSX_WRITEUNLOCK 8 +#define HSX_UPDATEUNLOCK 9 +#define HSX_APPENDUNLOCK 10 +#define HSX_HDRREADUNLOCK 11 +#define HSX_HDRWRITEUNLOCK 12 + +typedef struct _HSXHEADER +{ + BYTE recCount[4]; /* number of records in HSX index file */ + BYTE recSize[4]; /* in bytes 16, 32, 64 */ + BYTE recSizeBits[4]; /* 4, 5 or 6 */ + BYTE ignoreCase[2]; /* 1=> index is not case sensitive */ + BYTE filterType[2]; /* 1=> all characters, 2=> chars in range 33..126 */ + BYTE hashLetters[4]; /* 1=> use hash function for letters */ + BYTE keyExpression[1]; /* xHarbour extension: key expression for automatic update */ +} HSXHEADER; +typedef HSXHEADER * LPHSXHEADER; + +typedef struct _HSXINFO +{ + int iHandle; /* HSX handle */ + ULONG ulRecCount; /* number of records */ + USHORT uiRecordSize; /* record size in bytes */ + BOOL fIgnoreCase; /* ignore case */ + int iFilterType; /* character filter */ + BOOL fUseHash; /* use Hash functions for alphas */ + + FHANDLE hFile; /* file handle */ + char * szFileName; /* file name */ + BOOL fShared; /* Shared file */ + BOOL fReadonly; /* Read only file */ + ULONG ulBufSize; /* size of buffer in records */ + ULONG ulBufRec; /* number of record in buffer */ + ULONG ulFirstRec; /* first record in the buffer */ + BYTE * pBuffer; /* the buffer pointer */ + BOOL fChanged; /* the buffer is changed and should be written to index file */ + BOOL fHdrChanged; /* new records, header file has to be updated */ + BOOL fWrLocked; /* the index is locked for writing */ + + BYTE * pSearchVal; /* current search value for HS_NEXT */ + ULONG ulSearch; /* the length of search value */ + BYTE * pSearchKey; /* current search key val for HS_NEXT */ + ULONG ulCurrRec; /* current record for HS_NEXT */ + + /* xHarbour extension */ + int iArea; /* work area number if bound with WA or 0 */ + char * szKeyExpr; /* key expression when bound with WA for automatic update */ + PHB_ITEM pKeyItem; /* item with compiled key expression */ + BOOL fFlush; /* data was written to file and not commited */ +} HSXINFO; +typedef HSXINFO * LPHSXINFO; + + +/* number of active HSX indexes */ +static int s_iHandleCount = 0; +/* size of handle array */ +static int s_iHandleSize = 0; +/* array indexed by handle number with HSXINFO pointers */ +static LPHSXINFO * s_handleArray = NULL; + +/* the conversion table for ASCII alpha pairs */ +static const BYTE hb_hsxHashArray[] = { +/* A B C D E F G H I J K L M N O P Q R S T U W V X Y Z */ +/* A */ 7,102,222,185, 19, 48,167, 4,173, 4, 79,251,194,250, 7,187, 7,251,209,249, 41,101, 39, 29, 71, 40, +/* B */ 156, 3, 7, 7,149, 7, 7, 7,172, 7, 7,100, 7, 7,148, 7, 7,107, 38, 7,126, 7, 7, 7, 7, 7, +/* C */ 234, 7, 38, 7,229, 7, 7,208,145, 7,116,106, 7, 7,253, 7, 7,166, 40,237,129, 7, 7, 7, 63, 4, +/* D */ 125, 4, 4, 29,253, 7, 28, 7,226, 7, 7, 3, 3, 4,128, 7, 7,124, 44, 4,115, 7, 4, 7, 37, 7, +/* E */ 193, 37,236,198,114, 94,105, 3, 44, 7, 4,245,159,251, 93,151, 36,248,253,252, 36, 70, 28,147, 19, 4, +/* F */ 92, 7, 7, 7,123, 78, 7, 7,180, 7, 7,150, 7, 7,122, 7, 7,104, 4, 35, 55, 7, 7, 7, 7, 7, +/* G */ 121, 7, 7, 7,195, 7, 2, 86, 77, 7, 7, 85, 2, 76, 55, 7, 7,179, 27, 4, 54, 7, 7, 7, 63, 7, +/* H */ 197, 7, 7, 7,228, 7, 7, 7,164, 7, 7, 18, 4, 1,220, 7, 7, 99, 7, 62, 35, 7, 7, 7,169, 7, +/* I */ 192, 98,250,207,155,143,158, 1, 7, 7, 1,212,163,248,250, 97, 7,178,225,252,142,120, 7, 4, 7, 84, +/* J */ 4, 7, 7, 7, 34, 7, 7, 6, 6, 6, 6, 6, 6, 6, 15, 6, 6, 6, 6, 6, 34, 6, 6, 6, 6, 6, +/* K */ 15, 6, 6, 6,135, 6, 6, 6, 69, 6, 6, 4, 6, 14, 14, 6, 6, 6, 14, 6, 6, 6, 6, 6, 27, 6, +/* L */ 253, 4, 13, 62,251, 18, 4, 6,255, 6, 26,213, 17, 6,238, 13, 6, 6, 83,162,154, 12, 6, 6,134, 6, +/* M */ 216, 54, 6, 6,254, 6, 6, 6,231, 6, 6, 6, 68, 12,223,140, 6, 6, 4, 6,146, 6, 6, 6, 4, 6, +/* N */ 230, 6,204,202,252, 53,246, 6,227, 4, 53, 4, 4, 43,205, 4, 6, 11,201,251, 75, 52, 11, 6, 33, 4, +/* O */ 74, 96,161,171, 33, 73,168, 17,133, 4, 10,243,244,248, 82,219, 6,250,210,215,191, 52,119, 51, 32, 4, +/* P */ 186, 6, 6, 6,232, 6, 6,224,160, 6, 6,190, 6, 6,217, 26, 6,189, 32, 90, 67, 6, 6, 6, 51, 6, +/* Q */ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,111, 6, 6, 6, 6, 6, 6, +/* R */ 249, 89,117,113,250, 47,110, 47,252, 6, 46, 25,199,112,249,109, 6,139,183,144,138, 50, 10, 6,153, 6, +/* S */ 81, 6,175, 5,218, 9, 5,170,247, 5, 43, 66, 50, 16,206,177, 4, 5,176,252,182, 5, 9, 5, 61, 5, +/* T */ 242, 5, 16, 4,249, 5, 5,221,248, 5, 5, 25, 8, 5,241, 5, 5,250, 49,132,152, 5, 4, 5,181, 4, +/* U */ 80, 95, 88, 61, 60, 8, 46, 5, 60, 5, 5,214,196,184, 45,131, 5,203,188,174, 5, 5, 5, 4, 5, 5, +/* V */ 137, 5, 5, 5,200, 5, 5, 5,130, 5, 5, 5, 5, 5, 49, 5, 5, 5, 5, 5, 4, 5, 5, 5, 5, 5, +/* W */ 136, 5, 5, 5, 65, 5, 5, 31, 59, 5, 4, 4, 5, 23, 58, 5, 5, 4, 4, 5, 5, 5, 5, 5, 5, 5, +/* X */ 4, 5, 23, 5, 31, 5, 5, 5, 24, 5, 5, 5, 5, 5, 22, 22, 5, 5, 5, 45, 5, 5, 5, 5, 30, 5, +/* Y */ 30, 21, 42, 72, 21, 5, 4, 5, 4, 4, 4,127, 20,103, 20, 87, 4, 64,108, 4, 4, 4, 4, 4, 4, 4, +/* Z */ 42, 4, 4, 4, 56, 4, 4, 4, 24, 4, 4, 4, 4, 4, 41, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 4 }; + +static int hb_hsxHashVal( int c1, int c2, int iKeyBits, + BOOL fNoCase, int iFilter, BOOL fUseHash ) +{ + int iBitNum; + + if ( fNoCase ) + { +#ifndef HB_CDP_SUPPORT_OFF + if ( iFilter == 3 && hb_cdp_page->nChars ) + { + c1 = ( BYTE ) hb_cdp_page->s_upper[ c1 ]; + c2 = ( BYTE ) hb_cdp_page->s_upper[ c2 ]; + } + else +#endif + { + if ( c1 >= 'a' && c1 <= 'z' ) + c1 -= 'a' - 'A'; + if ( c2 >= 'a' && c2 <= 'z' ) + c2 -= 'a' - 'A'; + } + } + if ( iFilter == 1 ) + { + c1 &= 0x7F; + if ( c1 < 0x20 || c1 == 0x7f ) c1 = ' '; + c2 &= 0x7F; + if ( c2 < 0x20 || c2 == 0x7f ) c2 = ' '; + } + + if ( c1 == ' ' || c2 == ' ' || c1 == 0 || c2 == 0 ) + iBitNum = 0; + else if ( fUseHash && c1 >= 'A' && c1 <= 'Z' && c2 >= 'A' && c2 <= 'Z' ) + { + iBitNum = hb_hsxHashArray[ ( c1 - 'A' ) * 26 + ( c2 - 'A' ) ] + 1; + } + else + { + iBitNum = ( c1 + c2 * 78 ) % ( iKeyBits - 1 ) + 1; + if ( iBitNum == 1 ) + iBitNum++; + } + return iBitNum; +} + +static void hb_hsxHashStr( BYTE * pStr, ULONG ulLen, BYTE * pKey, int iKeySize, + BOOL fNoCase, int iFilter, BOOL fUseHash ) +{ + int c1, c2, iBitNum, iKeyBits = iKeySize << 3; + + memset( pKey, '\0', iKeySize ); +#if 0 +/* This code keeps the strict CFTS behavior which stops string + manipulating at first chr(0) character */ + if ( pStr && ulLen-- && ( c1 = *pStr++ ) != 0 ) + { + while ( ulLen-- && ( c2 = *pStr++ ) != 0 ) + { +#else + /* This version can work well with embedded 0 characters */ + if ( pStr && ulLen-- ) + { + c1 = *pStr++; + while ( ulLen-- ) + { + c2 = *pStr++; +#endif + iBitNum = hb_hsxHashVal( c1, c2, iKeyBits, fNoCase, iFilter, fUseHash ); + if ( iBitNum-- ) + { + pKey[ iBitNum >> 3 ] |= 0x80 >> ( iBitNum & 7 ); + } + c1 = c2; + } + } +} + +static int hb_hsxStrCmp( BYTE * pSub, ULONG ulSub, BYTE * pStr, ULONG ulLen, + BOOL fNoCase, int iFilter ) +{ + BOOL fResult = FALSE; + BYTE c1, c2; + ULONG ul; + + if ( ulSub == 0 ) + return HSX_SUCCESSFALSE; + + while ( !fResult && ulLen >= ulSub ) + { + fResult = TRUE; + for ( ul = 0; fResult && ul < ulSub; ul++ ) + { + c1 = pSub[ ul ]; + c2 = pStr[ ul ]; + if ( fNoCase ) + { +#ifndef HB_CDP_SUPPORT_OFF + if ( iFilter == 3 && hb_cdp_page->nChars ) + { + c1 = ( BYTE ) hb_cdp_page->s_upper[ c1 ]; + c2 = ( BYTE ) hb_cdp_page->s_upper[ c2 ]; + } + else +#endif + { + if ( c1 >= 'a' && c1 <= 'z' ) + c1 -= 'a' - 'A'; + if ( c2 >= 'a' && c2 <= 'z' ) + c2 -= 'a' - 'A'; + } + } +#if 0 +/* This code is for strict CftsVeri() behavior - uncomment if necessary + but it's IMHO bug */ + if ( iFilter == 1 ) + { + c1 &= 0x7F; + if ( c1 < 0x20 || c1 == 0x7f ) c1 = ' '; + c2 &= 0x7F; + if ( c2 < 0x20 || c2 == 0x7f ) c2 = ' '; + } +#elif defined( HB_CDP_SUPPORT_OFF ) + HB_SYMBOL_UNUSED( iFilter ); +#endif + fResult = ( c1 == c2 ); + } + --ulLen; + ++pStr; + } + + return fResult ? HSX_SUCCESS : HSX_SUCCESSFALSE; +} + +static LPHSXINFO hb_hsxGetPointer( int iHandle ) +{ + return ( iHandle >=0 && iHandle < s_iHandleSize ) ? + s_handleArray[ iHandle ] : NULL; +} + +static int hb_hsxCompile( char * szExpr, PHB_ITEM * pExpr ) +{ + AREAP pArea = ( AREAP ) hb_rddGetCurrentWorkAreaPointer(); + + *pExpr = NULL; + if ( pArea ) + { + if ( SELF_COMPILE( pArea, ( BYTE * ) szExpr ) == FAILURE ) + return HSX_BADPARMS; + *pExpr = pArea->valResult; + pArea->valResult = NULL; + } + else + { + HB_MACRO_PTR pMacro = hb_macroCompile( szExpr ); + if( !pMacro ) + return HSX_BADPARMS; + *pExpr = hb_itemPutPtr( NULL, ( void * ) pMacro ); + } + return HSX_SUCCESS; +} + +static int hb_hsxEval( int iHandle, PHB_ITEM pExpr, BYTE *pKey, BOOL *fDeleted ) +{ + LPHSXINFO pHSX = hb_hsxGetPointer( iHandle ); + int iResult = HSX_SUCCESS; + BYTE * pStr; + ULONG ulLen; + + if ( ! pHSX ) + return HSX_BADHANDLE; + + if ( !pExpr ) + pExpr = pHSX->pKeyItem; + + if ( !pExpr ) + return HSX_BADPARMS; + + if ( hb_itemType( pExpr ) & HB_IT_STRING ) + { + pStr = ( BYTE * ) hb_itemGetCPtr( pExpr ); + ulLen = hb_itemGetCLen( pExpr ); + if ( fDeleted ) + *fDeleted = FALSE; + } + else + { + int iArea = 0; + PHB_ITEM pItem; + + if ( pHSX->iArea != 0 ) + { + iArea = hb_rddGetCurrentWorkAreaNumber(); + if ( iArea != pHSX->iArea ) + hb_rddSelectWorkAreaNumber( pHSX->iArea ); + else + iArea = 0; + } + pItem = hb_vmEvalBlockOrMacro( pExpr ); + pStr = ( BYTE * ) hb_itemGetCPtr( pItem ); + ulLen = hb_itemGetCLen( pItem ); + if ( fDeleted ) + { + AREAP pArea = ( AREAP ) hb_rddGetCurrentWorkAreaPointer(); + if ( !pArea ) + *fDeleted = FALSE; + else if ( SELF_DELETED( pArea, fDeleted ) == FAILURE ) + iResult = HSX_RDDFAILURE; + } + if ( iArea ) + hb_rddSelectWorkAreaNumber( iArea ); + if ( hb_vmRequestQuery() ) + iResult = HSX_BADPARMS; + } + + if ( iResult == HSX_SUCCESS ) + hb_hsxHashStr( pStr, ulLen, pKey, pHSX->uiRecordSize, pHSX->fIgnoreCase, + pHSX->iFilterType, pHSX->fUseHash ); + + return iResult; +} + +static void hb_hsxGetRecCount( LPHSXINFO pHSX ) +{ + pHSX->ulRecCount = ( hb_fsSeekLarge( pHSX->hFile, 0, FS_END ) - + HSXHEADER_LEN ) / pHSX->uiRecordSize; +} + +static int hb_hsxHdrFlush( int iHandle ) +{ + LPHSXINFO pHSX = hb_hsxGetPointer( iHandle ); + + if ( ! pHSX ) + return HSX_BADHANDLE; + + if ( pHSX->fHdrChanged ) + { + BYTE headrBuf[ HSXHEADER_LEN ]; + LPHSXHEADER pHeader = ( LPHSXHEADER ) headrBuf; + USHORT uiBits = 0, uiSize = pHSX->uiRecordSize; + + while ( uiSize >>= 1 ) + uiBits++; + + HB_PUT_LE_UINT32( pHeader->recCount, pHSX->ulRecCount ); + HB_PUT_LE_UINT32( pHeader->recSize, pHSX->uiRecordSize ); + HB_PUT_LE_UINT32( pHeader->recSizeBits, uiBits ); + HB_PUT_LE_UINT16( pHeader->ignoreCase, pHSX->fIgnoreCase ? 1 : 0 ); + HB_PUT_LE_UINT16( pHeader->filterType, pHSX->iFilterType ); + HB_PUT_LE_UINT32( pHeader->hashLetters, pHSX->fUseHash ? 1 : 0 ); + + memset( pHeader->keyExpression, 0, HSXKEYEXP_LEN + 1 ); + if ( pHSX->szKeyExpr ) + hb_strncpy( ( char * ) pHeader->keyExpression, pHSX->szKeyExpr, HSXKEYEXP_LEN ); + + if ( hb_fsSeek( pHSX->hFile, 0, FS_SET ) != 0 ) + return HSX_BADHDRWRITE; + if ( hb_fsWrite( pHSX->hFile, headrBuf, HSXHEADER_LEN ) != HSXHEADER_LEN ) + return HSX_BADHDRWRITE; + + pHSX->fHdrChanged = FALSE; + pHSX->fFlush = TRUE; + } + return HSX_SUCCESS; +} + +static int hb_hsxFlush( int iHandle ) +{ + LPHSXINFO pHSX = hb_hsxGetPointer( iHandle ); + + if ( ! pHSX ) + return HSX_BADHANDLE; + + if ( pHSX->fChanged ) + { + HB_FOFFSET fOffset; + ULONG ulSize; + + fOffset = ( HB_FOFFSET ) HSXHEADER_LEN + + ( HB_FOFFSET ) ( pHSX->ulFirstRec - 1 ) * + ( HB_FOFFSET ) pHSX->uiRecordSize; + + if ( hb_fsSeekLarge( pHSX->hFile, fOffset, FS_SET ) != fOffset ) + return HSX_BADSEEK; + + ulSize = pHSX->ulBufRec * pHSX->uiRecordSize; + + if ( hb_fsWriteLarge( pHSX->hFile, pHSX->pBuffer, ulSize ) != ulSize ) + return HSX_BADWRITE; + + pHSX->fChanged = FALSE; + pHSX->fFlush = TRUE; + } + return HSX_SUCCESS; +} + +static int hb_hsxFlushAll( int iHandle ) +{ + int iRetVal; + + iRetVal = hb_hsxFlush( iHandle ); + if ( iRetVal == HSX_SUCCESS ) + iRetVal = hb_hsxHdrFlush( iHandle ); + + return iRetVal; +} + +static int hb_hsxHdrRead( int iHandle ) +{ + LPHSXINFO pHSX = hb_hsxGetPointer( iHandle ); + BYTE headrBuf[ HSXHEADER_LEN ]; + LPHSXHEADER pHeader = ( LPHSXHEADER ) headrBuf; + int iResult = HSX_SUCCESS; + + if ( ! pHSX ) + return HSX_BADHANDLE; + + if ( hb_fsSeek( pHSX->hFile, 0, FS_SET ) != 0 ) + return HSX_BADREAD; + if ( hb_fsRead( pHSX->hFile, headrBuf, HSXHEADER_LEN ) != HSXHEADER_LEN ) + return HSX_BADREAD; + + pHSX->ulRecCount = HB_GET_LE_UINT32( pHeader->recCount ); + pHSX->uiRecordSize = HB_GET_LE_UINT32( pHeader->recSize ); + pHSX->fIgnoreCase = HB_GET_LE_UINT16( pHeader->ignoreCase ) != 0; + pHSX->iFilterType = HB_GET_LE_UINT16( pHeader->filterType ); + pHSX->fUseHash = HB_GET_LE_UINT32( pHeader->hashLetters ) != 0; + + if ( pHeader->keyExpression[0] >= ' ' ) + { + headrBuf[ HSXHEADER_LEN - 1 ] = '\0'; + pHSX->szKeyExpr = hb_strdup( ( char * ) pHeader->keyExpression ); + iResult = hb_hsxCompile( pHSX->szKeyExpr, &pHSX->pKeyItem ); + } + + /* update the record counter */ + hb_hsxGetRecCount( pHSX ); + + return iResult; +} + +static int hb_hsxRead( int iHandle, ULONG ulRecord, BYTE ** pRecPtr ) +{ + LPHSXINFO pHSX = hb_hsxGetPointer( iHandle ); + BOOL fCount = pHSX->fShared; + + if ( ! pHSX ) + return HSX_BADHANDLE; + + if ( ulRecord > pHSX->ulRecCount && fCount ) + { + hb_hsxGetRecCount( pHSX ); + fCount = FALSE; + } + + if ( ulRecord == 0 || ulRecord > pHSX->ulRecCount ) + return HSX_RECBOUND; + + if ( pHSX->ulFirstRec == 0 || ulRecord < pHSX->ulFirstRec || + ulRecord >= pHSX->ulFirstRec + pHSX->ulBufRec ) + { + HB_FOFFSET fOffset; + ULONG ulSize, ulFirst; + int iRetVal; + + if ( ( iRetVal = hb_hsxFlush( iHandle ) ) != HSX_SUCCESS ) + return iRetVal; + + ulFirst = ulRecord; + if ( pHSX->fWrLocked && pHSX->fShared ) + pHSX->ulBufRec = 1; + else if ( ulFirst + pHSX->ulBufSize - 1 <= pHSX->ulRecCount ) + pHSX->ulBufRec = pHSX->ulBufSize; + else + { + if ( fCount ) + hb_hsxGetRecCount( pHSX ); + pHSX->ulBufRec = HB_MIN( pHSX->ulBufSize, pHSX->ulRecCount - ulFirst + 1 ); + } + + fOffset = ( HB_FOFFSET ) HSXHEADER_LEN + + ( HB_FOFFSET ) ( ulFirst - 1 ) * + ( HB_FOFFSET ) pHSX->uiRecordSize; + ulSize = pHSX->ulBufRec * pHSX->uiRecordSize; + + if ( hb_fsSeekLarge( pHSX->hFile, fOffset, FS_SET ) != fOffset ) + { + pHSX->ulFirstRec = pHSX->ulBufRec = 0; + return HSX_BADREAD; + } + if ( hb_fsReadLarge( pHSX->hFile, pHSX->pBuffer, ulSize ) != ulSize ) + { + pHSX->ulFirstRec = pHSX->ulBufRec = 0; + return HSX_BADREAD; + } + pHSX->ulFirstRec = ulFirst; + } + + *pRecPtr = pHSX->pBuffer + ( ulRecord - pHSX->ulFirstRec ) * pHSX->uiRecordSize; + + return HSX_SUCCESS; +} + +static int hb_hsxAppend( int iHandle, ULONG * pulRecNo, BYTE **pRecPtr ) +{ + LPHSXINFO pHSX = hb_hsxGetPointer( iHandle ); + + if ( ! pHSX ) + return HSX_BADHANDLE; + + if ( pHSX->ulFirstRec == 0 || pHSX->ulBufRec == pHSX->ulBufSize || + pHSX->ulFirstRec + pHSX->ulBufRec != pHSX->ulRecCount + 1 ) + { + int iRetVal; + + if ( ( iRetVal = hb_hsxFlush( iHandle ) ) != HSX_SUCCESS ) + return iRetVal; + + *pulRecNo = pHSX->ulFirstRec = ++pHSX->ulRecCount; + pHSX->ulBufRec = 1; + } + else + { + pHSX->ulBufRec++; + *pulRecNo = ++pHSX->ulRecCount; + } + *pRecPtr = pHSX->pBuffer + ( pHSX->ulBufRec - 1 ) * pHSX->uiRecordSize; + pHSX->fHdrChanged = TRUE; + + return HSX_SUCCESS; +} + +static int hb_hsxUpdate( int iHandle, ULONG ulRecord, BYTE **pRecPtr ) +{ + LPHSXINFO pHSX = hb_hsxGetPointer( iHandle ); + + if ( ! pHSX ) + return HSX_BADHANDLE; + + if ( ulRecord > pHSX->ulRecCount ) + { + /* this is intentional - when HSX index is bound with workarea + * then all updates should be synced by WA locks and it should + * be save to use REPLACE called from GOCOLD() method instead of + * ADD for newly appended records */ + if ( pHSX->iArea != 0 ) + pHSX->ulRecCount = ulRecord; + else if ( pHSX->fShared ) + hb_hsxGetRecCount( pHSX ); + } + + if ( ulRecord == 0 || ulRecord > pHSX->ulRecCount ) + return HSX_RECBOUND; + + if ( pHSX->ulFirstRec == 0 || ulRecord < pHSX->ulFirstRec || + ulRecord >= pHSX->ulFirstRec + pHSX->ulBufRec ) + { + int iRetVal; + + if ( ( iRetVal = hb_hsxFlush( iHandle ) ) != HSX_SUCCESS ) + return iRetVal; + + pHSX->ulFirstRec = ulRecord; + pHSX->ulBufRec = 1; + } + *pRecPtr = pHSX->pBuffer + ( ulRecord - pHSX->ulFirstRec ) * pHSX->uiRecordSize; + + return HSX_SUCCESS; +} + +static int hb_hsxLock( int iHandle, int iAction, ULONG ulRecord ) +{ + LPHSXINFO pHSX = hb_hsxGetPointer( iHandle ); + int iRetVal = HSX_SUCCESS, iRet; + BOOL fResult; + + HB_SYMBOL_UNUSED( ulRecord ); + + if ( ! pHSX ) + return HSX_BADHANDLE; + + if ( pHSX->fReadonly ) + { + switch ( iAction ) + { + case HSX_WRITELOCK: + case HSX_UPDATELOCK: + case HSX_APPENDLOCK: + case HSX_HDRWRITELOCK: + return HSX_LOCKFAILED; + } + } + + /* + * When HSX is bound with with workarea it should be synced + * by WA locks to not cause additional overhead with repeated + * operations. hb_hsxAdd() should be called when WA APPEND_LOCK + * is set and hb_hsxReplace() inside GOCOLD() method + */ + if ( pHSX->fShared && pHSX->iArea == 0 ) + { + switch ( iAction ) + { + case HSX_READLOCK: + break; + + case HSX_WRITELOCK: + case HSX_UPDATELOCK: + case HSX_APPENDLOCK: + do + { + fResult = hb_fsLockLarge( pHSX->hFile, HSX_HDRLOCKPOS, HSX_HDRLOCKSIZE, + FL_LOCK | FLX_EXCLUSIVE | FLX_WAIT ); + } while ( !fResult ); + if ( iRetVal == HSX_SUCCESS ) + { + /* discrad buffers in shared mode */ + pHSX->ulFirstRec = pHSX->ulBufRec = 0; + if ( iAction == HSX_APPENDLOCK ) + hb_hsxGetRecCount( pHSX ); + else if ( iAction == HSX_WRITELOCK ) + pHSX->fWrLocked = TRUE; + } + break; + + case HSX_HDRREADLOCK: + do + { + fResult = hb_fsLockLarge( pHSX->hFile, HSX_HDRLOCKPOS, HSX_HDRLOCKSIZE, + FL_LOCK | FLX_SHARED | FLX_WAIT ); + } while ( !fResult ); + break; + + case HSX_HDRWRITELOCK: + do + { + fResult = hb_fsLockLarge( pHSX->hFile, HSX_HDRLOCKPOS, HSX_HDRLOCKSIZE, + FL_LOCK | FLX_EXCLUSIVE | FLX_WAIT ); + } while ( !fResult ); + break; + + case HSX_READUNLOCK: + break; + + case HSX_WRITEUNLOCK: + case HSX_UPDATEUNLOCK: + case HSX_APPENDUNLOCK: + iRetVal = hb_hsxFlush( iHandle ); + if ( iAction == HSX_APPENDLOCK ) + pHSX->fWrLocked = FALSE; + case HSX_HDRWRITEUNLOCK: + iRet = hb_hsxHdrFlush( iHandle ); + if ( iRetVal == HSX_SUCCESS ) + iRetVal = iRet; + case HSX_HDRREADUNLOCK: + if ( ! hb_fsLockLarge( pHSX->hFile, HSX_HDRLOCKPOS, HSX_HDRLOCKSIZE, + FL_UNLOCK ) ) + { + if ( iRetVal == HSX_SUCCESS ) + iRetVal = HSX_CANNOTUNLOCK; + } + break; + } + } + + return iRetVal; +} + +static int hb_hsxIfDel( int iHandle, ULONG ulRecord ) +{ + BYTE *pRecPtr; + int iRetVal, iRet; + + iRetVal = hb_hsxLock( iHandle, HSX_READLOCK, ulRecord ); + + if ( iRetVal == HSX_SUCCESS ) + { + iRetVal = hb_hsxRead( iHandle, ulRecord, &pRecPtr ); + if ( iRetVal == HSX_SUCCESS ) + iRetVal = *pRecPtr & 0x80 ? HSX_SUCCESSFALSE : HSX_SUCCESS; + } + iRet = hb_hsxLock( iHandle, HSX_READUNLOCK, ulRecord ); + if ( iRetVal == HSX_SUCCESS ) + iRetVal = iRet; + return iRetVal; +} + +static int hb_hsxDelete( int iHandle, ULONG ulRecord ) +{ + LPHSXINFO pHSX = hb_hsxGetPointer( iHandle ); + int iRetVal, iRet; + + if ( ! pHSX ) + return HSX_BADHANDLE; + + iRetVal = hb_hsxLock( iHandle, HSX_UPDATELOCK, ulRecord ); + if ( iRetVal == HSX_SUCCESS ) + { + BYTE *pRecPtr; + + iRetVal = hb_hsxRead( iHandle, ulRecord, &pRecPtr ); + if ( iRetVal == HSX_SUCCESS ) + { + if ( *pRecPtr & 0x80 ) + iRetVal = HSX_ISDELETED; + else + { + *pRecPtr |= 0x80; + pHSX->fChanged = TRUE; + iRetVal = HSX_SUCCESS; + } + } + iRet = hb_hsxLock( iHandle, HSX_UPDATEUNLOCK, ulRecord ); + if ( iRetVal == HSX_SUCCESS ) + iRetVal = iRet; + } + return iRetVal; +} + +static int hb_hsxUnDelete( int iHandle, ULONG ulRecord ) +{ + LPHSXINFO pHSX = hb_hsxGetPointer( iHandle ); + int iRetVal, iRet; + + if ( ! pHSX ) + return HSX_BADHANDLE; + + iRetVal = hb_hsxLock( iHandle, HSX_UPDATELOCK, ulRecord ); + if ( iRetVal == HSX_SUCCESS ) + { + BYTE *pRecPtr; + + iRetVal = hb_hsxRead( iHandle, ulRecord, &pRecPtr ); + if ( iRetVal == HSX_SUCCESS ) + { + if ( ( *pRecPtr & 0x80 ) == 0 ) + iRetVal = HSX_NOTDELETED; + else + { + *pRecPtr &= ~0x80; + pHSX->fChanged = TRUE; + iRetVal = HSX_SUCCESS; + } + } + iRet = hb_hsxLock( iHandle, HSX_UPDATEUNLOCK, ulRecord ); + if ( iRetVal == HSX_SUCCESS ) + iRetVal = iRet; + } + return iRetVal; +} + +static int hb_hsxReplace( int iHandle, ULONG ulRecord, PHB_ITEM pExpr, BOOL fDeleted ) +{ + LPHSXINFO pHSX = hb_hsxGetPointer( iHandle ); + int iRetVal, iRet; + + if ( ! pHSX ) + return HSX_BADHANDLE; + + iRetVal = hb_hsxLock( iHandle, HSX_WRITELOCK, ulRecord ); + if ( iRetVal == HSX_SUCCESS ) + { + BYTE * pRecPtr; + + iRetVal = hb_hsxUpdate( iHandle, ulRecord, &pRecPtr ); + if ( iRetVal == HSX_SUCCESS ) + { + iRetVal = hb_hsxEval( iHandle, pExpr, pRecPtr, pExpr ? NULL : &fDeleted ); + if ( iRetVal == HSX_SUCCESS ) + { + if ( fDeleted ) + *pRecPtr |= 0x80; + pHSX->fChanged = TRUE; + } + } + iRet = hb_hsxLock( iHandle, HSX_WRITEUNLOCK, ulRecord ); + if ( iRetVal == HSX_SUCCESS ) + iRetVal = iRet; + } + return iRetVal; +} + +static int hb_hsxAdd( int iHandle, ULONG *pulRecNo, PHB_ITEM pExpr, BOOL fDeleted ) +{ + LPHSXINFO pHSX = hb_hsxGetPointer( iHandle ); + int iRetVal, iRet; + + if ( ! pHSX ) + return HSX_BADHANDLE; + + if ( !pExpr ) + pExpr = pHSX->pKeyItem; + + if ( !pExpr ) + return HSX_BADPARMS; + + iRetVal = hb_hsxLock( iHandle, HSX_APPENDLOCK, 0 ); + if ( iRetVal == HSX_SUCCESS ) + { + BYTE * pRecPtr; + ULONG ulRecNo; + + iRetVal = hb_hsxAppend( iHandle, &ulRecNo, &pRecPtr ); + if ( iRetVal == HSX_SUCCESS ) + { + iRetVal = hb_hsxEval( iHandle, pExpr, pRecPtr, pExpr ? NULL : &fDeleted ); + if ( iRetVal == HSX_SUCCESS ) + { + if ( fDeleted ) + *pRecPtr |= 0x80; + pHSX->fChanged = TRUE; + if ( pulRecNo ) + *pulRecNo = ulRecNo; + } + } + iRet = hb_hsxLock( iHandle, HSX_APPENDUNLOCK, 0 ); + if ( iRetVal == HSX_SUCCESS ) + iRetVal = iRet; + } + + return iRetVal; +} + +static int hb_hsxSeekSet( int iHandle, BYTE * pStr, ULONG ulLen ) +{ + LPHSXINFO pHSX = hb_hsxGetPointer( iHandle ); + int iRetVal; + + if ( !pHSX ) + return HSX_BADHANDLE; + + iRetVal = hb_hsxFlushAll( iHandle ); + if ( iRetVal == HSX_SUCCESS ) + { + if ( pHSX->ulRecCount == 0 ) + iRetVal = HSX_NORECS; + else + { + if ( pHSX->pSearchVal ) + hb_xfree( pHSX->pSearchVal ); + pHSX->pSearchVal = ( BYTE * ) hb_xgrab( ulLen + 1 ); + memcpy( pHSX->pSearchVal, pStr, ulLen ); + pHSX->pSearchVal[ ulLen ] = '\0'; + pHSX->ulSearch = ulLen; + if ( ! pHSX->pSearchKey ) + pHSX->pSearchKey = ( BYTE * ) hb_xgrab( pHSX->uiRecordSize ); + hb_hsxHashStr( pStr, ulLen, pHSX->pSearchKey, + pHSX->uiRecordSize, pHSX->fIgnoreCase, + pHSX->iFilterType, pHSX->fUseHash ); + pHSX->ulCurrRec = 0; + } + } + return iRetVal; +} + +static int hb_hsxNext( int iHandle, ULONG * pulRecNo ) +{ + LPHSXINFO pHSX = hb_hsxGetPointer( iHandle ); + int iRetVal, iRet; + + *pulRecNo = 0; + + if ( ! pHSX ) + return HSX_BADHANDLE; + + iRetVal = hb_hsxLock( iHandle, HSX_READLOCK, 0 ); + if ( iRetVal == HSX_SUCCESS ) + { + BYTE * pRecPtr; + int i; + + while ( pHSX->ulCurrRec < pHSX->ulRecCount ) + { + iRetVal = hb_hsxRead( iHandle, ++pHSX->ulCurrRec, &pRecPtr ); + if ( iRetVal != HSX_SUCCESS ) + break; + if ( ! hb_set.HB_SET_DELETED || ( *pRecPtr & 0x80 ) == 0 ) /* Not deleted */ + { + for ( i = 0; i < pHSX->uiRecordSize; i++ ) + { + if ( ( pRecPtr[ i ] & pHSX->pSearchKey[ i ] ) != pHSX->pSearchKey[ i ] ) + break; + } + if ( i == pHSX->uiRecordSize ) + { + *pulRecNo = pHSX->ulCurrRec; + break; + } + } + } + + iRet = hb_hsxLock( iHandle, HSX_READUNLOCK, 0 ); + if ( iRetVal == HSX_SUCCESS ) + iRetVal = iRet; + } + return iRetVal; +} + +static LPHSXINFO hb_hsxNew( void ) +{ + LPHSXINFO pHSX; + int iHandle = 0; + + if ( s_iHandleSize == 0 ) + { + s_iHandleSize = HSX_HALLOC; + s_handleArray = ( LPHSXINFO * ) hb_xgrab( sizeof( LPHSXINFO ) * HSX_HALLOC ); + memset( s_handleArray, 0, sizeof( LPHSXINFO ) * s_iHandleSize ); + } + else + { + while ( iHandle < s_iHandleSize ) + { + if ( s_handleArray[ iHandle ] == NULL ) + break; + iHandle++; + } + if ( iHandle == s_iHandleSize ) + { + s_iHandleSize += HSX_HALLOC; + s_handleArray = ( LPHSXINFO * ) hb_xrealloc( s_handleArray, + sizeof( LPHSXINFO ) * s_iHandleSize ); + memset( &s_handleArray[ iHandle ], 0, sizeof( LPHSXINFO ) * HSX_HALLOC ); + } + } + s_handleArray[ iHandle ] = pHSX = ( LPHSXINFO ) hb_xgrab( sizeof( HSXINFO ) ); + s_iHandleCount++; + memset( pHSX, 0, sizeof( HSXINFO ) ); + pHSX->iHandle = iHandle; + pHSX->hFile = FS_ERROR; + + return pHSX; +} + +static void hb_hsxExpDestroy( PHB_ITEM pItem ) +{ + if ( hb_itemType( pItem ) == HB_IT_POINTER ) + hb_macroDelete( ( HB_MACRO_PTR ) hb_itemGetPtr( pItem ) ); + hb_itemRelease( pItem ); +} + +static int hb_hsxVerify( int iHandle, BYTE * szText, ULONG ulLen, + BYTE * szSub, ULONG ulSub, int iType ) +{ + LPHSXINFO pHSX = hb_hsxGetPointer( iHandle ); + int iResult; + + if ( !szSub && pHSX ) + { + szSub = pHSX->pSearchVal; + ulSub = pHSX->ulSearch; + } + if ( !pHSX ) + iResult = HSX_BADHANDLE; + else if ( !szText || !szSub ) + iResult = HSX_BADPARMS; + else if ( ulSub > ulLen || ulSub == 0 ) + /* !ulSub -> do not accept empty substrings as $ operator at runtime */ + iResult = HSX_SUCCESSFALSE; + else + { + ULONG ul, ull; + + switch ( iType ) + { + case HSX_VERIFY_BEGIN: + iResult = hb_hsxStrCmp( szSub, ulSub, szText, ulSub, + pHSX->fIgnoreCase, pHSX->iFilterType ); + break; + case HSX_VERIFY_END: + iResult = hb_hsxStrCmp( szSub, ulSub, szText + ulLen - ulSub, ulSub, + pHSX->fIgnoreCase, pHSX->iFilterType ); + break; + case HSX_VERIFY_AND: + iResult = HSX_SUCCESS; + for ( ul = 0; ul < ulSub && iResult == HSX_SUCCESS; ul++ ) + { + while ( szSub[ ul ] == ' ' && ul < ulSub ) + ++ul; + ull = ul; + while ( szSub[ ull ] != ' ' && ull < ulSub ) + ++ull; + iResult = hb_hsxStrCmp( &szSub[ ul ], ull - ul, szText, ulLen, + pHSX->fIgnoreCase, pHSX->iFilterType ); + ul = ull; + } + break; +/* + case HSX_VERIFY_OR: + iResult = HSX_SUCCESSFALSE; + for ( ul = 0; ul < ulSub && iResult == HSX_SUCCESSFALSE; ul++ ) + { + while ( szSub[ ul ] == ' ' && ul < ulSub ) + ++ul; + ull = ul; + while ( szSub[ ull ] != ' ' && ull < ulSub ) + ++ull; + iResult = hb_hsxStrCmp( &szSub[ ul ], ull - ul, szText, ulLen, + pHSX->fIgnoreCase, pHSX->iFilterType ); + ul = ull; + } + break; +*/ + case HSX_VERIFY_PHRASE: + default: + iResult = hb_hsxStrCmp( szSub, ulSub, szText, ulLen, + pHSX->fIgnoreCase, pHSX->iFilterType ); + } + } + return iResult; +} + +static int hb_hsxDestroy( int iHandle ) +{ + if ( iHandle >=0 && iHandle < s_iHandleSize && s_handleArray[ iHandle ] != NULL ) + { + LPHSXINFO pHSX = s_handleArray[ iHandle ]; + int iRetVal = HSX_SUCCESS; + + if ( pHSX->hFile != FS_ERROR ) + { + iRetVal = hb_hsxFlushAll( iHandle ); + hb_fsClose( pHSX->hFile ); + } + + if ( pHSX->szFileName ) + hb_xfree( pHSX->szFileName ); + if ( pHSX->pSearchVal ) + hb_xfree( pHSX->pSearchVal ); + if ( pHSX->pSearchKey ) + hb_xfree( pHSX->pSearchKey ); + if ( pHSX->pBuffer ) + hb_xfree( pHSX->pBuffer ); + if ( pHSX->szKeyExpr ) + hb_xfree( pHSX->szKeyExpr ); + if ( pHSX->pKeyItem ) + hb_hsxExpDestroy( pHSX->pKeyItem ); + hb_xfree( pHSX ); + + s_handleArray[ iHandle ] = NULL; + if ( --s_iHandleCount == 0 ) + { + hb_xfree( s_handleArray ); + s_iHandleSize = 0; + s_handleArray = NULL; + } + return iRetVal; + } + return HSX_BADHANDLE; +} + +static int hb_hsxCreate( char * szFile, int iBufSize, int iKeySize, + BOOL fIgnoreCase, int iFilter, PHB_ITEM pExpr ) +{ + char szFileName[ _POSIX_PATH_MAX + 1 ], * szExpr = NULL; + PHB_ITEM pKeyExpr = NULL; + ULONG ulBufSize; + USHORT uiRecordSize; + LPHSXINFO pHSX; + FHANDLE hFile; + int iRetVal; + + if ( !szFile || ! *szFile ) + return HSX_BADPARMS; + + hb_strncpy( szFileName, szFile, _POSIX_PATH_MAX ); + + if ( iKeySize < 1 || iKeySize > HSXMAXKEY_SIZE ) + iKeySize = HSXDEFKEY_SIZE; + if ( iFilter < 1 || iFilter > 3 ) + iFilter = HSXDEFFILTER; + + ulBufSize = iBufSize * 1024; + if ( ulBufSize == 0 ) + ulBufSize = HSXDEFBUF_LEN; + else if ( ulBufSize < HSXMINBUF_LEN ) + ulBufSize = HSXMINBUF_LEN; + else if ( ulBufSize > HSXMAXBUF_LEN ) + ulBufSize = HSXMAXBUF_LEN; + uiRecordSize = ( USHORT ) 0x08 << iKeySize; + ulBufSize /= uiRecordSize; + if ( ulBufSize == 0 ) + ulBufSize = 1; + + if ( pExpr ) + { + if ( hb_itemGetCLen( pExpr ) > 0 ) + { + szExpr = hb_itemGetCPtr( pExpr ); + iRetVal = hb_hsxCompile( szExpr, &pKeyExpr ); + if ( iRetVal != HSX_SUCCESS ) + return iRetVal; + } + else if ( hb_itemType( pExpr ) == HB_IT_BLOCK ) + pKeyExpr = hb_itemNew( pExpr ); + } + + hFile = hb_fsExtOpen( ( BYTE * ) szFileName, ( BYTE * ) HSX_FILEEXT, + FO_READWRITE | FO_EXCLUSIVE | FXO_TRUNCATE | + FXO_DEFAULTS | FXO_SHARELOCK | FXO_COPYNAME, + NULL, NULL ); + + if( hFile == FS_ERROR ) + { + if ( pKeyExpr ) + hb_hsxExpDestroy( pKeyExpr ); + return HSX_CREATEFAIL; + } + + pHSX = hb_hsxNew(); + pHSX->uiRecordSize = uiRecordSize; + pHSX->fIgnoreCase = fIgnoreCase; + pHSX->iFilterType = iFilter; + pHSX->fUseHash = fIgnoreCase && iKeySize == 2 && iFilter != 3; + pHSX->hFile = hFile; + pHSX->szFileName = hb_strdup( szFileName ); + pHSX->fShared = FALSE; + pHSX->fReadonly = FALSE; + if ( szExpr ) + pHSX->szKeyExpr = hb_strdup( szExpr ); + pHSX->pKeyItem = pKeyExpr; + pHSX->pBuffer = ( BYTE * ) hb_xalloc( ulBufSize * uiRecordSize ); + if ( pHSX->pBuffer == NULL ) + { + hb_hsxDestroy( pHSX->iHandle ); + return HSX_MEMERR; + } + pHSX->ulBufSize = ulBufSize; + + pHSX->fHdrChanged = TRUE; + iRetVal = hb_hsxHdrFlush( pHSX->iHandle ); + if ( iRetVal != HSX_SUCCESS ) + { + hb_hsxDestroy( pHSX->iHandle ); + return iRetVal; + } + + return pHSX->iHandle; +} + +static int hb_hsxOpen( char * szFile, int iBufSize, int iMode ) +{ + char szFileName[ _POSIX_PATH_MAX + 1 ]; + BOOL fShared, fReadonly; + FHANDLE hFile; + ULONG ulBufSize; + USHORT uiFlags; + LPHSXINFO pHSX; + int iRetVal, iRet; + + if ( !szFile || ! *szFile ) + return HSX_BADPARMS; + + hb_strncpy( szFileName, szFile, _POSIX_PATH_MAX ); + + ulBufSize = iBufSize * 1024; + if ( ulBufSize == 0 ) + ulBufSize = HSXDEFBUF_LEN; + else if ( ulBufSize < HSXMINBUF_LEN ) + ulBufSize = HSXMINBUF_LEN; + else if ( ulBufSize > HSXMAXBUF_LEN ) + ulBufSize = HSXMAXBUF_LEN; + + if ( iMode < 0 || iMode > 3 ) + iMode = HSXDEFOPENMODE; + + fReadonly = ( iMode & 0x02 ) != 0; + fShared = ( iMode & 0x01 ) == 0; + if( hb_set.HB_SET_AUTOSHARE == 2 ) + fShared = FALSE; + uiFlags = ( fReadonly ? FO_READ : FO_READWRITE ) | + ( fShared ? FO_DENYNONE : FO_EXCLUSIVE ); + + hFile = hb_fsExtOpen( ( BYTE * ) szFileName, ( BYTE * ) HSX_FILEEXT, + uiFlags | FXO_DEFAULTS | FXO_SHARELOCK | FXO_COPYNAME, + NULL, NULL ); + + if ( hFile == FS_ERROR ) + return HSX_OPENERR; + + pHSX = hb_hsxNew(); + pHSX->hFile = hFile; + pHSX->szFileName = hb_strdup( szFileName ); + pHSX->fShared = fShared; + pHSX->fReadonly = fReadonly; + iRetVal = hb_hsxLock( pHSX->iHandle, HSX_HDRREADLOCK, 0 ); + if ( iRetVal == HSX_SUCCESS ) + { + iRetVal = hb_hsxHdrRead( pHSX->iHandle ); + iRet = hb_hsxLock( pHSX->iHandle, HSX_HDRREADUNLOCK, 0 ); + if ( iRetVal == HSX_SUCCESS ) + iRetVal = iRet; + } + if ( iRetVal != HSX_SUCCESS ) + { + hb_hsxDestroy( pHSX->iHandle ); + return iRetVal; + } + + ulBufSize /= pHSX->uiRecordSize; + if ( ulBufSize == 0 ) + ulBufSize = 1; + + pHSX->pBuffer = ( BYTE * ) hb_xalloc( ulBufSize * pHSX->uiRecordSize ); + if ( pHSX->pBuffer == NULL ) + { + hb_hsxDestroy( pHSX->iHandle ); + return HSX_MEMERR; + } + pHSX->ulBufSize = ulBufSize; + + return pHSX->iHandle; +} + +static int hb_hsxIndex( char * szFile, PHB_ITEM pExpr, int iKeySize, int iMode, + int iBufSize, BOOL fIgnoreCase, int iFilter ) +{ + int iRetVal = HSX_SUCCESS, iHandle; + ULONG ulRecNo = 0, ulRecCount = 0, ulNewRec, ulRec; + ERRCODE errCode; + AREAP pArea = ( AREAP ) hb_rddGetCurrentWorkAreaPointer(); + + if ( !pArea ) + { + hb_errRT_DBCMD( EG_NOTABLE, EDBCMD_NOTABLE, NULL, "HS_INDEX" ); + return HSX_NOTABLE; + } + + iHandle = hb_hsxCreate( szFile, iBufSize, iKeySize, fIgnoreCase, iFilter, pExpr ); + if ( iHandle < 0 ) + return iHandle; + + errCode = SELF_RECCOUNT( pArea, &ulRecCount ); + if ( errCode != FAILURE && ulRecCount ) + { + errCode = SELF_RECNO( pArea, &ulRecNo ); + if ( errCode != FAILURE ) + { + for ( ulRec = 1; ulRec <= ulRecCount; ulRec++ ) + { + errCode = SELF_GOTO( pArea, ulRec ); + if ( errCode == FAILURE ) + break; + iRetVal = hb_hsxAdd( iHandle, &ulNewRec, NULL, FALSE ); + if ( iRetVal != HSX_SUCCESS ) + break; + if ( ulNewRec != ulRec ) + { + iRetVal = HSX_RECBOUND; + break; + } + } + if ( pArea->valResult ) + { + hb_itemRelease( pArea->valResult ); + pArea->valResult = NULL; + } + if ( ulRecNo ) + SELF_GOTO( pArea, ulRecNo ); + } + } + hb_hsxDestroy( iHandle ); + if ( iRetVal != HSX_SUCCESS ) + return iRetVal; + if ( errCode == FAILURE ) + return HSX_RDDFAILURE; + + return hb_hsxOpen( szFile, iBufSize, iMode ); +} + +static int hb_hsxFilter( int iHandle, BYTE * pSeek, ULONG ulSeek, + PHB_ITEM pVerify, int iVerifyType ) +{ + AREAP pArea = ( AREAP ) hb_rddGetCurrentWorkAreaPointer(); + LPHSXINFO pHSX = hb_hsxGetPointer( iHandle ); + BOOL fDestroyExpr = FALSE, fValid; + int iResult = HSX_SUCCESS; + ERRCODE errCode; + ULONG ulRecNo = 0, ulRec; + PHB_ITEM pItem; + + if ( !pHSX ) + return HSX_BADHANDLE; + + if ( !pArea ) + { + hb_errRT_DBCMD( EG_NOTABLE, EDBCMD_NOTABLE, NULL, "HS_FILTER" ); + return HSX_NOTABLE; + } + + if ( ! pVerify || hb_itemType( pVerify ) == HB_IT_NIL ) + pVerify = pHSX->pKeyItem; + else + { + if ( hb_itemGetCLen( pVerify ) > 0 ) + { + iResult = hb_hsxCompile( hb_itemGetCPtr( pVerify ), &pVerify ); + if ( iResult != HSX_SUCCESS ) + return HSX_BADPARMS; + fDestroyExpr = TRUE; + } + else if ( hb_itemType( pVerify ) != HB_IT_BLOCK ) + { + pVerify = NULL; + } + } + + errCode = SELF_RECNO( pArea, &ulRecNo ); + if ( errCode != FAILURE ) + iResult = hb_hsxSeekSet( iHandle, pSeek, ulSeek ); + + fValid = TRUE; + pItem = hb_itemNew( NULL ); + while ( iResult == HSX_SUCCESS && errCode != FAILURE ) + { + iResult = hb_hsxNext( iHandle, &ulRec ); + if ( iResult != HSX_SUCCESS || ulRec == 0 ) + break; + if ( pVerify ) + { + errCode = SELF_GOTO( pArea, ulRec ); + if ( errCode == FAILURE ) + break; + errCode = SELF_EVALBLOCK( pArea, pVerify ); + if ( errCode == FAILURE ) + break; + fValid = hb_hsxVerify( iHandle, + ( BYTE * ) hb_itemGetCPtr( pArea->valResult ), + hb_itemGetCLen( pArea->valResult ), + pSeek, ulSeek, iVerifyType ) == HSX_SUCCESS; + } + if ( fValid ) + { + /* set record in WA RM filter */ + hb_itemPutNInt( pItem, ulRec ); + errCode = SELF_INFO( pArea, DBI_RM_ADD, pItem ); + } + } + if ( pArea->valResult ) + { + hb_itemRelease( pArea->valResult ); + pArea->valResult = NULL; + } + hb_itemRelease( pItem ); + + if ( ulRecNo ) + SELF_GOTO( pArea, ulRecNo ); + + if ( fDestroyExpr ) + hb_hsxExpDestroy( pVerify ); + + return errCode == FAILURE ? HSX_RDDFAILURE : iResult; +} + + +/* ************************************************************************ */ +/* .prg level functions: HS_*() */ +/* ************************************************************************ */ + +/* hs_Create( , , , , , ) + -> nVal >=0 (OK: ), nVal < 0 (ERROR CODE) + Creates a new, empty HiPer-SEEK index file */ +HB_FUNC( HS_CREATE ) +{ + hb_retni( hb_hsxCreate( hb_parc( 1 ), hb_parni( 2 ), hb_parni( 3 ), + hb_param( 4, HB_IT_LOGICAL ) == NULL || hb_parl( 4 ), + hb_parni( 5 ), hb_param( 6, HB_IT_ANY ) ) ); +} + +/* hs_Open( , , ) + -> nVal >=0 (OK: ), nVal < 0 (ERROR CODE) + Opens an existing HiPer-SEEK index file */ +HB_FUNC( HS_OPEN ) +{ + hb_retni( hb_hsxOpen( hb_parc( 1 ), hb_parni( 2 ), + hb_param( 3, HB_IT_NUMERIC ) ? hb_parni( 3 ) : HSXDEFOPENMODE ) ); +} + +/* hs_Close( ) -> nVal = 1 (OK), nVal < 0 (ERROR CODE) + Closes a previously opened HiPer-SEEK index file */ +HB_FUNC( HS_CLOSE ) +{ + if ( hb_param( 1, HB_IT_NUMERIC ) ) + hb_retni( hb_hsxDestroy( hb_parni( 1 ) ) ); + else + hb_retni( HSX_BADPARMS ); +} + +/* hs_Index( , , , , , , + ) -> nVal >=0 (OK: ), nVal < 0 (ERROR CODE) + Creates and populates a new HiPer-SEEK index */ +HB_FUNC( HS_INDEX ) +{ + hb_retni( hb_hsxIndex( hb_parc( 1 ), hb_param( 2, HB_IT_ANY ), hb_parni( 3 ), + hb_param( 4, HB_IT_NUMERIC ) ? hb_parni( 4 ) : HSXDEFOPENMODE, + hb_parni( 5 ), + hb_param( 6, HB_IT_LOGICAL ) == NULL || hb_parl( 6 ), + hb_parni( 7 ) ) ); +} + +/* hs_Add( , , [lDel] ) -> nVal >= 1 (RECNO), nVal < 0 (ERROR CODE) + Adds a text string entry to a HiPer-SEEK index file */ +HB_FUNC( HS_ADD ) +{ + if ( hb_param( 1, HB_IT_NUMERIC ) ) + { + ULONG ulRecNo; + int iRetVal; + + iRetVal = hb_hsxAdd( hb_parni( 1 ), &ulRecNo, + hb_param( 2, HB_IT_ANY ), hb_parl( 3 ) ); + + if ( iRetVal == HSX_SUCCESS ) + hb_retnint( ulRecNo ); + else + hb_retni( iRetVal ); + } + else + hb_retni( HSX_BADPARMS ); +} + +/* hs_Replace( , , , [lDel] ) -> nVal = 1 (OK), nVal < 0 (ERROR CODE) + Replaces current HiPer-SEEK index entry with a new value */ +HB_FUNC( HS_REPLACE ) +{ + if ( hb_param( 1, HB_IT_NUMERIC ) && hb_param( 3, HB_IT_NUMERIC ) ) + hb_retni( hb_hsxReplace( hb_parni( 1 ), hb_parnl( 3 ), + hb_param( 2, HB_IT_ANY ), hb_parl( 4 ) ) ); + else + hb_retni( HSX_BADPARMS ); +} + +/* hs_IfDel( , ) -> nVal = {0|1} (DELETED), nVal < 0 (ERROR CODE) + Determines if a HiPer-SEEK record is marked as deleted */ +HB_FUNC( HS_IFDEL ) +{ + if ( hb_param( 1, HB_IT_NUMERIC ) && hb_param( 2, HB_IT_NUMERIC ) ) + hb_retni( hb_hsxIfDel( hb_parni( 1 ), hb_parnl( 2 ) ) ); + else + hb_retni( HSX_BADPARMS ); +} + +/* hs_Delete( , ) -> nVal = 1 (OK), nVal < 0 (ERROR CODE) + Deletes specifed index record from HiPer-SEEK index file */ +HB_FUNC( HS_DELETE ) +{ + if ( hb_param( 1, HB_IT_NUMERIC ) && hb_param( 2, HB_IT_NUMERIC ) ) + hb_retni( hb_hsxDelete( hb_parni( 1 ), hb_parnl( 2 ) ) ); + else + hb_retni( HSX_BADPARMS ); +} + +/* hs_Undelete( , ) -> nVal = 1 (OK), nVal < 0 (ERROR CODE) + Unmarks the specified HiPer-SEEK record as being deleted */ +HB_FUNC( HS_UNDELETE ) +{ + if ( hb_param( 1, HB_IT_NUMERIC ) && hb_param( 2, HB_IT_NUMERIC ) ) + hb_retni( hb_hsxUnDelete( hb_parni( 1 ), hb_parnl( 2 ) ) ); + else + hb_retni( HSX_BADPARMS ); +} + +/* hs_KeyCount( ) -> nVal >= 0 (RECCOUNT), nVal < 0 (ERROR CODE) + Returns the number of entries in a HiPer-SEEK index */ +HB_FUNC( HS_KEYCOUNT ) +{ + if ( hb_param( 1, HB_IT_NUMERIC ) ) + { + LPHSXINFO pHSX = hb_hsxGetPointer( hb_parni( 1 ) ); + + if ( pHSX ) + { + if ( pHSX->fShared ) + hb_hsxGetRecCount( pHSX ); + + hb_retnint( pHSX->ulRecCount ); + } + else + hb_retni( HSX_BADHANDLE ); + } + else + hb_retni( HSX_BADPARMS ); +} + +/* hs_Set( , ) -> nVal = 1 (OK), nVal < 0 (ERROR CODE) + Sets up parameters for a subsequent hs_Next() call */ +HB_FUNC( HS_SET ) +{ + BYTE * pStr = ( BYTE * ) hb_parc( 2 ); + int iRetVal = HSX_BADPARMS; + + if ( pStr && hb_param( 1, HB_IT_NUMERIC ) ) + iRetVal = hb_hsxSeekSet( hb_parni( 1 ), pStr, hb_parclen( 2 ) ); + hb_retni( iRetVal ); +} + +/* hs_Filter( , , [xRealExp], [nBufSize], [nOpenMode] ) -> nRecMatch + Sets a WA RM filter using a HiPer-SEEK index */ +HB_FUNC( HS_FILTER ) +{ + BYTE * szText = ( BYTE * ) hb_parc( 2 ), * pBuff = NULL; + ULONG ulLen = hb_parclen( 2 ), ulRecords = 0, ull, ul; + int iHandle = -1, iResult = HSX_BADPARMS; + BOOL fNew = FALSE, fToken = TRUE; + + if ( hb_parclen( 1 ) > 0 ) + { + if ( ulLen > 0 ) + { + iHandle = hb_hsxOpen( hb_parc( 1 ), hb_parni( 4 ), + hb_param( 5, HB_IT_NUMERIC ) ? hb_parni( 5 ) : HSXDEFOPENMODE ); + if ( iHandle >= 0 ) + fNew = TRUE; + else + iResult = iHandle; + } + } + else if ( hb_param( 1, HB_IT_NUMERIC ) ) + { + LPHSXINFO pHSX = hb_hsxGetPointer( hb_parni( 1 ) ); + + if ( ! pHSX ) + iResult = HSX_BADHANDLE; + else + { + iHandle = pHSX->iHandle; + if ( !szText ) + { + ulLen = pHSX->ulSearch; + if ( ulLen && pHSX->pSearchVal ) + { + pBuff = ( BYTE * ) hb_xgrab( ulLen + 1 ); + memcpy( pBuff, pHSX->pSearchVal, ulLen ); + pBuff[ ulLen ] = '\0'; + szText = pBuff; + fToken = FALSE; + } + } + } + } + if ( iHandle >= 0 && ulLen > 0 ) + { + PHB_ITEM pItem = hb_itemNew( NULL ); + AREAP pArea = ( AREAP ) hb_rddGetCurrentWorkAreaPointer(); + + if ( !pArea ) + { + hb_errRT_DBCMD( EG_NOTABLE, EDBCMD_NOTABLE, NULL, "HS_FILTER" ); + iResult = HSX_NOTABLE; + } + /* create empty workarea RM filter */ + else if ( SELF_INFO( pArea, DBI_RM_CREATE, pItem ) == FAILURE ) + iResult = HSX_RDDFAILURE; + else + { + /* to be SIX compatible divide given text on space delimited tokens */ + if ( fToken ) + { + iResult = HSX_SUCCESS; + for ( ul = 0; ul < ulLen && iResult == HSX_SUCCESS; ul++ ) + { + while ( szText[ ul ] == ' ' && ul < ulLen ) + ++ul; + ull = ul; + while ( szText[ ull ] != ' ' && ull < ulLen ) + ++ull; + iResult = hb_hsxFilter( iHandle, &szText[ ul ], ull - ul, + hb_param( 3, HB_IT_ANY ), HSX_VERIFY_PHRASE ); + ul = ull; + } + } + else + { + iResult = hb_hsxFilter( iHandle, szText, ulLen, + hb_param( 3, HB_IT_ANY ), HSX_VERIFY_PHRASE ); + } + } + if ( iResult == HSX_SUCCESS ) + { + hb_itemPutNI( pItem, 0 ); + if ( SELF_INFO( pArea, DBI_RM_COUNT, pItem ) == FAILURE ) + iResult = HSX_RDDFAILURE; + else + ulRecords = hb_itemGetNL( pItem ); + } + hb_itemRelease( pItem ); + + if ( fNew ) + hb_hsxDestroy( iHandle ); + } + if ( pBuff ) + hb_xfree( pBuff ); + + if ( iResult != HSX_SUCCESS ) + hb_retni( iResult ); + else + hb_retnint( ulRecords ); +} + +/* hs_Next( ) -> nVal >= 0 (RECNO), nVal < 0 (ERROR CODE) + Searches a HiPer-SEEK index file for first/next match */ +HB_FUNC( HS_NEXT ) +{ + ULONG ulRecNo = 0; + int iRetVal = HSX_BADPARMS; + + if ( hb_param( 1, HB_IT_NUMERIC ) ) + iRetVal = hb_hsxNext( hb_parni( 1 ), &ulRecNo ); + + if ( iRetVal == HSX_SUCCESS ) + hb_retnint( ulRecNo ); + else + hb_retni( iRetVal ); +} + +/* hs_Verify( , , , ) + -> nVal = {0|1} (VERIFIED), nVal < 0 (ERROR CODE) + hs_Verify( , ) -> lOK + Verifies hs_Next() hit against code block expression */ +HB_FUNC( HS_VERIFY ) +{ + if ( hb_param( 1, HB_IT_NUMERIC ) ) + { + int iHandle = hb_parni( 1 ); + PHB_ITEM pExpr = hb_param( 2, HB_IT_BLOCK ); + BYTE * szText = NULL; + ULONG ulLen = 0; + LPHSXINFO pHSX; + + pHSX = hb_hsxGetPointer( iHandle ); + if ( !pHSX ) + { + hb_retni( HSX_BADHANDLE ); + return; + } + if ( pExpr ) + pExpr = hb_vmEvalBlockOrMacro( pExpr ); + else + { + pExpr = hb_param( 2, HB_IT_STRING ); + if ( !pExpr && pHSX->pKeyItem ) + pExpr = hb_vmEvalBlockOrMacro( pHSX->pKeyItem ); + } + if ( pExpr ) + { + szText = ( BYTE * ) hb_itemGetCPtr( pExpr ); + ulLen = hb_itemGetCLen( pExpr ); + } + + hb_retni( hb_hsxVerify( hb_parni( 1 ), szText, ulLen, + ( BYTE * ) hb_parc( 3 ), hb_parclen( 3 ), + hb_parni( 4 ) ) ); + } + else + { + PHB_ITEM pExpr = hb_param( 1, HB_IT_BLOCK ); + BYTE * szSub = ( BYTE * ) hb_parc( 2 ), * szText = NULL; + ULONG ulSub = hb_parclen( 2 ), ulLen = 0; + BOOL fIgnoreCase = hb_parl( 3 ); + + if ( ulSub ) + { + pExpr = pExpr ? hb_vmEvalBlockOrMacro( pExpr ) : hb_param( 2, HB_IT_STRING ); + + if ( pExpr ) + { + szText = ( BYTE * ) hb_itemGetCPtr( pExpr ); + ulLen = hb_itemGetCLen( pExpr ); + } + } + hb_retl( ulLen && ulSub && hb_hsxStrCmp( szSub, ulSub, szText, ulLen, + fIgnoreCase, 3 ) ); + } +} + +/* hs_Version() -> */ +HB_FUNC( HS_VERSION ) +{ + static const char szVer[] = "HiPer-SEEK / FTS library emulation"; + char * pszHBVersion, * pszVersion; + int iLen; + + pszHBVersion = hb_verHarbour(); + iLen = strlen( szVer ) + strlen( pszHBVersion ) + 2; + pszVersion = ( char * ) hb_xgrab( iLen + 1 ); + sprintf( pszVersion, "%s: %s", szVer, pszHBVersion ); + hb_retclen_buffer( pszVersion, iLen ); + hb_xfree( pszHBVersion ); +} diff --git a/harbour/source/rdd/nulsys/nulsys.prg b/harbour/source/rdd/nulsys/nulsys.prg index 54ed40ce75..12be68b3d2 100644 --- a/harbour/source/rdd/nulsys/nulsys.prg +++ b/harbour/source/rdd/nulsys/nulsys.prg @@ -9,7 +9,7 @@ * Copyright 1999 Bruno Cantero * www - http://www.harbour-project.org * - * This program is free software; you can redistribute it and/or modify + * This program is hb_xfree software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. @@ -54,6 +54,147 @@ ANNOUNCE RDDSYS -init procedure RDDInit +PROCEDURE RDDInit -return +RETURN + +PROCEDURE DBFInit + +RETURN + +#pragma BEGINDUMP + +#include "hbrddwrk.h" + +HB_FUNC ( NETERR ) { hb_retl( FALSE ); } + +HB_FUNC ( FIELDPOS ) { hb_retni( 0 ); } + +HB_FUNC( DBRELATION ) { hb_retc( NULL ); } + +HB_FUNC( DBRSELECT ) { hb_retni( 0 ); } + +HB_FUNC( ORDNAME ) { hb_retc( NULL ); } + +HB_FUNC( INDEXORD ) { hb_parni(1); } + +HB_FUNC( RDDNAME ) { hb_retc( NULL ); } + +HB_FUNC( RDDLIST ) { hb_reta( 0 ); } + +HB_FUNC( DBCREATE ) {} + +HB_FUNC( DBCLOSEAREA ) {} + +HB_FUNC( ALIAS ) { hb_retc( NULL ); } + +HB_FUNC( DBAPPEND ) {} + +HB_FUNC( DBSKIP ) { hb_retni( 0 ); } + +HB_FUNC( FIELDGET ) { hb_retc( NULL ); } + +HB_FUNC( FIELDPUT ) { hb_retc( NULL ); } + +HB_FUNC( DBUNLOCK ) { hb_retl( FALSE ); } + +HB_FUNC( DBSKIPPER ) { hb_retni( 0 ); } + +HB_FUNC( DBSEEK ) { hb_retl( FALSE ); } + +HB_FUNC( DBGOTO ) { hb_retni( 0 ); } + +HB_FUNC( INDEXKEY ) { hb_retc( NULL ); } + +HB_FUNC( DBGOTOP ) {} + +HB_FUNC( DBGOBOTTOM ) {} + +HB_FUNC( USED ) { hb_retl( FALSE ); } + +HB_FUNC( SELECT ) { hb_retni( 0 ); } + +HB_FUNC( LOCK ) { hb_retl( FALSE ); } + +HB_FUNC( LASTREC ) { hb_retni( 0 ); } + +HB_FUNC( FOUND ) { hb_retl( FALSE ); } + +HB_FUNC( FLOCK ) { hb_retl( FALSE ); } + +HB_FUNC( DELETED ) { hb_retl( FALSE ); } + +HB_FUNC( BOF ) { hb_retl( FALSE ); } + +HB_FUNC( FIELDNAME ) { hb_retc( NULL ); } + +HB_FUNC( RECCOUNT ) { hb_parni( 0 ); } + +HB_FUNC( FCOUNT ) { hb_parni( 0 ); } + +HB_FUNC( RLOCK ) { hb_retl( FALSE ); } + +HB_FUNC( RECNO ) { hb_retni( 0 ); } + +HB_FUNC( EOF ) { hb_retl( FALSE ); } + +void hb_rddShutDown( void ) {} + +ERRCODE HB_EXPORT hb_rddFieldPut( HB_ITEM_PTR pItem, PHB_SYMB pFieldSymbol ) +{ + HB_SYMBOL_UNUSED( pItem ); + HB_SYMBOL_UNUSED( pFieldSymbol ); + + return FAILURE; +} + +ERRCODE HB_EXPORT hb_rddSelectWorkAreaSymbol( PHB_SYMB pSymAlias ) +{ + HB_SYMBOL_UNUSED( pSymAlias ); + + return FAILURE; +} + +ERRCODE HB_EXPORT hb_rddSelectWorkAreaAlias( char * szName ) +{ + HB_SYMBOL_UNUSED( szName ); + + return FAILURE; +} + +ERRCODE HB_EXPORT hb_rddGetFieldValue( HB_ITEM_PTR pItem, PHB_SYMB pFieldSymbol ) +{ + HB_SYMBOL_UNUSED( pItem ); + HB_SYMBOL_UNUSED( pFieldSymbol ); + + return FAILURE; +} + +ERRCODE HB_EXPORT hb_rddFieldGet( HB_ITEM_PTR pItem, PHB_SYMB pFieldSymbol ) +{ + HB_SYMBOL_UNUSED( pItem ); + HB_SYMBOL_UNUSED( pFieldSymbol ); + + return FAILURE; +} + +ERRCODE HB_EXPORT hb_rddSelectWorkAreaNumber( int iArea ) +{ + HB_SYMBOL_UNUSED( iArea ); + + return FAILURE; +} + +ERRCODE HB_EXPORT hb_rddPutFieldValue( HB_ITEM_PTR pItem, PHB_SYMB pFieldSymbol ) +{ + HB_SYMBOL_UNUSED( pItem ); + HB_SYMBOL_UNUSED( pFieldSymbol ); + + return FAILURE; +} + +int HB_EXPORT hb_rddGetCurrentWorkAreaNumber( void ) +{ + return 0; +} +#pragma ENDDUMP diff --git a/harbour/source/rdd/rddsys.prg b/harbour/source/rdd/rddsys.prg index f10247f542..3a800f195a 100644 --- a/harbour/source/rdd/rddsys.prg +++ b/harbour/source/rdd/rddsys.prg @@ -50,19 +50,16 @@ * */ -// Standard Harbour RDDSys system +/* Standard Harbour RDDSys system */ ANNOUNCE RDDSYS PROCEDURE RddInit + REQUEST _DBF REQUEST DBFNTX - REQUEST DBFDBT + REQUEST DBFFPT - /* NOTE: Using this internal version of this functions, since at this - point the DBFNTX RDD may not be registered, depending on the - execution order of INIT procedures. */ - - __rddSetDefault( "DBFNTX" ) + rddSetDefault( "DBFNTX" ) return diff --git a/harbour/source/rdd/sdf0.prg b/harbour/source/rdd/sdf0.prg index 8ae5a3ad75..3ba3ab971f 100644 --- a/harbour/source/rdd/sdf0.prg +++ b/harbour/source/rdd/sdf0.prg @@ -52,11 +52,11 @@ #include "rddsys.ch" -ANNOUNCE _SDF +ANNOUNCE SDF init procedure SDFInit - REQUEST _SDFC + REQUEST _SDF rddRegister( "SDF", RDT_TRANSFER ) diff --git a/harbour/source/rdd/sdf1.c b/harbour/source/rdd/sdf1.c index 3f567aaddf..4e3ebc6242 100644 --- a/harbour/source/rdd/sdf1.c +++ b/harbour/source/rdd/sdf1.c @@ -59,20 +59,20 @@ #define __PRG_SOURCE__ __FILE__ -HB_FUNC( _SDFC ); +HB_FUNC( _SDF ); HB_FUNC( SDF_GETFUNCTABLE ); #undef HB_PRG_PCODE_VER #define HB_PRG_PCODE_VER HB_PCODE_VER HB_INIT_SYMBOLS_BEGIN( sdf1__InitSymbols ) -{ "_SDFC", HB_FS_PUBLIC, {HB_FUNCNAME( _SDFC )}, NULL }, +{ "_SDF", HB_FS_PUBLIC, {HB_FUNCNAME( _SDF )}, NULL }, { "SDF_GETFUNCTABLE", HB_FS_PUBLIC, {HB_FUNCNAME( SDF_GETFUNCTABLE )}, NULL } HB_INIT_SYMBOLS_END( sdf1__InitSymbols ) -#if defined(HB_STATIC_STARTUP) +#if defined(HB_PRAGMA_STARTUP) #pragma startup sdf1__InitSymbols -#elif defined(_MSC_VER) +#elif defined(HB_MSC_STARTUP) #if _MSC_VER >= 1010 #pragma data_seg( ".CRT$XIY" ) #pragma comment( linker, "/Merge:.CRT=.data" ) @@ -81,8 +81,6 @@ HB_INIT_SYMBOLS_END( sdf1__InitSymbols ) #endif static HB_$INITSYM hb_vm_auto_sdf1__InitSymbols = sdf1__InitSymbols; #pragma data_seg() -#elif ! defined(__GNUC__) - #pragma startup sdf1__InitSymbols #endif static RDDFUNCS sdfSuper; @@ -118,6 +116,7 @@ static RDDFUNCS sdfTable = { hb_sdfBof, hb_sdfRecCount, hb_sdfRecInfo, hb_sdfRecNo, + hb_sdfRecId, hb_sdfSetFieldExtent, hb_sdfAlias, hb_sdfClose, @@ -164,6 +163,7 @@ static RDDFUNCS sdfTable = { hb_sdfBof, hb_sdfSetLocate, hb_sdfSetScope, hb_sdfSkipScope, + hb_sdfLocate, hb_sdfCompile, hb_sdfError, hb_sdfEvalBlock, @@ -177,9 +177,11 @@ static RDDFUNCS sdfTable = { hb_sdfBof, hb_sdfPutValueFile, hb_sdfReadDBHeader, hb_sdfWriteDBHeader, + hb_sdfInit, hb_sdfExit, hb_sdfDrop, hb_sdfExists, + hb_sdfRddInfo, hb_sdfWhoCares }; @@ -190,9 +192,7 @@ static RDDFUNCS sdfTable = { hb_sdfBof, -HB_FUNC( _SDFC ) -{ -} +HB_FUNC( _SDF ) { ; } HB_FUNC( SDF_GETFUNCTABLE ) { diff --git a/harbour/source/rdd/workarea.c b/harbour/source/rdd/workarea.c index b03be5ea7a..a0fb985741 100644 --- a/harbour/source/rdd/workarea.c +++ b/harbour/source/rdd/workarea.c @@ -163,21 +163,11 @@ ERRCODE hb_waSkipFilter( AREAP pArea, LONG lUpDown ) */ lUpDown = ( lUpDown < 0 ? -1 : 1 ); + /* remember if we are here after SLEF_GOTOP() */ fBottom = pArea->fBottom; + while ( !pArea->fBof && !pArea->fEof ) { - /* SET FILTER TO */ - if( pArea->dbfi.itmCobExpr ) - { - pResult = hb_vmEvalBlock( pArea->dbfi.itmCobExpr ); - if( HB_IS_LOGICAL( pResult ) && !hb_itemGetL( pResult ) ) - { - if ( SELF_SKIPRAW( pArea, lUpDown ) != SUCCESS ) - return FAILURE; - continue; - } - } - /* SET DELETED */ if( hb_set.HB_SET_DELETED ) { @@ -189,6 +179,20 @@ ERRCODE hb_waSkipFilter( AREAP pArea, LONG lUpDown ) continue; } } + + /* SET FILTER TO */ + if( pArea->dbfi.itmCobExpr ) + { + pResult = hb_vmEvalBlock( pArea->dbfi.itmCobExpr ); + if( HB_IS_LOGICAL( pResult ) && !hb_itemGetL( pResult ) ) + { + + if ( SELF_SKIPRAW( pArea, lUpDown ) != SUCCESS ) + return FAILURE; + continue; + } + } + break; } @@ -201,6 +205,15 @@ ERRCODE hb_waSkipFilter( AREAP pArea, LONG lUpDown ) { if ( fBottom ) { + /* GOTO EOF (phantom) record - + this is the only one place where GOTO is used by xHarbour + directly and RDD which does not operate on numbers should + serve this method only as SELF_GOEOF() synonym. If it's a + problem then we can remove this if and always use SELF_GOTOP() + but it also means second table scan if all records filtered + are out of filter so I do not want to do that. I will prefer + explicit add SELF_GOEOF() method + */ uiError = SELF_GOTO( pArea, 0 ); } else @@ -222,24 +235,25 @@ ERRCODE hb_waSkipFilter( AREAP pArea, LONG lUpDown ) */ ERRCODE hb_waAddField( AREAP pArea, LPDBFIELDINFO pFieldInfo ) { - ULONG ulSize; LPFIELD pField; + char szFieldName[ HB_SYMBOL_NAME_LEN + 1 ], *szPtr; HB_TRACE(HB_TR_DEBUG, ("hb_waAddField(%p, %p)", pArea, pFieldInfo)); /* Validate the name of field */ - ulSize = strlen( ( char * ) pFieldInfo->atomName ); - hb_strLTrim( ( char * ) pFieldInfo->atomName, &ulSize ); - ulSize = hb_strRTrimLen( ( char * ) pFieldInfo->atomName, ulSize, TRUE ); - if( !ulSize ) + szPtr = ( char * ) pFieldInfo->atomName; + while( HB_ISSPACE( *szPtr ) ) + { + ++szPtr; + } + hb_strncpyUpperTrim( szFieldName, szPtr, HB_SYMBOL_NAME_LEN ); + if( strlen( szFieldName ) == 0 ) return FAILURE; - /* This line writes to the protected memory - pFieldInfo->atomName[ulSize] = '\0'; */ pField = pArea->lpFields + pArea->uiFieldCount; if( pArea->uiFieldCount > 0 ) ( ( LPFIELD ) ( pField - 1 ) )->lpfNext = pField; - pField->sym = ( void * ) hb_dynsymGet( ( char * ) pFieldInfo->atomName ); + pField->sym = ( void * ) hb_dynsymGetCase( szFieldName ); pField->uiType = pFieldInfo->uiType; pField->uiTypeExtended = pFieldInfo->uiTypeExtended; pField->uiLen = pFieldInfo->uiLen; @@ -264,9 +278,9 @@ ERRCODE hb_waCreateFields( AREAP pArea, PHB_ITEM pStruct ) uiItems = ( USHORT ) hb_arrayLen( pStruct ); SELF_SETFIELDEXTENT( pArea, uiItems ); - pFieldInfo.uiTypeExtended = 0; for( uiCount = 0; uiCount < uiItems; uiCount++ ) { + pFieldInfo.uiTypeExtended = 0; pFieldDesc = hb_arrayGetItemPtr( pStruct, uiCount + 1 ); pFieldInfo.atomName = ( BYTE * ) hb_arrayGetCPtr( pFieldDesc, 1 ); iData = hb_arrayGetNI( pFieldDesc, 3 ); @@ -283,11 +297,15 @@ ERRCODE hb_waCreateFields( AREAP pArea, PHB_ITEM pStruct ) { case 'C': pFieldInfo.uiType = HB_IT_STRING; + pFieldInfo.uiLen = uiLen; +/* Too many people reported the behavior with code below as a + Clipper compatibility bug so I commented this code. Druzus. #ifdef HB_C52_STRICT pFieldInfo.uiLen = uiLen; #else pFieldInfo.uiLen = uiLen + uiDec * 256; #endif +*/ break; case 'L': @@ -297,12 +315,17 @@ ERRCODE hb_waCreateFields( AREAP pArea, PHB_ITEM pStruct ) case 'M': pFieldInfo.uiType = HB_IT_MEMO; - pFieldInfo.uiLen = (uiLen == 4) ? 4 : 10; + pFieldInfo.uiLen = ( uiLen == 4 ) ? 4 : 10; + break; + + case 'V': + pFieldInfo.uiType = HB_IT_ANY; + pFieldInfo.uiLen = ( uiLen < 3 || uiLen == 5 ) ? 6 : uiLen; break; case 'D': pFieldInfo.uiType = HB_IT_DATE; - pFieldInfo.uiLen = ( uiLen == 3 ) ? 3 : 8; + pFieldInfo.uiLen = ( uiLen == 3 || uiLen == 4 ) ? uiLen : 8; break; case 'I': @@ -394,6 +417,10 @@ ERRCODE hb_waFieldInfo( AREAP pArea, USHORT uiIndex, USHORT uiType, PHB_ITEM pIt hb_itemPutC( pItem, "M" ); break; + case HB_IT_ANY: + hb_itemPutC( pItem, "V" ); + break; + case HB_IT_DATE: hb_itemPutC( pItem, "D" ); break; @@ -547,7 +574,9 @@ ERRCODE hb_waClose( AREAP pArea ) hb_rddIterateWorkAreas ( hb_waCloseAux, pArea->uiArea ); } - ( ( PHB_DYNS ) pArea->atomAlias )->hArea = 0; + if( pArea->atomAlias ) + ( ( PHB_DYNS ) pArea->atomAlias )->hArea = 0; + return SUCCESS; } @@ -566,6 +595,15 @@ ERRCODE hb_waInfo( AREAP pArea, USHORT uiIndex, PHB_ITEM pItem ) hb_itemPutL( pItem, FALSE ); break; + /* + * IMHO better to return FAILURE to notice that it's not supported + */ + case DBI_GETDELIMITER: + case DBI_SETDELIMITER: + case DBI_SEPARATOR: + hb_itemPutC( pItem, "" ); + return FAILURE; + case DBI_CHILDCOUNT: { LPDBRELINFO lpdbRelations = pArea->lpdbRelations; @@ -599,7 +637,7 @@ ERRCODE hb_waInfo( AREAP pArea, USHORT uiIndex, PHB_ITEM pItem ) break; case DBI_FCOUNT: - hb_itemPutL( pItem, pArea->uiFieldCount ); + hb_itemPutNI( pItem, pArea->uiFieldCount ); break; case DBI_ALIAS: @@ -613,6 +651,18 @@ ERRCODE hb_waInfo( AREAP pArea, USHORT uiIndex, PHB_ITEM pItem ) break; } + case DBI_RM_SUPPORTED: + hb_itemPutL( pItem, FALSE ); + break; + + case DBI_DB_VERSION: + hb_itemPutC( pItem, "" ); + break; + + case DBI_RDD_VERSION: + hb_itemPutC( pItem, "" ); + break; + default: return FAILURE; } @@ -627,11 +677,11 @@ ERRCODE hb_waInfo( AREAP pArea, USHORT uiIndex, PHB_ITEM pItem ) ERRCODE hb_waOrderInfo( AREAP pArea, USHORT index, LPDBORDERINFO param ) { HB_TRACE(HB_TR_DEBUG, ("hb_waOrderInfo(%p, %hu, %p)", pArea, index, param)); + HB_SYMBOL_UNUSED( pArea ); HB_SYMBOL_UNUSED( index ); + HB_SYMBOL_UNUSED( param ); - if ( param->itmResult ) - hb_itemRelease( param->itmResult ); hb_errRT_DBCMD( EG_ARG, EDBCMD_BADPARAMETER, NULL, "ORDERINFO" ); return FAILURE; } @@ -652,6 +702,25 @@ ERRCODE hb_waNewArea( AREAP pArea ) return SUCCESS; } +/* + * Open a data store in the WorkArea. + * Like in Clipper it's also mapped as Create() method at WA level + */ +ERRCODE hb_waOpen( AREAP pArea, LPDBOPENINFO pInfo ) +{ + if( !pArea->atomAlias && pInfo->atomAlias && pInfo->atomAlias[ 0 ] ) + { + pArea->atomAlias = hb_rddAllocWorkAreaAlias( ( char * ) pInfo->atomAlias, + ( int ) pInfo->uiArea ); + if( ! pArea->atomAlias ) + { + SELF_CLOSE( ( AREAP ) pArea ); + return FAILURE; + } + } + return SUCCESS; +} + ERRCODE hb_waOrderCondition( AREAP pArea, LPDBORDERCONDINFO param ) { if( pArea->lpdbOrdCondInfo ) @@ -672,6 +741,14 @@ ERRCODE hb_waOrderCondition( AREAP pArea, LPDBORDERCONDINFO param ) { hb_itemRelease( pArea->lpdbOrdCondInfo->itmCobEval ); } + if( pArea->lpdbOrdCondInfo->itmStartRecID ) + { + hb_itemRelease( pArea->lpdbOrdCondInfo->itmStartRecID ); + } + if( pArea->lpdbOrdCondInfo->itmRecID ) + { + hb_itemRelease( pArea->lpdbOrdCondInfo->itmRecID ); + } hb_xfree( pArea->lpdbOrdCondInfo ); } pArea->lpdbOrdCondInfo = param; @@ -692,6 +769,7 @@ ERRCODE hb_waRelease( AREAP pArea ) if( pArea->valResult ) hb_itemRelease( pArea->valResult ); if( pArea->lpdbOrdCondInfo ) + /* intentionally direct call not a method */ hb_waOrderCondition( pArea,NULL ); hb_xfree( pArea ); return SUCCESS; @@ -726,62 +804,123 @@ ERRCODE hb_waSysName( AREAP pArea, BYTE * pBuffer ) */ ERRCODE hb_waEval( AREAP pArea, LPDBEVALINFO pEvalInfo ) { - BOOL bFor, bWhile; - LONG lNext; + LONG lNext = 1; + BOOL fEof; HB_TRACE(HB_TR_DEBUG, ("hb_waEval(%p, %p)", pArea, pEvalInfo)); - lNext = 0; if( pEvalInfo->dbsci.itmRecID ) { - SELF_GOTO( pArea, hb_itemGetNL( pEvalInfo->dbsci.itmRecID ) ); - if( !pArea->fEof ) - { - if( pEvalInfo->dbsci.itmCobWhile ) - bWhile = hb_itemGetL( hb_vmEvalBlock( pEvalInfo->dbsci.itmCobWhile ) ); - else - bWhile = TRUE; - - if( pEvalInfo->dbsci.itmCobFor ) - bFor = hb_itemGetL( hb_vmEvalBlock( pEvalInfo->dbsci.itmCobFor ) ); - else - bFor = TRUE; - - if( bWhile && bFor ) - hb_vmEvalBlock( pEvalInfo->itmBlock ); - } - return SUCCESS; + if( SELF_GOTOID( pArea, pEvalInfo->dbsci.itmRecID ) == FAILURE ) + return FAILURE; + } + else if( pEvalInfo->dbsci.lNext ) + { + lNext = hb_itemGetNL( pEvalInfo->dbsci.lNext ); + } + else if( !pEvalInfo->dbsci.itmCobWhile && + !hb_itemGetL( pEvalInfo->dbsci.fRest ) ) + { + if( SELF_GOTOP( pArea ) == FAILURE ) + return FAILURE; } - if( !pEvalInfo->dbsci.itmCobWhile && - (!pEvalInfo->dbsci.fRest || !hb_itemGetL( pEvalInfo->dbsci.fRest ) ) && - !pEvalInfo->dbsci.lNext ) - SELF_GOTOP( pArea ); - - if( pEvalInfo->dbsci.lNext ) - lNext = hb_itemGetNL( pEvalInfo->dbsci.lNext ); + /* TODO: use SKIPSCOPE() method and fRest parameter */ if( !pEvalInfo->dbsci.lNext || lNext > 0 ) { - bFor = TRUE; - while( !pArea->fEof ) + while( TRUE ) { - if( pEvalInfo->dbsci.itmCobWhile ) - { - if ( ! hb_itemGetL( hb_vmEvalBlock( pEvalInfo->dbsci.itmCobWhile ) ) ) - break; - } + if( SELF_EOF( pArea, &fEof ) == FAILURE ) + return FAILURE; - if( pEvalInfo->dbsci.itmCobFor ) - bFor = hb_itemGetL( hb_vmEvalBlock( pEvalInfo->dbsci.itmCobFor ) ); - - if( bFor ) - hb_vmEvalBlock( pEvalInfo->itmBlock ); - - if( pEvalInfo->dbsci.lNext && --lNext < 1 ) + if( fEof ) break; - SELF_SKIP( pArea, 1 ); + if( pEvalInfo->dbsci.itmCobWhile && + ! hb_itemGetL( hb_vmEvalBlock( pEvalInfo->dbsci.itmCobWhile ) ) ) + break; + + if( ! pEvalInfo->dbsci.itmCobFor || + hb_itemGetL( hb_vmEvalBlock( pEvalInfo->dbsci.itmCobFor ) ) ) + hb_vmEvalBlock( pEvalInfo->itmBlock ); + + if( pEvalInfo->dbsci.itmRecID || ( pEvalInfo->dbsci.lNext && --lNext < 1 ) ) + break; + + if( SELF_SKIP( pArea, 1 ) == FAILURE ) + return FAILURE; + } + } + + return SUCCESS; +} + +/* + * Locate a record which pass given condition + */ +ERRCODE hb_waLocate( AREAP pArea, BOOL fContinue ) +{ + LONG lNext = 1; + BOOL fEof; + + HB_TRACE(HB_TR_DEBUG, ("hb_waLocate(%p, %d)", pArea, fContinue)); + + if( fContinue ) + { + if( ! pArea->dbsi.itmCobFor ) + return SUCCESS; + + if ( SELF_SKIP( pArea, 1 ) == FAILURE ) + return FAILURE; + } + else if( pArea->dbsi.itmRecID ) + { + if( SELF_GOTOID( pArea, pArea->dbsi.itmRecID ) == FAILURE ) + return FAILURE; + } + else if( pArea->dbsi.lNext ) + { + lNext = hb_itemGetNL( pArea->dbsi.lNext ); + } + else if( !pArea->dbsi.itmCobWhile && + !hb_itemGetL( pArea->dbsi.fRest ) ) + { + if( SELF_GOTOP( pArea ) == FAILURE ) + return FAILURE; + } + + pArea->fFound = FALSE; + + /* TODO: use SKIPSCOPE() method and fRest parameter */ + + if( !pArea->dbsi.lNext || lNext > 0 ) + { + while( TRUE ) + { + if( SELF_EOF( pArea, &fEof ) == FAILURE ) + return FAILURE; + + if( fEof ) + break; + + if( !fContinue && pArea->dbsi.itmCobWhile && + ! hb_itemGetL( hb_vmEvalBlock( pArea->dbsi.itmCobWhile ) ) ) + break; + + if( ! pArea->dbsi.itmCobFor || + hb_itemGetL( hb_vmEvalBlock( pArea->dbsi.itmCobFor ) ) ) + { + pArea->fFound = TRUE; + break; + } + + if( !fContinue && + ( pArea->dbsi.itmRecID || ( pArea->dbsi.lNext && --lNext < 1 ) ) ) + break; + + if( SELF_SKIP( pArea, 1 ) == FAILURE ) + return FAILURE; } } @@ -793,11 +932,58 @@ ERRCODE hb_waEval( AREAP pArea, LPDBEVALINFO pEvalInfo ) */ ERRCODE hb_waTrans( AREAP pArea, LPDBTRANSINFO pTransInfo ) { - HB_TRACE(HB_TR_DEBUG, ("hb_waTrans(%p, %p)", pArea, pTransInfo)); - HB_SYMBOL_UNUSED( pArea ); - HB_SYMBOL_UNUSED( pTransInfo ); + LONG lNext = 1; + BOOL fEof; + + HB_TRACE(HB_TR_DEBUG, ("hb_waTrans(%p, %p)", pArea, pTransInfo)); + + if( pTransInfo->dbsci.itmRecID ) + { + if( SELF_GOTOID( pArea, pTransInfo->dbsci.itmRecID ) == FAILURE ) + return FAILURE; + } + else if( pTransInfo->dbsci.lNext ) + { + lNext = hb_itemGetNL( pTransInfo->dbsci.lNext ); + } + else if( !pTransInfo->dbsci.itmCobWhile && + !hb_itemGetL( pTransInfo->dbsci.fRest ) ) + { + if( SELF_GOTOP( pArea ) == FAILURE ) + return FAILURE; + } + + /* TODO: use SKIPSCOPE() method and fRest parameter */ + + if( !pTransInfo->dbsci.lNext || lNext > 0 ) + { + while( TRUE ) + { + if( SELF_EOF( pArea, &fEof ) == FAILURE ) + return FAILURE; + + if( fEof ) + break; + + if( pTransInfo->dbsci.itmCobWhile && + ! hb_itemGetL( hb_vmEvalBlock( pTransInfo->dbsci.itmCobWhile ) ) ) + break; + + if( ! pTransInfo->dbsci.itmCobFor || + hb_itemGetL( hb_vmEvalBlock( pTransInfo->dbsci.itmCobFor ) ) ) + { + if( SELF_TRANSREC( pArea, pTransInfo ) == FAILURE ) + return FAILURE; + } + + if( pTransInfo->dbsci.itmRecID || ( pTransInfo->dbsci.lNext && --lNext < 1 ) ) + break; + + if( SELF_SKIP( pArea, 1 ) == FAILURE ) + return FAILURE; + } + } - printf( "\nTODO: hb_waTrans()\n" ); return SUCCESS; } @@ -806,11 +992,69 @@ ERRCODE hb_waTrans( AREAP pArea, LPDBTRANSINFO pTransInfo ) */ ERRCODE hb_waTransRec( AREAP pArea, LPDBTRANSINFO pTransInfo ) { - HB_TRACE(HB_TR_DEBUG, ("hb_waTransRec(%p, %p)", pArea, pTransInfo)); - HB_SYMBOL_UNUSED( pArea ); - HB_SYMBOL_UNUSED( pTransInfo ); + BOOL bDeleted; + BYTE *pRecord; + ERRCODE errCode; + + HB_TRACE(HB_TR_DEBUG, ("hb_waTransRec(%p, %p)", pArea, pTransInfo)); + + /* Record deleted? */ + errCode = SELF_DELETED( ( AREAP ) pArea, &bDeleted ); + if( errCode != SUCCESS ) + return errCode; + + if( pTransInfo->uiFlags & DBTF_MATCH && pTransInfo->uiFlags & DBTF_PUTREC ) + { + errCode = SELF_GETREC( ( AREAP ) pArea, &pRecord ); + if( errCode != SUCCESS ) + return errCode; + + /* Append a new record */ + errCode = SELF_APPEND( ( AREAP ) pTransInfo->lpaDest, TRUE ); + if( errCode != SUCCESS ) + return errCode; + + /* Copy record */ + errCode = SELF_PUTREC( ( AREAP ) pTransInfo->lpaDest, pRecord ); + } + else + { + PHB_ITEM pItem = hb_itemNew( NULL ); + LPDBTRANSITEM pTransItem; + USHORT uiCount = 0; + + /* Append a new record */ + errCode = SELF_APPEND( ( AREAP ) pTransInfo->lpaDest, TRUE ); + if( errCode != SUCCESS ) + return errCode; + + pTransItem = pTransInfo->lpTransItems; + for( uiCount = pTransInfo->uiItemCount; uiCount; --uiCount ) + { + errCode = SELF_GETVALUE( ( AREAP ) pArea, + pTransItem->uiSource, pItem ); + if( errCode != SUCCESS ) + break; + errCode = SELF_PUTVALUE( ( AREAP ) pTransInfo->lpaDest, + pTransItem->uiDest, pItem ); + if( errCode != SUCCESS ) + break; + ++pTransItem; + } + hb_itemRelease( pItem ); + } + + /* Delete the new record if copy fail */ + if( errCode != SUCCESS ) + { + SELF_DELETE( ( AREAP ) pTransInfo->lpaDest ); + return errCode; + } + + /* Delete the new record */ + if( bDeleted ) + return SELF_DELETE( ( AREAP ) pTransInfo->lpaDest ); - printf( "\nTODO: hb_waTransRec()\n" ); return SUCCESS; } @@ -821,8 +1065,17 @@ ERRCODE hb_waChildEnd( AREAP pArea, LPDBRELINFO pRelInfo ) { HB_TRACE(HB_TR_DEBUG, ("hb_waChildEnd(%p, %p)", pArea, pRelInfo)); - if ( pRelInfo->isScoped ) - SELF_CLEARSCOPE( pArea ); + if( pRelInfo->isScoped ) + { + DBORDERINFO pInfo; + pInfo.itmOrder = NULL; + pInfo.atomBagName = NULL; + pInfo.itmResult = hb_itemNew( NULL ); + pInfo.itmNewVal = NULL; + SELF_ORDINFO( pArea, DBOI_SCOPETOPCLEAR, &pInfo ); + SELF_ORDINFO( pArea, DBOI_SCOPEBOTTOMCLEAR, &pInfo ); + hb_itemRelease( pInfo.itmResult ); + } pArea->uiParents--; return SUCCESS; @@ -864,33 +1117,35 @@ ERRCODE hb_waSyncChildren( AREAP pArea ) */ ERRCODE hb_waClearRel( AREAP pArea ) { - LPDBRELINFO lpdbRelation, lpdbRelPrev; - int iCurrArea; - HB_TRACE(HB_TR_DEBUG, ("hb_waClearRel(%p)", pArea )); - iCurrArea = hb_rddGetCurrentWorkAreaNumber(); - /* Free all relations */ - lpdbRelation = pArea->lpdbRelations; - while( lpdbRelation ) + if( pArea->lpdbRelations ) { - hb_rddSelectWorkAreaNumber( lpdbRelation->lpaChild->uiArea ); - SELF_CHILDEND( lpdbRelation->lpaChild, lpdbRelation ); - hb_rddSelectWorkAreaNumber( iCurrArea ); + int iCurrArea = hb_rddGetCurrentWorkAreaNumber(); - if( lpdbRelation->itmCobExpr ) + do { - hb_itemRelease( lpdbRelation->itmCobExpr ); - } - if( lpdbRelation->abKey ) - hb_itemRelease( lpdbRelation->abKey ); + LPDBRELINFO lpdbRelation = pArea->lpdbRelations; - lpdbRelPrev = lpdbRelation; - lpdbRelation = lpdbRelation->lpdbriNext; - hb_xfree( lpdbRelPrev ); + hb_rddSelectWorkAreaNumber( lpdbRelation->lpaChild->uiArea ); + SELF_CHILDEND( lpdbRelation->lpaChild, lpdbRelation ); + pArea->lpdbRelations = lpdbRelation->lpdbriNext; + + if( lpdbRelation->itmCobExpr ) + { + hb_itemRelease( lpdbRelation->itmCobExpr ); + } + if( lpdbRelation->abKey ) + { + hb_itemRelease( lpdbRelation->abKey ); + } + hb_xfree( lpdbRelation ); + } + while( pArea->lpdbRelations ); + + hb_rddSelectWorkAreaNumber( iCurrArea ); } - pArea->lpdbRelations = NULL; return SUCCESS; } @@ -926,58 +1181,62 @@ ERRCODE hb_waRelArea( AREAP pArea, USHORT uiRelNo, void * pRelArea ) */ ERRCODE hb_waRelEval( AREAP pArea, LPDBRELINFO pRelInfo ) { - int iCurrArea; PHB_ITEM pResult; DBORDERINFO pInfo; + ERRCODE errCode; int iOrder; HB_TRACE(HB_TR_DEBUG, ("hb_waRelEval(%p, %p)", pArea, pRelInfo)); - iCurrArea = hb_rddGetCurrentWorkAreaNumber(); - hb_rddSelectWorkAreaNumber( pRelInfo->lpaParent->uiArea ); - pResult = hb_vmEvalBlock( pRelInfo->itmCobExpr ); - hb_rddSelectWorkAreaNumber( iCurrArea ); + errCode = SELF_EVALBLOCK( pRelInfo->lpaParent, pRelInfo->itmCobExpr ); - /* - * Check the current order - */ - - pInfo.itmResult = hb_itemPutNI( NULL, 0 ); - pInfo.itmOrder = NULL; - SELF_ORDINFO( pArea, DBOI_NUMBER, &pInfo ); - iOrder = hb_itemGetNI( pInfo.itmResult ); - hb_itemRelease( pInfo.itmResult ); - - if( iOrder != 0 ) - { - if ( pRelInfo->isScoped ) - { - DBORDSCOPEINFO sInfo; - - sInfo.scopeValue = pResult; - sInfo.nScope = 0; - if ( SELF_SETSCOPE( pArea, (LPDBORDSCOPEINFO) &sInfo ) == FAILURE ) - return FAILURE; - sInfo.nScope = 1; - if ( SELF_SETSCOPE( pArea, (LPDBORDSCOPEINFO) &sInfo ) == FAILURE ) - return FAILURE; - } - if( SELF_SEEK( pArea, 0, pResult, 0 ) == SUCCESS ) - return SUCCESS; - else - return FAILURE; - } - else + if( errCode == SUCCESS ) { /* - * If current order equals to zero, use GOTO instead of SEEK - */ + * Check the current order + */ + pResult = pRelInfo->lpaParent->valResult; + pRelInfo->lpaParent->valResult = NULL; + memset( &pInfo, 0, sizeof( DBORDERINFO ) ); + pInfo.itmResult = hb_itemPutNI( NULL, 0 ); + errCode = SELF_ORDINFO( pArea, DBOI_NUMBER, &pInfo ); - if( SELF_GOTO( pArea, hb_itemGetNI( pResult ) ) == SUCCESS ) - return SUCCESS; - else - return FAILURE; + if( errCode == SUCCESS ) + { + iOrder = hb_itemGetNI( pInfo.itmResult ); + if( iOrder != 0 ) + { + if( pRelInfo->isScoped ) + { + pInfo.itmNewVal = pResult; + errCode = SELF_ORDINFO( pArea, DBOI_SCOPETOP, &pInfo ); + if( errCode == SUCCESS ) + errCode = SELF_ORDINFO( pArea, DBOI_SCOPEBOTTOM, &pInfo ); + } + if( errCode == SUCCESS ) + errCode = SELF_SEEK( pArea, FALSE, pResult, FALSE ); + } + else + { + /* + * If current order equals to zero, use GOTOID instead of SEEK + * Unfortunately it interacts with buggy .prg code which returns + * non numerical values from relation expression and RDD accepts + * only numerical record ID. In such case SELF_GOTO() works like + * SELF_GOEOF() but SELF_GOTOID() reports error. So for Clipper + * compatibility SELF_GOTO() is used here but if RDD can use + * non numerical record IDs then this method should be overloaded + * to use SELF_GOTOID(), [druzus] + */ + /* errCode = SELF_GOTOID( pArea, pResult ); */ + errCode = SELF_GOTO( pArea, hb_itemGetNL( pResult ) ); + } + } + hb_itemRelease( pInfo.itmResult ); + hb_itemRelease( pResult ); } + + return errCode; } /* @@ -987,24 +1246,23 @@ ERRCODE hb_waRelText( AREAP pArea, USHORT uiRelNo, void * pExpr ) { LPDBRELINFO lpdbRelations; USHORT uiIndex = 1; - char* pBuf = (char*) pExpr; /*TODO: Why is the string buffer declared as void*? This creates casting hassles.*/ HB_TRACE(HB_TR_DEBUG, ("hb_waRelText(%p, %hu, %p)", pArea, uiRelNo, pExpr)); - *pBuf = 0; lpdbRelations = pArea->lpdbRelations; while( lpdbRelations ) { if ( uiIndex++ == uiRelNo ) { - strcpy(pBuf, lpdbRelations->abKey->item.asString.value ); - break; - /* TODO: Verify buffer size is big enough ?? */ + hb_strncpy( ( char* ) pExpr, hb_itemGetCPtr( lpdbRelations->abKey ), + HARBOUR_MAX_RDD_RELTEXT_LENGTH ); + return SUCCESS; } lpdbRelations = lpdbRelations->lpdbriNext; } - return *pBuf ? SUCCESS : FAILURE ; + * ( char * ) pExpr = 0; + return FAILURE; } /* @@ -1033,6 +1291,7 @@ ERRCODE hb_waSetRel( AREAP pArea, LPDBRELINFO lpdbRelInf ) lpdbRelations->lpaChild = lpdbRelInf->lpaChild; lpdbRelations->itmCobExpr = lpdbRelInf->itmCobExpr; lpdbRelations->isScoped = lpdbRelInf->isScoped; + lpdbRelations->isOptimized = lpdbRelInf->isOptimized; lpdbRelations->abKey = lpdbRelInf->abKey; lpdbRelations->lpdbriNext = lpdbRelInf->lpdbriNext; @@ -1142,6 +1401,7 @@ ERRCODE hb_waSetFilter( AREAP pArea, LPDBFILTERINFO pFilterInfo ) { pArea->dbfi.abFilterText = hb_itemNew( pFilterInfo->abFilterText ); } + pArea->dbfi.fOptimized = pArea->dbfi.fOptimized; pArea->dbfi.fFilter = TRUE; return SUCCESS; @@ -1158,17 +1418,13 @@ ERRCODE hb_waSetLocate( AREAP pArea, LPDBSCOPEINFO pScopeInfo ) SELF_CLEARLOCATE( pArea ); if( pScopeInfo->itmCobFor ) - { pArea->dbsi.itmCobFor = hb_itemNew( pScopeInfo->itmCobFor ); - } if( pScopeInfo->lpstrFor ) pArea->dbsi.lpstrFor = hb_itemNew( pScopeInfo->lpstrFor ); if( pScopeInfo->itmCobWhile ) - { pArea->dbsi.itmCobWhile = hb_itemNew( pScopeInfo->itmCobWhile ); - } if( pScopeInfo->lpstrWhile ) pArea->dbsi.lpstrWhile = hb_itemNew( pScopeInfo->lpstrWhile ); @@ -1182,6 +1438,13 @@ ERRCODE hb_waSetLocate( AREAP pArea, LPDBSCOPEINFO pScopeInfo ) if( pScopeInfo->fRest ) pArea->dbsi.fRest = hb_itemNew( pScopeInfo->fRest ); + pArea->dbsi.fIgnoreFilter = pScopeInfo->fIgnoreFilter; + pArea->dbsi.fIncludeDeleted = pScopeInfo->fIncludeDeleted; + pArea->dbsi.fLast = pScopeInfo->fLast; + pArea->dbsi.fIgnoreDuplicates = pScopeInfo->fIgnoreDuplicates; + pArea->dbsi.fBackword = pScopeInfo->fBackword; + pArea->dbsi.fOptimized = pScopeInfo->fOptimized; + return SUCCESS; } @@ -1197,9 +1460,6 @@ ERRCODE hb_waCompile( AREAP pArea, BYTE * pExpr ) pMacro = hb_macroCompile( ( char * ) pExpr ); if( pMacro ) { - if( ! pArea->valResult ) - pArea->valResult = hb_itemNew( NULL ); - pArea->valResult = hb_itemPutPtr( pArea->valResult, ( void * ) pMacro ); return SUCCESS; } @@ -1217,7 +1477,7 @@ ERRCODE hb_waError( AREAP pArea, PHB_ITEM pError ) HB_TRACE(HB_TR_DEBUG, ("hb_waError(%p, %p)", pArea, pError)); szRddName = ( char * ) hb_xgrab( HARBOUR_MAX_RDD_DRIVERNAME_LENGTH + 1 ); - if( ( pArea )->lprfsHost->sysName ) + if( pArea && pArea->lprfsHost->sysName ) SELF_SYSNAME( pArea, ( BYTE * ) szRddName ); else strcpy( szRddName, "???DRIVER" ); @@ -1232,23 +1492,145 @@ ERRCODE hb_waError( AREAP pArea, PHB_ITEM pError ) */ ERRCODE hb_waEvalBlock( AREAP pArea, PHB_ITEM pBlock ) { + PHB_ITEM pItem; int iCurrArea; HB_TRACE(HB_TR_DEBUG, ("hb_waEvalBlock(%p, %p)", pArea, pBlock)); - if( ! pArea->valResult ) - pArea->valResult = hb_itemNew( NULL ); - iCurrArea = hb_rddGetCurrentWorkAreaNumber(); if ( iCurrArea != pArea->uiArea ) hb_rddSelectWorkAreaNumber( pArea->uiArea ); else iCurrArea = 0; - hb_itemCopy( pArea->valResult, hb_vmEvalBlock( pBlock ) ); + pItem = hb_vmEvalBlockOrMacro( pBlock ); + if( ! pArea->valResult ) + pArea->valResult = hb_itemNew( NULL ); + hb_itemCopy( pArea->valResult, pItem ); if ( iCurrArea ) hb_rddSelectWorkAreaNumber( iCurrArea ); + return hb_vmRequestQuery() ? FAILURE : SUCCESS; +} + +/* + * RDD info + */ +extern ERRCODE hb_rddInfo( LPRDDNODE pRDD, USHORT uiIndex, ULONG ulConnection, PHB_ITEM pItem ) +{ + BOOL fResult; + int iResult; + + HB_TRACE(HB_TR_DEBUG, ("hb_rddInfo(%p, %hu, %lu, %p)", pRDD, uiIndex, ulConnection, pItem)); + + HB_SYMBOL_UNUSED( pRDD ); + HB_SYMBOL_UNUSED( ulConnection ); + + switch( uiIndex ) + { + case RDDI_ISDBF: + case RDDI_CANPUTREC: + case RDDI_LOCAL: + case RDDI_REMOTE: + case RDDI_RECORDMAP: + case RDDI_ENCRYPTION: + case RDDI_TRIGGERS: + case RDDI_AUTOLOCK: + case RDDI_STRUCTORD: + case RDDI_LARGEFILE: + case RDDI_MULTITAG: + case RDDI_SORTRECNO: + case RDDI_MULTIKEY: + hb_itemPutL( pItem, FALSE ); + break; + + case RDDI_CONNECTION: + case RDDI_TABLETYPE: + case RDDI_MEMOTYPE: + case RDDI_MEMOVERSION: + hb_itemPutNI( pItem, 0 ); + break; + + case RDDI_STRICTREAD: + fResult = hb_set.HB_SET_STRICTREAD; + if( hb_itemType( pItem ) == HB_IT_LOGICAL ) + hb_set.HB_SET_STRICTREAD = hb_itemGetL( pItem ); + hb_itemPutL( pItem, fResult ); + break; + case RDDI_OPTIMIZE: + fResult = hb_set.HB_SET_OPTIMIZE; + if( hb_itemType( pItem ) == HB_IT_LOGICAL ) + hb_set.HB_SET_OPTIMIZE = hb_itemGetL( pItem ); + hb_itemPutL( pItem, fResult ); + break; + case RDDI_FORCEOPT: + fResult = hb_set.HB_SET_FORCEOPT; + if( hb_itemType( pItem ) == HB_IT_LOGICAL ) + hb_set.HB_SET_FORCEOPT = hb_itemGetL( pItem ); + hb_itemPutL( pItem, fResult ); + break; + case RDDI_AUTOOPEN: + fResult = hb_set.HB_SET_AUTOPEN; + if( hb_itemType( pItem ) == HB_IT_LOGICAL ) + hb_set.HB_SET_AUTOPEN = hb_itemGetL( pItem ); + hb_itemPutL( pItem, fResult ); + break; + case RDDI_AUTOORDER: + fResult = hb_set.HB_SET_AUTORDER; + if( hb_itemType( pItem ) == HB_IT_LOGICAL ) + hb_set.HB_SET_AUTORDER = hb_itemGetL( pItem ); + hb_itemPutL( pItem, fResult ); + break; + case RDDI_AUTOSHARE: + fResult = hb_set.HB_SET_AUTOSHARE; + if( hb_itemType( pItem ) == HB_IT_LOGICAL ) + hb_set.HB_SET_AUTOSHARE = hb_itemGetL( pItem ); + hb_itemPutL( pItem, fResult ); + break; + case RDDI_LOCKSCHEME: + iResult = hb_set.HB_SET_DBFLOCKSCHEME; + if( hb_itemType( pItem ) & HB_IT_NUMERIC ) + hb_set.HB_SET_DBFLOCKSCHEME = hb_itemGetNI( pItem ); + hb_itemPutNI( pItem, iResult ); + break; + case RDDI_MEMOBLOCKSIZE: + iResult = hb_set.HB_SET_MBLOCKSIZE; + if( hb_itemType( pItem ) & HB_IT_NUMERIC ) + hb_set.HB_SET_MBLOCKSIZE = hb_itemGetNI( pItem ); + hb_itemPutNI( pItem, iResult ); + break; + case RDDI_MEMOEXT: + if( hb_itemType( pItem ) & HB_IT_STRING ) + { + if( hb_set.HB_SET_MFILEEXT ) + { + hb_itemPutC( pItem, hb_set.HB_SET_MFILEEXT ); + hb_xfree( hb_set.HB_SET_MFILEEXT ); + } + else + { + hb_itemPutC( pItem, "" ); + } + hb_set.HB_SET_MFILEEXT = hb_strdup( hb_itemGetCPtr( pItem ) ); + break; + } + else if( hb_set.HB_SET_MFILEEXT ) + { + hb_itemPutC( pItem, hb_set.HB_SET_MFILEEXT ); + break; + } + case RDDI_TABLEEXT: + case RDDI_ORDBAGEXT: + case RDDI_ORDEREXT: + case RDDI_ORDSTRUCTEXT: + case RDDI_DELIMITER: + case RDDI_SEPARATOR: + hb_itemPutC( pItem, "" ); + /* no break - return FAILURE */ + + default: + return FAILURE; + } return SUCCESS; } diff --git a/harbour/source/rtl/errorapi.c b/harbour/source/rtl/errorapi.c index 71a0ac5b43..e6ec222e6f 100644 --- a/harbour/source/rtl/errorapi.c +++ b/harbour/source/rtl/errorapi.c @@ -725,6 +725,36 @@ PHB_ITEM hb_errRT_New_Subst( return pError; } +PHB_ITEM hb_errRT_SubstParams( char *szSubSystem, ULONG ulGenCode, ULONG ulSubCode, char * szDescription, char * szOperation ) +{ + PHB_ITEM pRetVal; + PHB_ITEM pError; + PHB_ITEM pArray; + + HB_TRACE_STEALTH( HB_TR_DEBUG, ( "hb_errRT_SubstParams()") ); + + pError = hb_errRT_New_Subst( ES_ERROR, szSubSystem ? szSubSystem : HB_ERR_SS_BASE, + ulGenCode, ulSubCode, szDescription, szOperation, 0, EF_NONE ); + + pArray = hb_arrayFromParams( hb_stack.pBase ); + + /* Assign the new array to the object data item. */ + hb_vmPushSymbol( hb_dynsymGet( "_ARGS" )->pSymbol ); + hb_vmPush( pError ); + hb_vmPush( pArray ); + hb_vmSend( 1 ); + + hb_itemRelease( pArray ); + + /* Ok, launch... */ + pRetVal = hb_errLaunchSubst( pError ); + + hb_itemRelease( pError ); + + return pRetVal; +} + + HB_FUNC( __ERRRT_BASE ) { hb_errRT_BASE( ( ULONG ) hb_parnl( 1 ), @@ -983,6 +1013,20 @@ USHORT hb_errRT_DBCMD( ULONG ulGenCode, ULONG ulSubCode, char * szDescription, c return uiAction; } +USHORT hb_errRT_DBCMD_Ext( ULONG ulGenCode, ULONG ulSubCode, const char * szDescription, const char * szOperation, USHORT uiFlags ) +{ + USHORT uiAction; + PHB_ITEM pError; + + pError = hb_errRT_New( ES_ERROR, HB_ERR_SS_DBCMD, ulGenCode, ulSubCode, (char *)szDescription, (char *)szOperation, 0, uiFlags ); + + uiAction = hb_errLaunch( pError ); + + hb_itemRelease( pError ); + + return uiAction; +} + USHORT hb_errRT_TOOLS( ULONG ulGenCode, ULONG ulSubCode, char * szDescription, char * szOperation ) { USHORT uiAction; diff --git a/harbour/source/rtl/filesys.c b/harbour/source/rtl/filesys.c index 99cf62fffc..808a1d8abc 100644 --- a/harbour/source/rtl/filesys.c +++ b/harbour/source/rtl/filesys.c @@ -103,6 +103,7 @@ #include "hbapi.h" #include "hbapifs.h" +#include "hbapierr.h" #include "hbset.h" #include "hb_io.h" @@ -2130,24 +2131,172 @@ BYTE HB_EXPORT hb_fsCurDrv( void ) return ( BYTE ) uiResult; /* Return the drive number, base 0. */ } -/* TODO: Implement hb_fsExtOpen */ - -FHANDLE hb_fsExtOpen( BYTE * pFilename, BYTE * pDefExt, - USHORT uiFlags, BYTE * pPaths, PHB_ITEM pError ) +/* copied from xHarbour */ +FHANDLE HB_EXPORT hb_fsExtOpen( BYTE * pFilename, BYTE * pDefExt, + USHORT uiExFlags, BYTE * pPaths, + PHB_ITEM pError ) { - HB_TRACE(HB_TR_DEBUG, ("hb_fsExtOpen(%s, %s, %hu, %p, %p)", (char*) pFilename, (char*) pDefExt, uiFlags, pPaths, pError)); + HB_PATHNAMES *pSearchPath = NULL, *pNextPath; + PHB_FNAME pFilepath; + FHANDLE hFile; + BOOL fIsFile = FALSE; + BYTE * szPath; + USHORT uiFlags; - s_uiErrorLast = FS_ERROR; + HB_TRACE(HB_TR_DEBUG, ("hb_fsExtOpen(%s, %s, %hu, %p, %p)", pFilename, pDefExt, uiExFlags, pPaths, pError)); - HB_SYMBOL_UNUSED( pFilename ); - HB_SYMBOL_UNUSED( pDefExt ); - HB_SYMBOL_UNUSED( uiFlags ); - HB_SYMBOL_UNUSED( pPaths ); - HB_SYMBOL_UNUSED( pError ); +/* + #define FXO_TRUNCATE 0x0100 // Create (truncate if exists) + #define FXO_APPEND 0x0200 // Create (append if exists) + #define FXO_UNIQUE 0x0400 // Create unique file FO_EXCL ??? + #define FXO_FORCEEXT 0x0800 // Force default extension + #define FXO_DEFAULTS 0x1000 // Use SET command defaults + #define FXO_DEVICERAW 0x2000 // Open devices in raw mode + // xHarbour extension + #define FXO_SHARELOCK 0x4000 // emulate DOS SH_DENY* mode in POSIX OS + #define FXO_COPYNAME 0x8000 // copy final szPath into pFilename - return s_uiErrorLast; + hb_errGetFileName( pError ); +*/ + + szPath = (BYTE *) hb_xgrab( _POSIX_PATH_MAX + 1 ); + + uiFlags = uiExFlags & 0xff; + if( uiExFlags & ( FXO_TRUNCATE | FXO_APPEND | FXO_UNIQUE ) ) + { + uiFlags |= FO_CREAT; + if( uiExFlags & FXO_UNIQUE ) + uiFlags |= FO_EXCL; +#if !defined( HB_USE_SHARELOCKS ) + else if( uiExFlags & FXO_TRUNCATE ) + uiFlags |= FO_TRUNC; +#endif + } + + pFilepath = hb_fsFNameSplit( ( char * ) pFilename ); + + if( pDefExt && ( ( uiExFlags & FXO_FORCEEXT ) || !pFilepath->szExtension ) ) + { + pFilepath->szExtension = ( char * ) pDefExt; + } + + if( pFilepath->szPath ) + { + hb_fsFNameMerge( ( char * ) szPath, pFilepath ); + } + else if( uiExFlags & FXO_DEFAULTS ) + { + if( hb_set.HB_SET_DEFAULT ) + { + pFilepath->szPath = hb_set.HB_SET_DEFAULT; + hb_fsFNameMerge( ( char * ) szPath, pFilepath ); + fIsFile = hb_fsFile( szPath ); + } + if( !fIsFile && hb_set.HB_SET_PATH ) + { + pNextPath = hb_setGetFirstSetPath(); + while( !fIsFile && pNextPath ) + { + pFilepath->szPath = pNextPath->szPath; + hb_fsFNameMerge( ( char * ) szPath, pFilepath ); + fIsFile = hb_fsFile( szPath ); + pNextPath = pNextPath->pNext; + } + } + if( !fIsFile ) + { + pFilepath->szPath = hb_set.HB_SET_DEFAULT ? hb_set.HB_SET_DEFAULT : NULL; + hb_fsFNameMerge( ( char * ) szPath, pFilepath ); + } + } + else if( pPaths ) + { + hb_fsAddSearchPath( ( char * ) pPaths, &pSearchPath ); + pNextPath = pSearchPath; + while( !fIsFile && pNextPath ) + { + pFilepath->szPath = pNextPath->szPath; + hb_fsFNameMerge( ( char * ) szPath, pFilepath ); + fIsFile = hb_fsFile( szPath ); + pNextPath = pNextPath->pNext; + } + if( !fIsFile ) + { + pFilepath->szPath = NULL; + hb_fsFNameMerge( ( char * ) szPath, pFilepath ); + } + } + else + { + hb_fsFNameMerge( ( char * ) szPath, pFilepath ); + } + hb_xfree( pFilepath ); + + hFile = hb_fsOpen( szPath, uiFlags ); + +#if defined( HB_USE_SHARELOCKS ) + if( hFile != FS_ERROR && uiExFlags & FXO_SHARELOCK ) + { + USHORT uiLock; + if( ( uiFlags & ( FO_READ | FO_WRITE | FO_READWRITE ) ) == FO_READ || + ( uiFlags & ( FO_DENYREAD | FO_DENYWRITE | FO_EXCLUSIVE ) ) == 0 ) + uiLock = FL_LOCK | FLX_SHARED; + else + uiLock = FL_LOCK | FLX_EXCLUSIVE; + + if( !hb_fsLockLarge( hFile, HB_SHARELOCK_POS, HB_SHARELOCK_SIZE, uiLock ) ) + { + hb_fsClose( hFile ); + hFile = FS_ERROR; + /* + * fix for neterr() support and Clipper compatibility, + * should be revised with a better multi platform solution. + */ + hb_fsSetError( ( uiExFlags & FXO_TRUNCATE ) ? 5 : 32 ); + } + else if( uiExFlags & FXO_TRUNCATE ) + { + /* truncate the file only if properly locked */ + hb_fsSeek( hFile, 0, FS_SET ); + hb_fsWrite( hFile, NULL, 0 ); + if( hb_fsError() != 0 ) + { + hb_fsClose( hFile ); + hFile = FS_ERROR; + hb_fsSetError( 5 ); + } + } + } +#elif 1 + /* + * Temporary fix for neterr() support and Clipper compatibility, + * should be revised with a better solution. + */ + if( ( uiExFlags & ( FXO_TRUNCATE | FXO_APPEND | FXO_UNIQUE ) ) == 0 && + hb_fsError() == 5 ) + { + hb_fsSetError( 32 ); + } +#endif + + if( pError ) + { + hb_errPutFileName( pError, ( char * ) szPath ); + if( hFile == FS_ERROR ) + { + hb_errPutOsCode( pError, hb_fsError() ); + hb_errPutGenCode( pError, ( uiExFlags & FXO_TRUNCATE ) ? EG_CREATE : EG_OPEN ); + } + } + + if( uiExFlags & FXO_COPYNAME && hFile != FS_ERROR ) + strcpy( ( char * ) pFilename, ( char * ) szPath ); + + hb_xfree( szPath ); + return hFile; } + BOOL hb_fsEof( FHANDLE hFileHandle ) { #if defined(__DJGPP__) || defined(__CYGWIN__) || defined(OS_UNIX_COMPATIBLE) diff --git a/harbour/source/vm/arrays.c b/harbour/source/vm/arrays.c index 8ee669ce33..159d353e81 100644 --- a/harbour/source/vm/arrays.c +++ b/harbour/source/vm/arrays.c @@ -125,6 +125,27 @@ BOOL HB_EXPORT hb_arrayAdd( PHB_ITEM pArray, PHB_ITEM pValue ) return FALSE; } +BOOL HB_EXPORT hb_arrayAddForward( PHB_ITEM pArray, PHB_ITEM pValue ) +{ + HB_TRACE(HB_TR_DEBUG, ("hb_arrayAddForward(%p, %p)", pArray, pValue)); + + if( pArray->type == HB_IT_ARRAY ) + { + PHB_BASEARRAY pBaseArray = ( PHB_BASEARRAY ) pArray->item.asArray.value; + + if( pBaseArray->ulLen < ULONG_MAX ) + { + hb_arraySize( pArray, pBaseArray->ulLen + 1 ); + pBaseArray = ( PHB_BASEARRAY ) pArray->item.asArray.value; + hb_itemForwardValue( pBaseArray->pItems + ( pBaseArray->ulLen - 1 ), pValue ); + + return TRUE; + } + } + + return FALSE; +} + ULONG HB_EXPORT hb_arrayLen( PHB_ITEM pArray ) { HB_TRACE(HB_TR_DEBUG, ("hb_arrayLen(%p)", pArray)); diff --git a/harbour/source/vm/dynsym.c b/harbour/source/vm/dynsym.c index 6555e1cf74..ce55a4d7a9 100644 --- a/harbour/source/vm/dynsym.c +++ b/harbour/source/vm/dynsym.c @@ -158,6 +158,19 @@ PHB_DYNS HB_EXPORT hb_dynsymNew( PHB_SYMB pSymbol ) /* creates a new dynamic return pDynSym; } +PHB_DYNS HB_EXPORT hb_dynsymGetCase( char * szName ) /* finds and creates a symbol if not found */ +{ + PHB_DYNS pDynSym; + + HB_TRACE(HB_TR_DEBUG, ("hb_dynsymGet(%s)", szName)); + + pDynSym = hb_dynsymFind( szName ); + if( ! pDynSym ) /* Does it exists ? */ + pDynSym = hb_dynsymNew( hb_symbolNew( szName ) ); /* Make new symbol */ + + return pDynSym; +} + PHB_DYNS HB_EXPORT hb_dynsymGet( char * szName ) /* finds and creates a symbol if not found */ { PHB_DYNS pDynSym; diff --git a/harbour/source/vm/extend.c b/harbour/source/vm/extend.c index 505f06b0f4..79c0f4a43e 100644 --- a/harbour/source/vm/extend.c +++ b/harbour/source/vm/extend.c @@ -160,6 +160,35 @@ char HB_EXPORT * hb_parc( int iParam, ... ) return ( char * ) 0; } +char HB_EXPORT * hb_parcx( int iParam, ... ) +{ + HB_TRACE(HB_TR_DEBUG, ("hb_parc(%d, ...)", iParam)); + + if( ( iParam >= 0 && iParam <= hb_pcount() ) || ( iParam == -1 ) ) + { + PHB_ITEM pItem = ( iParam == -1 ) ? &hb_stack.Return : hb_stackItemFromBase( iParam ); + + if( HB_IS_BYREF( pItem ) ) + pItem = hb_itemUnRef( pItem ); + + if( HB_IS_STRING( pItem ) ) + return pItem->item.asString.value; + else if( HB_IS_ARRAY( pItem ) ) + { + va_list va; + ULONG ulArrayIndex; + + va_start( va, iParam ); + ulArrayIndex = va_arg( va, ULONG ); + va_end( va ); + + return hb_arrayGetCPtr( pItem, ulArrayIndex ); + } + } + + return ""; +} + ULONG HB_EXPORT hb_parclen( int iParam, ... ) { HB_TRACE(HB_TR_DEBUG, ("hb_parclen(%d, ...)", iParam)); @@ -290,6 +319,42 @@ char HB_EXPORT * hb_pardsbuff( char * szDate, int iParam, ... ) return hb_dateDecStr( szDate, 0 ); } +/* retrieve a date as long integer - number of days from Julian's day */ + +LONG HB_EXPORT hb_pardl( int iParam, ... ) +{ + HB_TRACE(HB_TR_DEBUG, ("hb_pardl(%d, ...)", iParam)); + + if( ( iParam >= 0 && iParam <= hb_pcount() ) || ( iParam == -1 ) ) + { + PHB_ITEM pItem = ( iParam == -1 ) ? &hb_stack.Return : hb_stackItemFromBase( iParam ); + + if( HB_IS_BYREF( pItem ) ) + { + pItem = hb_itemUnRef( pItem ); + } + + if( HB_IS_DATE( pItem ) ) + { + return pItem->item.asDate.value; + } + else if( HB_IS_ARRAY( pItem ) ) + { + va_list va; + ULONG ulArrayIndex; + + va_start( va, iParam ); + ulArrayIndex = va_arg( va, ULONG ); + va_end( va ); + + return hb_arrayGetDL( pItem, ulArrayIndex ); + } + } + + return hb_itemGetDL( NULL ); +} + + int HB_EXPORT hb_parl( int iParam, ... ) { HB_TRACE(HB_TR_DEBUG, ("hb_parl(%d, ...)", iParam)); @@ -649,6 +714,32 @@ void HB_EXPORT hb_retclen_buffer( char * szText, ULONG ulLen ) hb_itemPutCPtr( &hb_stack.Return, szText, ulLen ); } +#undef hb_retcAdopt +void HB_EXPORT hb_retcAdopt( char * szText ) +{ + /* + * This functions "adopts" passed pointer to buffer containing a string + * as a value of item of string type + * + * Copied from xHarbour + */ + HB_TRACE_STEALTH( HB_TR_INFO, ("hb_retcAdopt(%s)", szText ) ); + + + if( ( &(hb_stack.Return) )->type ) + { + hb_itemClear( &(hb_stack.Return) ); + } + + ( &(hb_stack.Return) )->type = HB_IT_STRING; + ( &(hb_stack.Return) )->item.asString.u.pulHolders = ( HB_COUNTER * ) hb_xgrab( sizeof( HB_COUNTER ) ); + *( ( &(hb_stack.Return) )->item.asString.u.pulHolders ) = 1; + ( &(hb_stack.Return) )->item.asString.bStatic = FALSE; + ( &(hb_stack.Return) )->item.asString.value = szText; + ( &(hb_stack.Return) )->item.asString.length = strlen( szText ); + +} + /* szDate must have YYYYMMDD format */ #undef hb_retds diff --git a/harbour/source/vm/hvm.c b/harbour/source/vm/hvm.c index cb4c74d73f..2b5e01c655 100644 --- a/harbour/source/vm/hvm.c +++ b/harbour/source/vm/hvm.c @@ -3928,6 +3928,36 @@ HB_ITEM_PTR hb_vmEvalBlockV( HB_ITEM_PTR pBlock, ULONG ulArgCount, ... ) return &hb_stack.Return; } +/* Evaluates a passed codeblock item or macro pointer item + */ +HB_EXPORT HB_ITEM_PTR hb_vmEvalBlockOrMacro( HB_ITEM_PTR pItem ) +{ + + HB_TRACE(HB_TR_DEBUG, ("hb_vmEvalBlockOrMacro(%p)", pItem)); + + if ( pItem->type == HB_IT_BLOCK ) + { + hb_vmPushSymbol( &hb_symEval ); + hb_vmPush( pItem ); + hb_vmSend( 0 ); + } + else + { + HB_MACRO_PTR pMacro = ( HB_MACRO_PTR ) hb_itemGetPtr( pItem ); + if ( pMacro ) + { + hb_macroRun( pMacro ); + hb_itemCopy( &hb_stack.Return, hb_stackItemFromTop( - 1 ) ); + hb_stackPop(); + } + else + { + hb_itemClear( &hb_stack.Return ); + } + } + return &hb_stack.Return; +} + void hb_vmFunction( USHORT uiParams ) { HB_TRACE(HB_TR_DEBUG, ("hb_vmFunction(%hu)", uiParams)); diff --git a/harbour/source/vm/itemapi.c b/harbour/source/vm/itemapi.c index 8894c95c1e..deb2d1c0ad 100644 --- a/harbour/source/vm/itemapi.c +++ b/harbour/source/vm/itemapi.c @@ -610,6 +610,19 @@ PHB_ITEM HB_EXPORT hb_itemReturn( PHB_ITEM pItem ) return pItem; } +PHB_ITEM HB_EXPORT hb_itemReturnForward( PHB_ITEM pItem ) +{ + HB_TRACE_STEALTH( HB_TR_DEBUG, ("hb_itemReturnForward(%p)", pItem ) ); + + if( pItem ) + { + hb_itemForwardValue( &hb_stack.Return, pItem ); + } + + return pItem; +} + + PHB_ITEM HB_EXPORT hb_itemPutDS( PHB_ITEM pItem, char * szDate ) { HB_TRACE(HB_TR_DEBUG, ("hb_itemPutDS(%p, %s)", pItem, szDate)); @@ -1152,6 +1165,31 @@ void HB_EXPORT hb_itemCopy( PHB_ITEM pDest, PHB_ITEM pSource ) } } +/* copy (transfer) the value of item without increasing + * a reference counters (the pSource item cannot be cleared) +*/ +void HB_EXPORT hb_itemForwardValue( PHB_ITEM pDest, PHB_ITEM pSource ) +{ + HB_TRACE_STEALTH( HB_TR_DEBUG, ("hb_itemForwardValue(%p, %p) %i", pDest, pSource, pDest->type ) ); + + if( pDest == pSource ) + { + hb_errInternal( HB_EI_ITEMBADCOPY, NULL, "hb_itemForwardValue()", NULL ); + } + + if( HB_IS_COMPLEX( pDest ) ) + { + hb_itemClear( pDest ); + } + + /* Forward. */ + memcpy( pDest, pSource, sizeof( HB_ITEM ) ); + + /* Now fake clear the transferer. */ + //pSource->item.asString.bStatic = FALSE; + pSource->type = HB_IT_NIL; +} + void HB_EXPORT hb_itemMove( PHB_ITEM pDest, PHB_ITEM pSource ) { HB_TRACE(HB_TR_DEBUG, ("hb_itemCopy(%p, %p)", pDest, pSource));