From 2b4c4b3b5fa3bdceecf419bdaf8f1d8626f9159e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20Czerpak?= Date: Tue, 12 Dec 2017 12:26:24 +0100 Subject: [PATCH] 2017-12-12 12:26 UTC+0100 Przemyslaw Czerpak (druzus/at/poczta.onet.pl) * contrib/hbnf/fttext.c * contrib/hbnf/hbnf.hbx * synced with Viktor's modifications: - use FILE API instead of FS API - protection against GPF when FT area has no valid file handle - alternative function names which exceeds 10 character Cl*pper limit ! fixed handle and memory leak when new file is open in FT area which already has open file * include/harbour.hbx * src/harbour.def * src/vm/hvm.c + added new PRG function: __vmItemRefs( ) -> Please remember that passed parameter increases the counter so if you want to eliminate it then pass it by reference, i,e.: aVal := {} ? __vmItemRefs( aVal ), __vmItemRefs( @aVal ) * include/hbapi.h * src/harbour.def * src/vm/arrays.c * src/vm/codebloc.c * src/vm/hashes.c + added new C functions: HB_COUNTER hb_arrayRefs( PHB_ITEM pArray ); HB_COUNTER hb_hashRefs( PHB_ITEM pHash ); HB_COUNTER hb_codeblockRefs( PHB_ITEM pItem ); * src/rtl/itemseri.c * added new internal function to replace 3 times repeated code for resizing array of references. % use new functions to check number of references to hashes, arrays and objects to ignore in system detecting multiple references the items which have reference counter smaller then 2. Such items cannot have multiple references. In practice this modification resolves the time problem when very big items are serialized to the level comparable to HB_SERIALIZE_IGNOREREF so now this flag is useless though I'll keep it because only in such mode serialization code can be used as filter in streams. I also created binary tree to store references but after this modifications it is not necessary so I decided to not commit it yet. Please only remember that practice limit of such serialization code is created by physical memory attached by OS to the process. When this limit is exceed then swap is actively used what completely kill the performance. The CPU usage is reduced to less then 1% because it waits for restoring swapped memory pages by extremely heavy used disks. In such case I cannot help. --- ChangeLog.txt | 49 ++ contrib/hbnf/fttext.c | 1393 ++++++++++++++++++++--------------------- contrib/hbnf/hbnf.hbx | 2 + include/harbour.hbx | 1 + include/hbapi.h | 65 +- src/harbour.def | 4 + src/rtl/itemseri.c | 89 ++- src/vm/arrays.c | 9 + src/vm/codebloc.c | 9 + src/vm/hashes.c | 9 + src/vm/hvm.c | 21 + 11 files changed, 867 insertions(+), 784 deletions(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index 876f980c73..41896fec2f 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -7,6 +7,55 @@ Entries may not always be in chronological/commit order. See license at the end of file. */ +2017-12-12 12:26 UTC+0100 Przemyslaw Czerpak (druzus/at/poczta.onet.pl) + * contrib/hbnf/fttext.c + * contrib/hbnf/hbnf.hbx + * synced with Viktor's modifications: + - use FILE API instead of FS API + - protection against GPF when FT area has no valid file handle + - alternative function names which exceeds 10 character Cl*pper limit + ! fixed handle and memory leak when new file is open in FT area which + already has open file + + * include/harbour.hbx + * src/harbour.def + * src/vm/hvm.c + + added new PRG function: __vmItemRefs( ) -> + Please remember that passed parameter increases the counter so + if you want to eliminate it then pass it by reference, i,e.: + aVal := {} + ? __vmItemRefs( aVal ), __vmItemRefs( @aVal ) + + * include/hbapi.h + * src/harbour.def + * src/vm/arrays.c + * src/vm/codebloc.c + * src/vm/hashes.c + + added new C functions: + HB_COUNTER hb_arrayRefs( PHB_ITEM pArray ); + HB_COUNTER hb_hashRefs( PHB_ITEM pHash ); + HB_COUNTER hb_codeblockRefs( PHB_ITEM pItem ); + + * src/rtl/itemseri.c + * added new internal function to replace 3 times repeated code for + resizing array of references. + % use new functions to check number of references to hashes, arrays and + objects to ignore in system detecting multiple references the items + which have reference counter smaller then 2. Such items cannot have + multiple references. + In practice this modification resolves the time problem when very big + items are serialized to the level comparable to HB_SERIALIZE_IGNOREREF + so now this flag is useless though I'll keep it because only in such + mode serialization code can be used as filter in streams. + I also created binary tree to store references but after this + modifications it is not necessary so I decided to not commit it yet. + Please only remember that practice limit of such serialization code + is created by physical memory attached by OS to the process. When this + limit is exceed then swap is actively used what completely kill the + performance. The CPU usage is reduced to less then 1% because it waits + for restoring swapped memory pages by extremely heavy used disks. In + such case I cannot help. + 2017-11-22 11:33 UTC+0100 Przemyslaw Czerpak (druzus/at/poczta.onet.pl) * contrib/rddads/ads1.c * src/rdd/workarea.c diff --git a/contrib/hbnf/fttext.c b/contrib/hbnf/fttext.c index 4c6c0c4447..9c3a16546c 100644 --- a/contrib/hbnf/fttext.c +++ b/contrib/hbnf/fttext.c @@ -133,6 +133,10 @@ faster reads) */ #define BUFFSIZE 4096 +#define FT_CHR_CR 13 +#define FT_CHR_LF 10 +#define FT_CHR_EOF 26 + #include "hbapi.h" #include "hbapifs.h" #include "hbstack.h" @@ -143,7 +147,7 @@ typedef struct /* arrays used by the text workareas */ long recno[ TEXT_WORKAREAS ]; HB_FOFFSET offset[ TEXT_WORKAREAS ]; - HB_FHANDLE handles[ TEXT_WORKAREAS ]; + PHB_FILE handles[ TEXT_WORKAREAS ]; long last_rec[ TEXT_WORKAREAS ]; HB_FOFFSET last_off[ TEXT_WORKAREAS ]; HB_FOFFSET lastbyte[ TEXT_WORKAREAS ]; @@ -152,656 +156,11 @@ typedef struct HB_ERRCODE error[ TEXT_WORKAREAS ]; } FT_TEXT, * PFT_TEXT; -static void s_ft_text_init( void * cargo ) -{ - PFT_TEXT ft_text = ( PFT_TEXT ) cargo; +/* the TSD area is allocated by hb_xgrabz() so we do not need init + function to clear its items */ +static HB_TSD_NEW( s_ft_text, sizeof( FT_TEXT ), NULL, NULL ); - ft_text->area = 0; -} - -static HB_TSD_NEW( s_ft_text, sizeof( FT_TEXT ), s_ft_text_init, NULL ); - -/* routines internal to this module */ -static HB_ISIZ _findeol( char * buf, HB_ISIZ buf_len, HB_ISIZ * eol_len ); -static HB_ISIZ _findbol( char * buf, HB_ISIZ buf_len ); -static int _ins_buff( PFT_TEXT ft_text, HB_ISIZ iLen ); -static int _del_buff( PFT_TEXT ft_text, HB_ISIZ iLen ); -static long _ft_skip( long recs ); -static int _writeLine( PFT_TEXT ft_text, const char * theData, HB_SIZE iDataLen ); -static HB_BOOL _writeeol( HB_FHANDLE fhnd ); - -HB_FUNC( FT_FOFFSET ) -{ - PFT_TEXT ft_text = ( PFT_TEXT ) hb_stackGetTSD( &s_ft_text ); - - hb_retnint( ft_text->offset[ ft_text->area ] ); -} - -#define FT_CHR_CR 13 -#define FT_CHR_LF 10 -#define FT_CHR_EOF 26 - -HB_FUNC( FT_FUSE ) -{ - PFT_TEXT ft_text = ( PFT_TEXT ) hb_stackGetTSD( &s_ft_text ); - - ft_text->error[ ft_text->area ] = 0; - - if( HB_ISCHAR( 1 ) ) - { - int attr = hb_parnidef( 2, FO_READWRITE | FO_DENYNONE ); - - ft_text->handles[ ft_text->area ] = hb_fsOpen( hb_parc( 1 ), ( HB_USHORT ) attr ); - if( ft_text->handles[ ft_text->area ] == FS_ERROR ) - ft_text->error[ ft_text->area ] = hb_fsError(); - ft_text->offset[ ft_text->area ] = 0; - ft_text->recno[ ft_text->area ] = 1; - ft_text->lastbyte[ ft_text->area ] = hb_fsSeekLarge( ft_text->handles[ ft_text->area ], 0, FS_END ); - hb_retnint( ft_text->handles[ ft_text->area ] ); - } - else - { - if( ft_text->handles[ ft_text->area ] != 0 ) - { - hb_fsClose( ft_text->handles[ ft_text->area ] ); - hb_retnint( 0 ); - ft_text->recno[ ft_text->area ] = 0L; - ft_text->offset[ ft_text->area ] = 0L; - ft_text->handles[ ft_text->area ] = 0; - ft_text->last_rec[ ft_text->area ] = 0L; - ft_text->last_off[ ft_text->area ] = 0L; - ft_text->lastbyte[ ft_text->area ] = 0L; - ft_text->isBof[ ft_text->area ] = HB_FALSE; - ft_text->isEof[ ft_text->area ] = HB_FALSE; - } - } -} - -HB_FUNC( FT_FSELECT ) -{ - PFT_TEXT ft_text = ( PFT_TEXT ) hb_stackGetTSD( &s_ft_text ); - - int oldarea = ft_text->area + 1; - - if( HB_ISNUM( 1 ) ) - { - int newArea = hb_parni( 1 ); - - if( newArea <= TEXT_WORKAREAS ) - { - if( newArea == 0 ) - { - for(; newArea < TEXT_WORKAREAS - 1; newArea++ ) - { - if( ft_text->handles[ newArea ] == 0 ) - { - ft_text->area = newArea; - break; - } - } - } - else - ft_text->area = newArea - 1; - } - } - hb_retni( oldarea ); -} - -HB_FUNC( FT_FGOTOP ) -{ - PFT_TEXT ft_text = ( PFT_TEXT ) hb_stackGetTSD( &s_ft_text ); - - ft_text->error[ ft_text->area ] = 0; - ft_text->offset[ ft_text->area ] = 0L; - ft_text->recno[ ft_text->area ] = 1L; - ft_text->isBof[ ft_text->area ] = HB_FALSE; - ft_text->isEof[ ft_text->area ] = HB_FALSE; -} - -HB_FUNC( FT_FERROR ) -{ - PFT_TEXT ft_text = ( PFT_TEXT ) hb_stackGetTSD( &s_ft_text ); - - hb_retni( ft_text->error[ ft_text->area ] ); -} - -HB_FUNC( FT_FRECNO ) -{ - PFT_TEXT ft_text = ( PFT_TEXT ) hb_stackGetTSD( &s_ft_text ); - - hb_retnl( ft_text->recno[ ft_text->area ] ); -} - -HB_FUNC( FT_FGOBOT ) -{ - PFT_TEXT ft_text = ( PFT_TEXT ) hb_stackGetTSD( &s_ft_text ); - - ft_text->error[ ft_text->area ] = 0; - if( ! ft_text->last_rec[ ft_text->area ] ) - { - /* if the last record has not already been found */ - _ft_skip( 0 ); - } - - ft_text->recno[ ft_text->area ] = ft_text->last_rec[ ft_text->area ]; - ft_text->offset[ ft_text->area ] = ft_text->last_off[ ft_text->area ]; - ft_text->isBof[ ft_text->area ] = HB_FALSE; - ft_text->isEof[ ft_text->area ] = HB_FALSE; -} - -HB_FUNC( FT_FSKIP ) -{ - if( HB_ISNUM( 1 ) ) - { - if( hb_parnl( 1 ) ) - hb_retnl( _ft_skip( hb_parnl( 1 ) ) ); - else - hb_retnl( 0L ); - } - else - hb_retnl( _ft_skip( 1L ) ); -} - -/* internal routine to do buffer skips. Passing a positive value performs - a downward skip, a negative number does an upward skip. Passing 0 - skips to the end of file. - Returns a long indicating the number of records skipped */ -static long _ft_skip( long iRecs ) -{ - PFT_TEXT ft_text = ( PFT_TEXT ) hb_stackGetTSD( &s_ft_text ); - - HB_ISIZ iByteCount; - HB_ISIZ iBytesRead, iBytesRemaining; - char * cPtr; - long iSkipped = 0; - - char * cBuff = ( char * ) hb_xgrab( BUFFSIZE ); - HB_FOFFSET fpOffset = ft_text->offset[ ft_text->area ]; - - ft_text->isBof[ ft_text->area ] = HB_FALSE; - ft_text->isEof[ ft_text->area ] = HB_FALSE; - ft_text->error[ ft_text->area ] = 0; - - /* iRecs is zero if they want to find the EOF, start a top of file */ - if( iRecs == 0 ) - { - fpOffset = 0L; - ft_text->recno[ ft_text->area ] = 1; - } - - if( iRecs >= 0 ) - { - do - { - cPtr = cBuff; - - /* position file pointer to beginning of current record */ - hb_fsSeekLarge( ft_text->handles[ ft_text->area ], fpOffset, FS_SET ); - - /* read a chunk */ - iBytesRead = hb_fsRead( ft_text->handles[ ft_text->area ], cBuff, BUFFSIZE ); - - if( ! iBytesRead ) - { - /* buffer is empty thus EOF, set vars and quit */ - ft_text->isEof[ ft_text->area ] = HB_TRUE; - ft_text->last_rec[ ft_text->area ] = ft_text->recno[ ft_text->area ]; - ft_text->last_off[ ft_text->area ] = ft_text->offset[ ft_text->area ]; - ft_text->error[ ft_text->area ] = hb_fsError(); - break; - } - - iBytesRemaining = iBytesRead; - /* parse the buffer while there's still stuff in it */ - do - { - /* get count of chars in this line */ - iByteCount = _findeol( cPtr, iBytesRemaining, NULL ); - - if( iByteCount > 0 && iByteCount != iBytesRemaining ) - { - /* found an EOL, iByteCount points to first char of next - record */ - iBytesRemaining -= iByteCount; - fpOffset += iByteCount; - cPtr += iByteCount; - ft_text->offset[ ft_text->area ] = fpOffset; - ft_text->recno[ ft_text->area ]++; - iSkipped++; - if( iRecs && ( iSkipped == iRecs ) ) - iBytesRemaining = iBytesRead = 0; - } - else - { - - /* no more EOLs in this buffer, or EOL is last - chars in the buffer */ - - /* check for EOF */ - if( iBytesRead != BUFFSIZE ) - { - /* buffer was not full, thus EOF, set vars and quit */ - iBytesRemaining = 0; - ft_text->last_rec[ ft_text->area ] = ft_text->recno[ ft_text->area ]; - ft_text->last_off[ ft_text->area ] = ft_text->offset[ ft_text->area ]; - if( iRecs ) - ft_text->isEof[ ft_text->area ] = HB_TRUE; - } - else - { - /* buffer was full, so probably not EOF, but maybe - EOL straddled end of buffer, so back up pointer a bit - before doing the next read */ - fpOffset = hb_fsSeekLarge( ft_text->handles[ ft_text->area ], 0, FS_RELATIVE ) - 1; - iBytesRemaining = 0; - } - } - } - while( iBytesRemaining > 0 ); - } - while( iBytesRead == BUFFSIZE ); - } - else - { - /* skip backwards */ - iRecs = -iRecs; - - if( ft_text->recno[ ft_text->area ] > iRecs ) - { - do - { - /* calc offset to read area of file ahead of current pointer */ - fpOffset = HB_MAX( ft_text->offset[ ft_text->area ] - BUFFSIZE, 0L ); - - /* move file pointer */ - hb_fsSeekLarge( ft_text->handles[ ft_text->area ], fpOffset, FS_SET ); - - /* read a chunk */ - iBytesRead = - hb_fsRead( ft_text->handles[ ft_text->area ], cBuff, BUFFSIZE ); - - if( ! iBytesRead ) - { - /* buffer is empty thus file is zero len, set vars and quit */ - ft_text->isBof[ ft_text->area ] = HB_TRUE; - ft_text->isEof[ ft_text->area ] = HB_TRUE; - ft_text->recno[ ft_text->area ] = 0; - ft_text->offset[ ft_text->area ] = 0; - ft_text->last_rec[ ft_text->area ] = 0; - ft_text->error[ ft_text->area ] = hb_fsError(); - break; - } - - /* set pointer within buffer */ - - iBytesRemaining = ( int ) ( ft_text->offset[ ft_text->area ] - fpOffset ); - - cPtr = cBuff + iBytesRemaining; - - /* parse the buffer while there's still stuff in it */ - do - { - /* get count of chars in this line */ - iByteCount = _findbol( cPtr, iBytesRemaining ); - - if( iByteCount > 0 ) - { - /* found an EOL, iByteCount points to first char of next - record */ - iBytesRemaining -= iByteCount; - ft_text->offset[ ft_text->area ] -= iByteCount; - cPtr -= iByteCount; - fpOffset = ft_text->offset[ ft_text->area ]; - ft_text->recno[ ft_text->area ]--; - iSkipped++; - if( iSkipped == iRecs ) - iBytesRemaining = iBytesRead = 0; - } - else - { - /* no more EOLs in this buffer so we're either at - BOF or record crosses buffer boundary */ - /* check for BOF */ - if( iBytesRead != BUFFSIZE ) - { - /* buffer was not full, thus BOF, set vars and quit */ - iBytesRemaining = 0; - ft_text->offset[ ft_text->area ] = 0; - ft_text->recno[ ft_text->area ] = 1; - ft_text->isBof[ ft_text->area ] = HB_TRUE; - } - else - { - /* buffer was full, so not BOF */ - iBytesRemaining = 0; - } - } - } - while( iBytesRemaining > 0 ); - } - while( fpOffset > 0 && iBytesRead == BUFFSIZE ); - } - else - { - ft_text->offset[ ft_text->area ] = 0; - ft_text->recno[ ft_text->area ] = 1; - ft_text->isBof[ ft_text->area ] = HB_TRUE; - } - } - - hb_xfree( cBuff ); - return iSkipped; -} - -HB_FUNC( FT_FREADLN ) -{ - PFT_TEXT ft_text = ( PFT_TEXT ) hb_stackGetTSD( &s_ft_text ); - - HB_ISIZ iByteCount; - HB_ISIZ iBytesRead; - HB_ISIZ eol_len; - char * cPtr = ( char * ) hb_xgrab( BUFFSIZE ); - - hb_fsSeekLarge( ft_text->handles[ ft_text->area ], ft_text->offset[ ft_text->area ], FS_SET ); - iBytesRead = hb_fsReadLarge( ft_text->handles[ ft_text->area ], cPtr, BUFFSIZE ); - - ft_text->error[ ft_text->area ] = 0; - - if( ! iBytesRead ) - ft_text->error[ ft_text->area ] = hb_fsError(); - - iByteCount = _findeol( cPtr, iBytesRead, &eol_len ); - if( iByteCount ) - hb_retclen( cPtr, iByteCount - eol_len ); - else - hb_retclen( cPtr, iBytesRead ); - - hb_xfree( cPtr ); -} - -HB_FUNC( FT_FDELETE ) -{ - PFT_TEXT ft_text = ( PFT_TEXT ) hb_stackGetTSD( &s_ft_text ); - - int iBytesRead; - HB_FOFFSET srcPtr; - HB_FOFFSET destPtr; - long cur_rec = ft_text->recno[ ft_text->area ]; - HB_FOFFSET cur_off = ft_text->offset[ ft_text->area ]; - char * Buff = ( char * ) hb_xgrab( BUFFSIZE ); - - /* save address to current record ( first record to be deleted ) */ - destPtr = ft_text->offset[ ft_text->area ]; - - /* skip over deleted records, point to first 'to be retained' record */ - _ft_skip( hb_parnldef( 1, 1 ) ); - srcPtr = hb_fsSeekLarge( ft_text->handles[ ft_text->area ], ft_text->offset[ ft_text->area ], FS_SET ); - - /* buffer read retained data, write atop old data */ - do - { - hb_fsSeekLarge( ft_text->handles[ ft_text->area ], srcPtr, FS_SET ); - iBytesRead = hb_fsRead( ft_text->handles[ ft_text->area ], Buff, BUFFSIZE ); /* now read in a big glob */ - srcPtr += iBytesRead; - hb_fsSeekLarge( ft_text->handles[ ft_text->area ], destPtr, FS_SET ); - destPtr += hb_fsWriteLarge( ft_text->handles[ ft_text->area ], Buff, iBytesRead ); - } - while( iBytesRead > 0 ); - - /* move legacy EOF marker */ - hb_fsSeekLarge( ft_text->handles[ ft_text->area ], srcPtr, FS_SET ); - hb_fsWrite( ft_text->handles[ ft_text->area ], Buff, 0 ); - - ft_text->error[ ft_text->area ] = hb_fsError(); - - /* restore pointers */ - ft_text->recno[ ft_text->area ] = cur_rec; - ft_text->offset[ ft_text->area ] = cur_off; - - /* re_calc EOF */ - ft_text->lastbyte[ ft_text->area ] = hb_fsSeekLarge( ft_text->handles[ ft_text->area ], 0L, FS_END ); - _ft_skip( 0 ); - - /* restore pointers again */ - ft_text->recno[ ft_text->area ] = cur_rec; - ft_text->offset[ ft_text->area ] = cur_off; - - /* if we've deleted to EOF, leave EOF flag set, otherwise clear it */ - if( ft_text->recno[ ft_text->area ] != ft_text->last_rec[ ft_text->area ] ) - ft_text->isEof[ ft_text->area ] = HB_FALSE; - - hb_xfree( Buff ); - - hb_retl( ft_text->error[ ft_text->area ] ? 0 : 1 ); -} - -HB_FUNC( FT_FINSERT ) -{ - PFT_TEXT ft_text = ( PFT_TEXT ) hb_stackGetTSD( &s_ft_text ); - - int no_lines = hb_parnidef( 1, 1 ); - HB_ISIZ no_bytes = no_lines * 2; - int err = 1; - - if( _ins_buff( ft_text, no_bytes ) ) - err = 0; - else - { - while( no_lines-- ) - if( ! _writeeol( ft_text->handles[ ft_text->area ] ) ) - { - ft_text->error[ ft_text->area ] = hb_fsError(); - err = 0; - break; - } - } - - hb_retl( err ); -} - -HB_FUNC( FT_FAPPEND ) -{ - PFT_TEXT ft_text = ( PFT_TEXT ) hb_stackGetTSD( &s_ft_text ); - - int no_lines = hb_parnidef( 1, 1 ); - HB_ISIZ iRead; - HB_ISIZ iByteCount; - - char * buff = ( char * ) hb_xgrab( BUFFSIZE ); - - ft_text->error[ ft_text->area ] = 0; - - /* go to end of file */ - - HB_FUNC_EXEC( FT_FGOBOT ); - - /* find end of record */ - - hb_fsSeekLarge( ft_text->handles[ ft_text->area ], ft_text->offset[ ft_text->area ], FS_SET ); - iRead = hb_fsRead( ft_text->handles[ ft_text->area ], buff, BUFFSIZE ); /* now read in a big glob */ - - /* determine if EOL exists, if not, add one */ - - /* get count of chars in this line */ - iByteCount = _findeol( buff, iRead, NULL ); - if( iByteCount == 0 ) - hb_fsSeekLarge( ft_text->handles[ ft_text->area ], 0, FS_END ); - else - { - ft_text->offset[ ft_text->area ] = hb_fsSeekLarge( ft_text->handles[ ft_text->area ], ft_text->offset[ ft_text->area ] + iByteCount, FS_SET ); - ft_text->recno[ ft_text->area ]++; - no_lines--; - } - - while( no_lines-- ) - { - if( ! _writeeol( ft_text->handles[ ft_text->area ] ) ) - { - ft_text->error[ ft_text->area ] = hb_fsError(); - break; - } - ft_text->recno[ ft_text->area ]++; - ft_text->offset[ ft_text->area ] = hb_fsSeekLarge( ft_text->handles[ ft_text->area ], 0, FS_RELATIVE ); -#if 0 - no_lines--; /* Harbour FIX */ -#endif - } - - if( ! ft_text->error[ ft_text->area ] ) - { - /* move legacy EOF marker */ - hb_fsWrite( ft_text->handles[ ft_text->area ], buff, 0 ); - ft_text->error[ ft_text->area ] = hb_fsError(); - } - - /* force recalc of last record/offset */ - ft_text->last_rec[ ft_text->area ] = 0; - - hb_xfree( buff ); - - hb_retl( ft_text->error[ ft_text->area ] ? 0 : 1 ); - -} - -HB_FUNC( FT_FWRITELN ) -{ - PFT_TEXT ft_text = ( PFT_TEXT ) hb_stackGetTSD( &s_ft_text ); - - const char * theData = hb_parc( 1 ); - HB_ISIZ iDataLen = hb_parclen( 1 ); - HB_BOOL bInsert = hb_parl( 2 ); - int err; - - /* position file pointer to insertion point */ - hb_fsSeekLarge( ft_text->handles[ ft_text->area ], ft_text->offset[ ft_text->area ], FS_SET ); - - if( bInsert ) - { - /* insert mode, insert the length of new string + EOL */ - err = _ins_buff( ft_text, iDataLen + 2 ); - - if( ! err ) - { - hb_fsSeekLarge( ft_text->handles[ ft_text->area ], ft_text->offset[ ft_text->area ], FS_SET ); - err = _writeLine( ft_text, theData, iDataLen ); - } - } - else - { - /* overwrite mode, determine how many bytes over/under */ - char * buffer = ( char * ) hb_xgrab( BUFFSIZE ); - - HB_ISIZ iLineLen = 0; - HB_ISIZ iRead, iEOL; - - /* find length of current line, loop if longer than buffer */ - do - { - iRead = hb_fsRead( ft_text->handles[ ft_text->area ], buffer, BUFFSIZE ); - iEOL = _findeol( buffer, iRead, NULL ); - if( iEOL == 0 ) - { - iLineLen += iRead; - } - else - { - iLineLen += iEOL; - break; - } - } - while( iRead == BUFFSIZE ); - - hb_xfree( buffer ); - - if( ( iDataLen + 2 ) <= iLineLen ) - { - /* delete excess bytes from current record */ - _del_buff( ft_text, iLineLen - iDataLen - 2 ); - - /* write the new record's contents */ - hb_fsWriteLarge( ft_text->handles[ ft_text->area ], theData, iDataLen ); - } - else - { - /* insert extra bytes into current record */ - _ins_buff( ft_text, iDataLen - iLineLen + 2 ); - - /* write the new record's contents */ - hb_fsWriteLarge( ft_text->handles[ ft_text->area ], theData, iDataLen ); - } - ft_text->error[ ft_text->area ] = hb_fsError(); - err = ( ft_text->error[ ft_text->area ] ) ? 0 : 1; - } - hb_retl( err ); -} - -HB_FUNC_TRANSLATE( FT_FWRITEL, FT_FWRITELN ) - -HB_FUNC( FT_FLASTRE ) -{ - PFT_TEXT ft_text = ( PFT_TEXT ) hb_stackGetTSD( &s_ft_text ); - - long cur_rec; - HB_FOFFSET cur_offset; - - cur_rec = ft_text->recno[ ft_text->area ]; - cur_offset = ft_text->offset[ ft_text->area ]; - - HB_FUNC_EXEC( FT_FGOBOT ); - hb_retnl( ft_text->last_rec[ ft_text->area ] ); - - ft_text->recno[ ft_text->area ] = cur_rec; - ft_text->offset[ ft_text->area ] = cur_offset; -} - -HB_FUNC( FT_FEOF ) -{ - PFT_TEXT ft_text = ( PFT_TEXT ) hb_stackGetTSD( &s_ft_text ); - - hb_retl( ft_text->isEof[ ft_text->area ] ); -} - -HB_FUNC( FT_FBOF ) -{ - PFT_TEXT ft_text = ( PFT_TEXT ) hb_stackGetTSD( &s_ft_text ); - - hb_retl( ft_text->isBof[ ft_text->area ] ); -} - -HB_FUNC( FT_FGOTO ) -{ - PFT_TEXT ft_text = ( PFT_TEXT ) hb_stackGetTSD( &s_ft_text ); - - long target = hb_parnl( 1 ); - - /* if a recno was passed, do a relative skip */ - if( target ) - { - /* skip relative */ - target -= ft_text->recno[ ft_text->area ]; - - if( target ) - _ft_skip( target ); - } - else - { - /* goto 0 passed, go top then skip back */ - target = ft_text->recno[ ft_text->area ]; - - ft_text->offset[ ft_text->area ] = 0L; - ft_text->recno[ ft_text->area ] = 1L; - ft_text->isBof[ ft_text->area ] = HB_FALSE; - ft_text->isEof[ ft_text->area ] = HB_FALSE; - - if( --target ) - _ft_skip( target ); - } - ft_text->error[ ft_text->area ] = hb_fsError(); -} - -/*---------------------------------------------------------------------- - In-line assembler routine to parse a buffer - for an EOL +/* Routine to parse a buffer for an EOL Returns count to first character _after_ next EOL (beginning of next line). Current line @@ -837,16 +196,13 @@ static HB_ISIZ _findeol( char * buf, HB_ISIZ buf_len, HB_ISIZ * eol_len ) return 0; } -/*---------------------------------------------------------------------- - In-line assembler routine to parse a buffer - for a EOL +/* Routine to parse a buffer for a EOL buf pointer points at beginning of search (end of the buffer), all searches are conducted backwards, returns No. of characters betw. initial position and first character _after_ - the preceding EOL (beginning of line). - */ + the preceding EOL (beginning of line). */ static HB_ISIZ _findbol( char * buf, HB_ISIZ buf_len ) { HB_ISIZ tmp = buf_len - 1; @@ -895,7 +251,195 @@ static HB_ISIZ _findbol( char * buf, HB_ISIZ buf_len ) return buf_len; } -/*--------------------------------------------------------------------------*/ +/* internal routine to do buffer skips. Passing a positive value performs + a downward skip, a negative number does an upward skip. Passing 0 + skips to the end of file. + Returns a long indicating the number of records skipped */ +static long _ft_skip( long iRecs ) +{ + PFT_TEXT ft_text = ( PFT_TEXT ) hb_stackGetTSD( &s_ft_text ); + + long iSkipped = 0; + + if( ft_text->handles[ ft_text->area ] ) + { + HB_ISIZ iByteCount; + HB_ISIZ iBytesRead, iBytesRemaining; + char * cPtr; + + char * cBuff = ( char * ) hb_xgrab( BUFFSIZE ); + HB_FOFFSET fpOffset = ft_text->offset[ ft_text->area ]; + + ft_text->isBof[ ft_text->area ] = HB_FALSE; + ft_text->isEof[ ft_text->area ] = HB_FALSE; + ft_text->error[ ft_text->area ] = 0; + + /* iRecs is zero if they want to find the EOF, start a top of file */ + if( iRecs == 0 ) + { + fpOffset = 0; + ft_text->recno[ ft_text->area ] = 1; + } + + if( iRecs >= 0 ) + { + do + { + cPtr = cBuff; + + /* read a chunk */ + if( ( iBytesRead = hb_fileResult( hb_fileReadAt( ft_text->handles[ ft_text->area ], cBuff, BUFFSIZE, fpOffset ) ) ) == 0 ) + { + /* buffer is empty thus EOF, set vars and quit */ + ft_text->isEof[ ft_text->area ] = HB_TRUE; + ft_text->last_rec[ ft_text->area ] = ft_text->recno[ ft_text->area ]; + ft_text->last_off[ ft_text->area ] = ft_text->offset[ ft_text->area ]; + ft_text->error[ ft_text->area ] = hb_fsError(); + break; + } + + iBytesRemaining = iBytesRead; + /* parse the buffer while there's still stuff in it */ + do + { + /* get count of chars in this line */ + iByteCount = _findeol( cPtr, iBytesRemaining, NULL ); + + if( iByteCount > 0 && iByteCount != iBytesRemaining ) + { + /* found an EOL, iByteCount points to first char of next record */ + iBytesRemaining -= iByteCount; + fpOffset += iByteCount; + cPtr += iByteCount; + ft_text->offset[ ft_text->area ] = fpOffset; + ft_text->recno[ ft_text->area ]++; + iSkipped++; + if( iRecs && ( iSkipped == iRecs ) ) + iBytesRemaining = iBytesRead = 0; + } + else + { + /* no more EOLs in this buffer, or EOL is last + chars in the buffer */ + + /* check for EOF */ + if( iBytesRead != BUFFSIZE ) + { + /* buffer was not full, thus EOF, set vars and quit */ + iBytesRemaining = 0; + ft_text->last_rec[ ft_text->area ] = ft_text->recno[ ft_text->area ]; + ft_text->last_off[ ft_text->area ] = ft_text->offset[ ft_text->area ]; + if( iRecs ) + ft_text->isEof[ ft_text->area ] = HB_TRUE; + } + else + { + /* buffer was full, so probably not EOF, but maybe + EOL straddled end of buffer, so back up pointer a bit + before doing the next read */ + fpOffset = hb_fileSeek( ft_text->handles[ ft_text->area ], 0, FS_RELATIVE ) - 1; + iBytesRemaining = 0; + } + } + } + while( iBytesRemaining > 0 ); + } + while( iBytesRead == BUFFSIZE ); + } + else + { + /* skip backwards */ + iRecs = -iRecs; + + if( ft_text->recno[ ft_text->area ] > iRecs ) + { + do + { + /* calc offset to read area of file ahead of current pointer */ + fpOffset = HB_MAX( ft_text->offset[ ft_text->area ] - BUFFSIZE, 0 ); + + /* read a chunk */ + if( ( iBytesRead = hb_fileResult( hb_fileReadAt( ft_text->handles[ ft_text->area ], cBuff, BUFFSIZE, fpOffset ) ) ) == 0 ) + { + /* buffer is empty thus file is zero len, set vars and quit */ + ft_text->isBof[ ft_text->area ] = HB_TRUE; + ft_text->isEof[ ft_text->area ] = HB_TRUE; + ft_text->recno[ ft_text->area ] = 0; + ft_text->offset[ ft_text->area ] = 0; + ft_text->last_rec[ ft_text->area ] = 0; + ft_text->error[ ft_text->area ] = hb_fsError(); + break; + } + + /* set pointer within buffer */ + + iBytesRemaining = ( int ) ( ft_text->offset[ ft_text->area ] - fpOffset ); + + cPtr = cBuff + iBytesRemaining; + + /* parse the buffer while there's still stuff in it */ + do + { + /* get count of chars in this line */ + iByteCount = _findbol( cPtr, iBytesRemaining ); + + if( iByteCount > 0 ) + { + /* found an EOL, iByteCount points to first char of next + record */ + iBytesRemaining -= iByteCount; + ft_text->offset[ ft_text->area ] -= iByteCount; + cPtr -= iByteCount; + fpOffset = ft_text->offset[ ft_text->area ]; + ft_text->recno[ ft_text->area ]--; + iSkipped++; + if( iSkipped == iRecs ) + iBytesRemaining = iBytesRead = 0; + } + else + { + /* no more EOLs in this buffer so we're either at + BOF or record crosses buffer boundary */ + /* check for BOF */ + if( iBytesRead != BUFFSIZE ) + { + /* buffer was not full, thus BOF, set vars and quit */ + iBytesRemaining = 0; + ft_text->offset[ ft_text->area ] = 0; + ft_text->recno[ ft_text->area ] = 1; + ft_text->isBof[ ft_text->area ] = HB_TRUE; + } + else + { + /* buffer was full, so not BOF */ + iBytesRemaining = 0; + } + } + } + while( iBytesRemaining > 0 ); + } + while( fpOffset > 0 && iBytesRead == BUFFSIZE ); + } + else + { + ft_text->offset[ ft_text->area ] = 0; + ft_text->recno[ ft_text->area ] = 1; + ft_text->isBof[ ft_text->area ] = HB_TRUE; + } + } + + hb_xfree( cBuff ); + } + else + { + ft_text->isBof[ ft_text->area ] = HB_TRUE; + ft_text->isEof[ ft_text->area ] = HB_TRUE; + ft_text->error[ ft_text->area ] = 0; + } + + return iSkipped; +} + /* inserts xxx bytes into the current file, beginning at the current record */ /* the contents of the inserted bytes are indeterminate, i.e. you'll have to write to them before they mean anything */ @@ -919,11 +463,10 @@ static int _ins_buff( PFT_TEXT ft_text, HB_ISIZ iLen ) fpWrite = ft_text->offset[ ft_text->area ] + iLen; /* do initial load of both buffers */ - hb_fsSeekLarge( ft_text->handles[ ft_text->area ], fpRead, FS_SET ); - WriteLen = hb_fsRead( ft_text->handles[ ft_text->area ], WriteBuff, BUFFSIZE ); + WriteLen = hb_fileResult( hb_fileReadAt( ft_text->handles[ ft_text->area ], WriteBuff, BUFFSIZE, fpRead ) ); fpRead += WriteLen; - ReadLen = hb_fsRead( ft_text->handles[ ft_text->area ], ReadBuff, BUFFSIZE ); + ReadLen = hb_fileResult( hb_fileRead( ft_text->handles[ ft_text->area ], ReadBuff, BUFFSIZE, -1 ) ); fpRead += ReadLen; ft_text->error[ ft_text->area ] = 0; @@ -933,15 +476,13 @@ static int _ins_buff( PFT_TEXT ft_text, HB_ISIZ iLen ) while( WriteLen > 0 ) { /* position to beginning of write area */ - if( hb_fsSeekLarge( ft_text->handles[ ft_text->area ], fpWrite, FS_SET ) != fpWrite ) + if( hb_fileSeek( ft_text->handles[ ft_text->area ], fpWrite, FS_SET ) != fpWrite ) { ft_text->error[ ft_text->area ] = hb_fsError(); break; } - SaveLen = hb_fsWriteLarge( ft_text->handles[ ft_text->area ], WriteBuff, WriteLen ); - - if( ! SaveLen ) + if( ( SaveLen = hb_fileResult( hb_fileWrite( ft_text->handles[ ft_text->area ], WriteBuff, WriteLen, -1 ) ) ) == 0 ) { ft_text->error[ ft_text->area ] = hb_fsError(); break; @@ -967,8 +508,7 @@ static int _ins_buff( PFT_TEXT ft_text, HB_ISIZ iLen ) WriteLen = ReadLen; /* return to read area and read another buffer */ - hb_fsSeekLarge( ft_text->handles[ ft_text->area ], fpRead, FS_SET ); - ReadLen = hb_fsRead( ft_text->handles[ ft_text->area ], ReadBuff, BUFFSIZE ); + ReadLen = hb_fileResult( hb_fileReadAt( ft_text->handles[ ft_text->area ], ReadBuff, BUFFSIZE, fpRead ) ); fpRead += ReadLen; } @@ -977,12 +517,12 @@ static int _ins_buff( PFT_TEXT ft_text, HB_ISIZ iLen ) } /* store length in bytes, set legacy EOF marker */ - ft_text->lastbyte[ ft_text->area ] = hb_fsSeekLarge( ft_text->handles[ ft_text->area ], fpWrite, FS_SET ); - hb_fsWrite( ft_text->handles[ ft_text->area ], WriteBuff, 0 ); + ft_text->lastbyte[ ft_text->area ] = hb_fileSeek( ft_text->handles[ ft_text->area ], fpWrite, FS_SET ); + hb_fileWrite( ft_text->handles[ ft_text->area ], WriteBuff, 0, -1 ); /* clear last_rec so next gobot will recount the records */ - ft_text->last_rec[ ft_text->area ] = 0L; - hb_fsSeekLarge( ft_text->handles[ ft_text->area ], ft_text->offset[ ft_text->area ], FS_SET ); + ft_text->last_rec[ ft_text->area ] = 0; + hb_fileSeek( ft_text->handles[ ft_text->area ], ft_text->offset[ ft_text->area ], FS_SET ); hb_xfree( ReadBuff ); hb_xfree( WriteBuff ); @@ -990,31 +530,29 @@ static int _ins_buff( PFT_TEXT ft_text, HB_ISIZ iLen ) return ft_text->error[ ft_text->area ]; } -/*--------------------------------------------------------------------------*/ /* deletes xxx bytes from the current file, beginning at the current record */ static int _del_buff( PFT_TEXT ft_text, HB_ISIZ iLen ) { char * WriteBuff = ( char * ) hb_xgrab( BUFFSIZE ); HB_FOFFSET fpRead, fpWrite; HB_ISIZ WriteLen; - HB_ISIZ SaveLen; /* initialize file pointers */ fpWrite = ft_text->offset[ ft_text->area ]; fpRead = ft_text->offset[ ft_text->area ] + iLen; /* do initial load of buffer */ - hb_fsSeekLarge( ft_text->handles[ ft_text->area ], fpRead, FS_SET ); - WriteLen = hb_fsRead( ft_text->handles[ ft_text->area ], WriteBuff, BUFFSIZE ); + WriteLen = hb_fileResult( hb_fileReadAt( ft_text->handles[ ft_text->area ], WriteBuff, BUFFSIZE, fpRead ) ); fpRead += WriteLen; ft_text->error[ ft_text->area ] = 0; while( WriteLen > 0 ) { + HB_ISIZ SaveLen; + /* position to beginning of write area */ - hb_fsSeekLarge( ft_text->handles[ ft_text->area ], fpWrite, FS_SET ); - SaveLen = hb_fsWriteLarge( ft_text->handles[ ft_text->area ], WriteBuff, WriteLen ); + SaveLen = hb_fileResult( hb_fileWriteAt( ft_text->handles[ ft_text->area ], WriteBuff, WriteLen, fpWrite ) ); /* move write pointer */ fpWrite += SaveLen; @@ -1027,47 +565,498 @@ static int _del_buff( PFT_TEXT ft_text, HB_ISIZ iLen ) } /* return to read area and read another buffer */ - hb_fsSeekLarge( ft_text->handles[ ft_text->area ], fpRead, FS_SET ); - WriteLen = hb_fsRead( ft_text->handles[ ft_text->area ], WriteBuff, BUFFSIZE ); + WriteLen = hb_fileResult( hb_fileReadAt( ft_text->handles[ ft_text->area ], WriteBuff, BUFFSIZE, fpRead ) ); fpRead += WriteLen; } /* store length in bytes, set legacy EOF marker */ - ft_text->lastbyte[ ft_text->area ] = hb_fsSeekLarge( ft_text->handles[ ft_text->area ], fpWrite, FS_SET ); - hb_fsWrite( ft_text->handles[ ft_text->area ], WriteBuff, 0 ); + ft_text->lastbyte[ ft_text->area ] = hb_fileSeek( ft_text->handles[ ft_text->area ], fpWrite, FS_SET ); + hb_fileWrite( ft_text->handles[ ft_text->area ], WriteBuff, 0, -1 ); /* clear last_rec so next gobot will recount the records */ - ft_text->last_rec[ ft_text->area ] = 0L; - hb_fsSeekLarge( ft_text->handles[ ft_text->area ], ft_text->offset[ ft_text->area ], FS_SET ); + ft_text->last_rec[ ft_text->area ] = 0; + hb_fileSeek( ft_text->handles[ ft_text->area ], ft_text->offset[ ft_text->area ], FS_SET ); hb_xfree( WriteBuff ); return ft_text->error[ ft_text->area ]; } -/*--------------------------------------------------------------------------*/ -/* writes a line of data to the file, including the terminating EOL */ -static int _writeLine( PFT_TEXT ft_text, const char * theData, HB_SIZE iDataLen ) -{ - int err = 0; - - if( ! ( hb_fsWriteLarge( ft_text->handles[ ft_text->area ], theData, iDataLen ) == iDataLen ) ) - { - err = 1; - ft_text->error[ ft_text->area ] = hb_fsError(); - } - else if( ! _writeeol( ft_text->handles[ ft_text->area ] ) ) - { - err = 1; - ft_text->error[ ft_text->area ] = hb_fsError(); - } - return err; -} - -static HB_BOOL _writeeol( HB_FHANDLE fhnd ) +static HB_BOOL _writeeol( PHB_FILE fhnd ) { const char * eol = hb_conNewLine(); HB_SIZE len = strlen( eol ); - return hb_fsWriteLarge( fhnd, eol, len ) == len; + return hb_fileWrite( fhnd, eol, len, -1 ) == len; +} + +/* writes a line of data to the file, including the terminating EOL */ +static HB_BOOL _writeLine( PFT_TEXT ft_text, const char * theData, HB_SIZE iDataLen ) +{ + HB_BOOL fSuccess = HB_TRUE; + + if( hb_fileWrite( ft_text->handles[ ft_text->area ], theData, iDataLen, -1 ) != iDataLen ) + { + fSuccess = HB_FALSE; + ft_text->error[ ft_text->area ] = hb_fsError(); + } + else if( ! _writeeol( ft_text->handles[ ft_text->area ] ) ) + { + fSuccess = HB_FALSE; + ft_text->error[ ft_text->area ] = hb_fsError(); + } + return fSuccess; +} + +HB_FUNC( FT_FOFFSET ) +{ + PFT_TEXT ft_text = ( PFT_TEXT ) hb_stackGetTSD( &s_ft_text ); + + hb_retnint( ft_text->offset[ ft_text->area ] ); +} + +HB_FUNC( FT_FUSE ) +{ + PFT_TEXT ft_text = ( PFT_TEXT ) hb_stackGetTSD( &s_ft_text ); + const char * pszFileName = hb_parc( 1 ); + + ft_text->error[ ft_text->area ] = 0; + if( ft_text->handles[ ft_text->area ] != NULL ) + { + hb_fileClose( ft_text->handles[ ft_text->area ] ); + hb_retnint( 0 ); + ft_text->recno[ ft_text->area ] = 0; + ft_text->offset[ ft_text->area ] = 0; + ft_text->handles[ ft_text->area ] = NULL; + ft_text->last_rec[ ft_text->area ] = 0; + ft_text->last_off[ ft_text->area ] = 0; + ft_text->lastbyte[ ft_text->area ] = 0; + ft_text->isBof[ ft_text->area ] = HB_FALSE; + ft_text->isEof[ ft_text->area ] = HB_FALSE; + } + + if( pszFileName ) + { + ft_text->handles[ ft_text->area ] = hb_fileExtOpen( pszFileName, NULL, + ( HB_FATTR ) ( hb_parnidef( 2, FO_READWRITE | FO_DENYNONE ) & 0xFF ), + NULL, NULL ); + ft_text->offset[ ft_text->area ] = 0; + ft_text->recno[ ft_text->area ] = 1; + if( ft_text->handles[ ft_text->area ] == NULL ) + { + ft_text->error[ ft_text->area ] = hb_fsError(); + ft_text->lastbyte[ ft_text->area ] = 0; + hb_retnint( FS_ERROR ); + } + else + { + ft_text->lastbyte[ ft_text->area ] = hb_fileSeek( ft_text->handles[ ft_text->area ], 0, FS_END ); + hb_retnint( hb_fileHandle( ft_text->handles[ ft_text->area ] ) ); + } + } +} + +HB_FUNC( FT_FSELECT ) +{ + PFT_TEXT ft_text = ( PFT_TEXT ) hb_stackGetTSD( &s_ft_text ); + + int oldarea = ft_text->area + 1; + + if( HB_ISNUM( 1 ) ) + { + int newArea = hb_parni( 1 ); + + if( newArea <= TEXT_WORKAREAS ) + { + if( newArea == 0 ) + { + for(; newArea < TEXT_WORKAREAS - 1; newArea++ ) + { + if( ft_text->handles[ newArea ] == NULL ) + { + ft_text->area = newArea; + break; + } + } + } + else + ft_text->area = newArea - 1; + } + } + hb_retni( oldarea ); +} + +HB_FUNC( FT_FGOTOP ) +{ + PFT_TEXT ft_text = ( PFT_TEXT ) hb_stackGetTSD( &s_ft_text ); + + ft_text->error[ ft_text->area ] = 0; + ft_text->offset[ ft_text->area ] = 0; + ft_text->recno[ ft_text->area ] = 1; + ft_text->isBof[ ft_text->area ] = HB_FALSE; + ft_text->isEof[ ft_text->area ] = HB_FALSE; +} + +HB_FUNC( FT_FERROR ) +{ + PFT_TEXT ft_text = ( PFT_TEXT ) hb_stackGetTSD( &s_ft_text ); + + hb_retni( ft_text->error[ ft_text->area ] ); +} + +HB_FUNC( FT_FRECNO ) +{ + PFT_TEXT ft_text = ( PFT_TEXT ) hb_stackGetTSD( &s_ft_text ); + + hb_retnl( ft_text->recno[ ft_text->area ] ); +} + +HB_FUNC( FT_FGOBOT ) +{ + PFT_TEXT ft_text = ( PFT_TEXT ) hb_stackGetTSD( &s_ft_text ); + + ft_text->error[ ft_text->area ] = 0; + if( ! ft_text->last_rec[ ft_text->area ] ) + { + /* if the last record has not already been found */ + _ft_skip( 0 ); + } + + ft_text->recno[ ft_text->area ] = ft_text->last_rec[ ft_text->area ]; + ft_text->offset[ ft_text->area ] = ft_text->last_off[ ft_text->area ]; + ft_text->isBof[ ft_text->area ] = HB_FALSE; + ft_text->isEof[ ft_text->area ] = HB_FALSE; +} + +HB_FUNC_TRANSLATE( FT_FGOBOTTOM, FT_FGOBOT ) /* HB_EXTENSION */ + +HB_FUNC( FT_FSKIP ) +{ + if( HB_ISNUM( 1 ) ) + { + if( hb_parnl( 1 ) ) + hb_retnl( _ft_skip( hb_parnl( 1 ) ) ); + else + hb_retnl( 0 ); + } + else + hb_retnl( _ft_skip( 1 ) ); +} + +HB_FUNC( FT_FREADLN ) +{ + PFT_TEXT ft_text = ( PFT_TEXT ) hb_stackGetTSD( &s_ft_text ); + + if( ft_text->handles[ ft_text->area ] ) + { + HB_ISIZ iByteCount; + HB_ISIZ iBytesRead; + HB_ISIZ eol_len; + char * cPtr = ( char * ) hb_xgrab( BUFFSIZE ); + + if( ( iBytesRead = hb_fileResult( hb_fileReadAt( ft_text->handles[ ft_text->area ], cPtr, BUFFSIZE, ft_text->offset[ ft_text->area ] ) ) ) == 0 ) + ft_text->error[ ft_text->area ] = hb_fsError(); + else + ft_text->error[ ft_text->area ] = 0; + + if( ( iByteCount = _findeol( cPtr, iBytesRead, &eol_len ) ) > 0 ) + hb_retclen( cPtr, iByteCount - eol_len ); + else + hb_retclen( cPtr, iBytesRead ); + + hb_xfree( cPtr ); + } + else + hb_retc_null(); +} + +HB_FUNC( FT_FDELETE ) +{ + PFT_TEXT ft_text = ( PFT_TEXT ) hb_stackGetTSD( &s_ft_text ); + + if( ft_text->handles[ ft_text->area ] ) + { + HB_SIZE nBytesRead; + HB_FOFFSET srcPtr; + HB_FOFFSET destPtr; + long cur_rec = ft_text->recno[ ft_text->area ]; + HB_FOFFSET cur_off = ft_text->offset[ ft_text->area ]; + char * Buff = ( char * ) hb_xgrab( BUFFSIZE ); + + /* save address to current record ( first record to be deleted ) */ + destPtr = ft_text->offset[ ft_text->area ]; + + /* skip over deleted records, point to first 'to be retained' record */ + _ft_skip( hb_parnldef( 1, 1 ) ); + srcPtr = hb_fileSeek( ft_text->handles[ ft_text->area ], ft_text->offset[ ft_text->area ], FS_SET ); + + /* buffer read retained data, write atop old data */ + do + { + nBytesRead = hb_fileResult( hb_fileReadAt( ft_text->handles[ ft_text->area ], Buff, BUFFSIZE, srcPtr ) ); /* now read in a big glob */ + srcPtr += nBytesRead; + destPtr += hb_fileResult( hb_fileWriteAt( ft_text->handles[ ft_text->area ], Buff, nBytesRead, destPtr ) ); + } + while( nBytesRead > 0 ); + + /* move legacy EOF marker */ + hb_fileWriteAt( ft_text->handles[ ft_text->area ], Buff, 0, srcPtr ); + + ft_text->error[ ft_text->area ] = hb_fsError(); + + /* restore pointers */ + ft_text->recno[ ft_text->area ] = cur_rec; + ft_text->offset[ ft_text->area ] = cur_off; + + /* re_calc EOF */ + ft_text->lastbyte[ ft_text->area ] = hb_fileSeek( ft_text->handles[ ft_text->area ], 0, FS_END ); + _ft_skip( 0 ); + + /* restore pointers again */ + ft_text->recno[ ft_text->area ] = cur_rec; + ft_text->offset[ ft_text->area ] = cur_off; + + /* if we've deleted to EOF, leave EOF flag set, otherwise clear it */ + if( ft_text->recno[ ft_text->area ] != ft_text->last_rec[ ft_text->area ] ) + ft_text->isEof[ ft_text->area ] = HB_FALSE; + + hb_xfree( Buff ); + } + + hb_retl( ft_text->error[ ft_text->area ] == 0 ); +} + +HB_FUNC( FT_FINSERT ) +{ + PFT_TEXT ft_text = ( PFT_TEXT ) hb_stackGetTSD( &s_ft_text ); + + HB_BOOL fSuccess = HB_FALSE; + + if( ft_text->handles[ ft_text->area ] ) + { + int no_lines = hb_parnidef( 1, 1 ); + HB_ISIZ no_bytes = no_lines * 2; + + if( _ins_buff( ft_text, no_bytes ) == 0 ) + { + fSuccess = HB_TRUE; + while( no_lines-- ) + { + if( ! _writeeol( ft_text->handles[ ft_text->area ] ) ) + { + ft_text->error[ ft_text->area ] = hb_fsError(); + fSuccess = HB_FALSE; + break; + } + } + } + } + + hb_retl( fSuccess ); +} + +HB_FUNC( FT_FAPPEND ) +{ + PFT_TEXT ft_text = ( PFT_TEXT ) hb_stackGetTSD( &s_ft_text ); + + if( ft_text->handles[ ft_text->area ] ) + { + int no_lines = hb_parnidef( 1, 1 ); + HB_ISIZ iRead; + HB_ISIZ iByteCount; + + char * buff = ( char * ) hb_xgrab( BUFFSIZE ); + + ft_text->error[ ft_text->area ] = 0; + + /* go to end of file */ + HB_FUNC_EXEC( FT_FGOBOT ); + + /* find end of record */ + iRead = hb_fileResult( hb_fileReadAt( ft_text->handles[ ft_text->area ], buff, BUFFSIZE, ft_text->offset[ ft_text->area ] ) ); /* now read in a big glob */ + + /* determine if EOL exists, if not, add one */ + + /* get count of chars in this line */ + if( ( iByteCount = _findeol( buff, iRead, NULL ) ) == 0 ) + hb_fileSeek( ft_text->handles[ ft_text->area ], 0, FS_END ); + else + { + ft_text->offset[ ft_text->area ] = hb_fileSeek( ft_text->handles[ ft_text->area ], ft_text->offset[ ft_text->area ] + iByteCount, FS_SET ); + ft_text->recno[ ft_text->area ]++; + no_lines--; + } + + while( no_lines-- ) + { + if( ! _writeeol( ft_text->handles[ ft_text->area ] ) ) + { + ft_text->error[ ft_text->area ] = hb_fsError(); + break; + } + ft_text->recno[ ft_text->area ]++; + ft_text->offset[ ft_text->area ] = hb_fileSeek( ft_text->handles[ ft_text->area ], 0, FS_RELATIVE ); +#if 0 + no_lines--; /* Harbour FIX */ +#endif + } + + if( ! ft_text->error[ ft_text->area ] ) + { + /* move legacy EOF marker */ + hb_fileWrite( ft_text->handles[ ft_text->area ], buff, 0, -1 ); + ft_text->error[ ft_text->area ] = hb_fsError(); + } + + /* force recalc of last record/offset */ + ft_text->last_rec[ ft_text->area ] = 0; + + hb_xfree( buff ); + } + + hb_retl( ft_text->error[ ft_text->area ] == 0 ); +} + +HB_FUNC( FT_FWRITELN ) +{ + PFT_TEXT ft_text = ( PFT_TEXT ) hb_stackGetTSD( &s_ft_text ); + + HB_BOOL fSuccess = HB_FALSE; + + if( ft_text->handles[ ft_text->area ] ) + { + const char * theData = hb_parc( 1 ); + HB_ISIZ iDataLen = hb_parclen( 1 ); + HB_BOOL bInsert = hb_parl( 2 ); + + /* position file pointer to insertion point */ + hb_fileSeek( ft_text->handles[ ft_text->area ], ft_text->offset[ ft_text->area ], FS_SET ); + + if( bInsert ) + { + /* insert mode, insert the length of new string + EOL */ + fSuccess = ( _ins_buff( ft_text, iDataLen + 2 ) == 0 ); + + if( fSuccess ) + { + hb_fileSeek( ft_text->handles[ ft_text->area ], ft_text->offset[ ft_text->area ], FS_SET ); + fSuccess = _writeLine( ft_text, theData, iDataLen ); + } + } + else + { + /* overwrite mode, determine how many bytes over/under */ + char * buffer = ( char * ) hb_xgrab( BUFFSIZE ); + + HB_ISIZ iLineLen = 0; + HB_ISIZ iRead; + + /* find length of current line, loop if longer than buffer */ + do + { + HB_ISIZ iEOL; + + iRead = hb_fileResult( hb_fileRead( ft_text->handles[ ft_text->area ], buffer, BUFFSIZE, -1 ) ); + if( ( iEOL = _findeol( buffer, iRead, NULL ) ) == 0 ) + iLineLen += iRead; + else + { + iLineLen += iEOL; + break; + } + } + while( iRead == BUFFSIZE ); + + hb_xfree( buffer ); + + if( ( iDataLen + 2 ) <= iLineLen ) + { + /* delete excess bytes from current record */ + _del_buff( ft_text, iLineLen - iDataLen - 2 ); + + /* write the new record's contents */ + hb_fileWrite( ft_text->handles[ ft_text->area ], theData, iDataLen, -1 ); + } + else + { + /* insert extra bytes into current record */ + _ins_buff( ft_text, iDataLen - iLineLen + 2 ); + + /* write the new record's contents */ + hb_fileWrite( ft_text->handles[ ft_text->area ], theData, iDataLen, -1 ); + } + ft_text->error[ ft_text->area ] = hb_fsError(); + fSuccess = ( ft_text->error[ ft_text->area ] == 0 ); + } + } + + hb_retl( fSuccess ); +} + +HB_FUNC_TRANSLATE( FT_FWRITEL, FT_FWRITELN ) + +HB_FUNC( FT_FLASTRE ) +{ + PFT_TEXT ft_text = ( PFT_TEXT ) hb_stackGetTSD( &s_ft_text ); + + if( ft_text->handles[ ft_text->area ] ) + { + long cur_rec = ft_text->recno[ ft_text->area ]; + HB_FOFFSET cur_offset = ft_text->offset[ ft_text->area ]; + + HB_FUNC_EXEC( FT_FGOBOT ); + hb_retnl( ft_text->last_rec[ ft_text->area ] ); + + ft_text->recno[ ft_text->area ] = cur_rec; + ft_text->offset[ ft_text->area ] = cur_offset; + } + else + hb_retnl( 0 ); +} + +HB_FUNC_TRANSLATE( FT_FLASTREC, FT_FLASTRE ) + +HB_FUNC( FT_FEOF ) +{ + PFT_TEXT ft_text = ( PFT_TEXT ) hb_stackGetTSD( &s_ft_text ); + + hb_retl( ft_text->isEof[ ft_text->area ] ); +} + +HB_FUNC( FT_FBOF ) +{ + PFT_TEXT ft_text = ( PFT_TEXT ) hb_stackGetTSD( &s_ft_text ); + + hb_retl( ft_text->isBof[ ft_text->area ] ); +} + +HB_FUNC( FT_FGOTO ) +{ + PFT_TEXT ft_text = ( PFT_TEXT ) hb_stackGetTSD( &s_ft_text ); + + long target = hb_parnl( 1 ); + + /* if a recno was passed, do a relative skip */ + if( target ) + { + /* skip relative */ + target -= ft_text->recno[ ft_text->area ]; + + if( target ) + _ft_skip( target ); + } + else + { + /* goto 0 passed, go top then skip back */ + target = ft_text->recno[ ft_text->area ]; + + ft_text->offset[ ft_text->area ] = 0; + ft_text->recno[ ft_text->area ] = 1; + ft_text->isBof[ ft_text->area ] = HB_FALSE; + ft_text->isEof[ ft_text->area ] = HB_FALSE; + + if( --target ) + _ft_skip( target ); + } + ft_text->error[ ft_text->area ] = hb_fsError(); } diff --git a/contrib/hbnf/hbnf.hbx b/contrib/hbnf/hbnf.hbx index 844b392854..6eb033f60e 100644 --- a/contrib/hbnf/hbnf.hbx +++ b/contrib/hbnf/hbnf.hbx @@ -87,12 +87,14 @@ DYNAMIC ft_FDelete DYNAMIC ft_FEof DYNAMIC ft_FError DYNAMIC ft_FGoBot +DYNAMIC ft_FGoBottom DYNAMIC ft_FGoto DYNAMIC ft_FGoTop DYNAMIC ft_Fill DYNAMIC ft_FindITh DYNAMIC ft_FInsert DYNAMIC ft_FLastRe +DYNAMIC ft_FLastRec DYNAMIC ft_FlopTst DYNAMIC ft_FOffset DYNAMIC ft_FReadLn diff --git a/include/harbour.hbx b/include/harbour.hbx index 8a888c81d7..6c38ff7f43 100644 --- a/include/harbour.hbx +++ b/include/harbour.hbx @@ -1594,6 +1594,7 @@ DYNAMIC __TracePrgCalls DYNAMIC __TypeFile DYNAMIC __vmCountThreads DYNAMIC __vmItemID +DYNAMIC __vmItemRefs DYNAMIC __vmModulesVerify DYNAMIC __vmNoInternals DYNAMIC __Wait diff --git a/include/hbapi.h b/include/hbapi.h index 3715d7e0b6..17ffdf0baf 100644 --- a/include/hbapi.h +++ b/include/hbapi.h @@ -798,6 +798,7 @@ extern HB_EXPORT HB_BOOL hb_arrayNew( PHB_ITEM pItem, HB_SIZE nLen ); /* cr extern HB_EXPORT HB_SIZE hb_arrayLen( PHB_ITEM pArray ); /* retrieves the array length */ extern HB_EXPORT HB_BOOL hb_arrayIsObject( PHB_ITEM pArray ); /* retrieves if the array is an object */ extern HB_EXPORT void * hb_arrayId( PHB_ITEM pArray ); /* retrieves the array unique ID */ +extern HB_EXPORT HB_COUNTER hb_arrayRefs( PHB_ITEM pArray ); /* retrieves numer of references to the array */ extern HB_EXPORT PHB_ITEM hb_arrayFromId( PHB_ITEM pItem, void * pArrayId ); extern HB_EXPORT HB_BOOL hb_arrayAdd( PHB_ITEM pArray, PHB_ITEM pItemValue ); /* add a new item to the end of an array item */ extern HB_EXPORT HB_BOOL 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 */ @@ -877,39 +878,40 @@ extern void hb_hashCloneBody( PHB_ITEM pDest, PHB_ITEM pHash, PHB_NESTED_CLONED /* hash management */ -extern HB_EXPORT PHB_ITEM hb_hashNew( PHB_ITEM pItem ); -extern HB_EXPORT HB_SIZE hb_hashLen( PHB_ITEM pHash ); -extern HB_EXPORT HB_BOOL hb_hashDel( PHB_ITEM pHash, PHB_ITEM pKey ); -extern HB_EXPORT HB_BOOL hb_hashAdd( PHB_ITEM pHash, PHB_ITEM pKey, PHB_ITEM pValue ); -extern HB_EXPORT HB_BOOL hb_hashAddNew( PHB_ITEM pHash, PHB_ITEM pKey, PHB_ITEM pValue ); -extern HB_EXPORT HB_BOOL hb_hashRemove( PHB_ITEM pHash, PHB_ITEM pItem ); -extern HB_EXPORT HB_BOOL hb_hashClear( PHB_ITEM pHash ); -extern HB_EXPORT HB_BOOL hb_hashAllocNewPair( PHB_ITEM pHash, PHB_ITEM * pKeyPtr, PHB_ITEM * pValPtr ); -extern HB_EXPORT void hb_hashSort( PHB_ITEM pHash ); -extern HB_EXPORT PHB_ITEM hb_hashClone( PHB_ITEM pHash ); -extern HB_EXPORT PHB_ITEM hb_hashCloneTo( PHB_ITEM pDest, PHB_ITEM pHash ); -extern HB_EXPORT void hb_hashJoin( PHB_ITEM pDest, PHB_ITEM pSource, int iType ); -extern HB_EXPORT HB_BOOL hb_hashScan( PHB_ITEM pHash, PHB_ITEM pKey, HB_SIZE * pnPos ); -extern HB_EXPORT HB_BOOL hb_hashScanSoft( PHB_ITEM pHash, PHB_ITEM pKey, HB_SIZE * pnPos ); -extern HB_EXPORT void hb_hashPreallocate( PHB_ITEM pHash, HB_SIZE nNewSize ); -extern HB_EXPORT PHB_ITEM hb_hashGetKeys( PHB_ITEM pHash ); -extern HB_EXPORT PHB_ITEM hb_hashGetValues( PHB_ITEM pHash ); -extern HB_EXPORT void hb_hashSetDefault( PHB_ITEM pHash, PHB_ITEM pValue ); -extern HB_EXPORT PHB_ITEM hb_hashGetDefault( PHB_ITEM pHash ); -extern HB_EXPORT void hb_hashSetFlags( PHB_ITEM pHash, int iFlags ); -extern HB_EXPORT void hb_hashClearFlags( PHB_ITEM pHash, int iFlags ); -extern HB_EXPORT int hb_hashGetFlags( PHB_ITEM pHash ); -extern HB_EXPORT void * hb_hashId( PHB_ITEM pHash ); /* retrieves the hash unique ID */ +extern HB_EXPORT PHB_ITEM hb_hashNew( PHB_ITEM pItem ); +extern HB_EXPORT HB_SIZE hb_hashLen( PHB_ITEM pHash ); +extern HB_EXPORT HB_BOOL hb_hashDel( PHB_ITEM pHash, PHB_ITEM pKey ); +extern HB_EXPORT HB_BOOL hb_hashAdd( PHB_ITEM pHash, PHB_ITEM pKey, PHB_ITEM pValue ); +extern HB_EXPORT HB_BOOL hb_hashAddNew( PHB_ITEM pHash, PHB_ITEM pKey, PHB_ITEM pValue ); +extern HB_EXPORT HB_BOOL hb_hashRemove( PHB_ITEM pHash, PHB_ITEM pItem ); +extern HB_EXPORT HB_BOOL hb_hashClear( PHB_ITEM pHash ); +extern HB_EXPORT HB_BOOL hb_hashAllocNewPair( PHB_ITEM pHash, PHB_ITEM * pKeyPtr, PHB_ITEM * pValPtr ); +extern HB_EXPORT void hb_hashSort( PHB_ITEM pHash ); +extern HB_EXPORT PHB_ITEM hb_hashClone( PHB_ITEM pHash ); +extern HB_EXPORT PHB_ITEM hb_hashCloneTo( PHB_ITEM pDest, PHB_ITEM pHash ); +extern HB_EXPORT void hb_hashJoin( PHB_ITEM pDest, PHB_ITEM pSource, int iType ); +extern HB_EXPORT HB_BOOL hb_hashScan( PHB_ITEM pHash, PHB_ITEM pKey, HB_SIZE * pnPos ); +extern HB_EXPORT HB_BOOL hb_hashScanSoft( PHB_ITEM pHash, PHB_ITEM pKey, HB_SIZE * pnPos ); +extern HB_EXPORT void hb_hashPreallocate( PHB_ITEM pHash, HB_SIZE nNewSize ); +extern HB_EXPORT PHB_ITEM hb_hashGetKeys( PHB_ITEM pHash ); +extern HB_EXPORT PHB_ITEM hb_hashGetValues( PHB_ITEM pHash ); +extern HB_EXPORT void hb_hashSetDefault( PHB_ITEM pHash, PHB_ITEM pValue ); +extern HB_EXPORT PHB_ITEM hb_hashGetDefault( PHB_ITEM pHash ); +extern HB_EXPORT void hb_hashSetFlags( PHB_ITEM pHash, int iFlags ); +extern HB_EXPORT void hb_hashClearFlags( PHB_ITEM pHash, int iFlags ); +extern HB_EXPORT int hb_hashGetFlags( PHB_ITEM pHash ); +extern HB_EXPORT void * hb_hashId( PHB_ITEM pHash ); /* retrieves the hash unique ID */ +extern HB_EXPORT HB_COUNTER hb_hashRefs( PHB_ITEM pHash ); /* retrieves numer of references to the hash */ /* these hb_hashGet*() functions are dangerous, be sure that base HASH value will not be changed */ -extern HB_EXPORT PHB_ITEM hb_hashGetItemPtr( PHB_ITEM pHash, PHB_ITEM pKey, int iFlags ); -extern HB_EXPORT PHB_ITEM hb_hashGetItemRefPtr( PHB_ITEM pHash, PHB_ITEM pKey ); -extern HB_EXPORT PHB_ITEM hb_hashGetCItemPtr( PHB_ITEM pHash, const char * pszKey ); -extern HB_EXPORT HB_SIZE hb_hashGetCItemPos( PHB_ITEM pHash, const char * pszKey ); -extern HB_EXPORT PHB_ITEM hb_hashGetKeyAt( PHB_ITEM pHash, HB_SIZE nPos ); -extern HB_EXPORT PHB_ITEM hb_hashGetValueAt( PHB_ITEM pHash, HB_SIZE nPos ); +extern HB_EXPORT PHB_ITEM hb_hashGetItemPtr( PHB_ITEM pHash, PHB_ITEM pKey, int iFlags ); +extern HB_EXPORT PHB_ITEM hb_hashGetItemRefPtr( PHB_ITEM pHash, PHB_ITEM pKey ); +extern HB_EXPORT PHB_ITEM hb_hashGetCItemPtr( PHB_ITEM pHash, const char * pszKey ); +extern HB_EXPORT HB_SIZE hb_hashGetCItemPos( PHB_ITEM pHash, const char * pszKey ); +extern HB_EXPORT PHB_ITEM hb_hashGetKeyAt( PHB_ITEM pHash, HB_SIZE nPos ); +extern HB_EXPORT PHB_ITEM hb_hashGetValueAt( PHB_ITEM pHash, HB_SIZE nPos ); -extern HB_EXPORT HB_BOOL hb_hashDelAt( PHB_ITEM pHash, HB_SIZE nPos ); +extern HB_EXPORT HB_BOOL hb_hashDelAt( PHB_ITEM pHash, HB_SIZE nPos ); /* hash item flags */ #define HB_HASH_AUTOADD_NEVER 0x00 @@ -1071,7 +1073,8 @@ extern HB_EXPORT void hb_winmainArgVFree( void ); #endif /* Codeblock management */ -extern HB_EXPORT void * hb_codeblockId( PHB_ITEM pItem ); /* retrieves the codeblock unique ID */ +extern HB_EXPORT void * hb_codeblockId( PHB_ITEM pItem ); /* retrieves the codeblock unique ID */ +extern HB_EXPORT HB_COUNTER hb_codeblockRefs( PHB_ITEM pItem ); /* retrieves numer of references to the codeblock */ extern PHB_CODEBLOCK hb_codeblockNew( const HB_BYTE * pBuffer, HB_USHORT uiLocals, const HB_BYTE * pLocalPosTable, PHB_SYMB pSymbols, HB_SIZE nLen ); /* create a code-block */ extern PHB_CODEBLOCK hb_codeblockMacroNew( const HB_BYTE * pBuffer, HB_SIZE nLen ); extern PHB_ITEM hb_codeblockGetVar( PHB_ITEM pItem, int iItemPos ); /* get local variable referenced in a codeblock */ diff --git a/src/harbour.def b/src/harbour.def index ccf9de7b20..5ae5fde085 100644 --- a/src/harbour.def +++ b/src/harbour.def @@ -1918,6 +1918,7 @@ HB_FUN___TRACEPRGCALLS HB_FUN___TYPEFILE HB_FUN___VMCOUNTTHREADS HB_FUN___VMITEMID +HB_FUN___VMITEMREFS HB_FUN___VMMODULESVERIFY HB_FUN___VMNOINTERNALS HB_FUN___WAIT @@ -2031,6 +2032,7 @@ hb_arrayIsObject hb_arrayLast hb_arrayLen hb_arrayNew +hb_arrayRefs hb_arrayRevScan hb_arrayScan hb_arraySelfParams @@ -2161,6 +2163,7 @@ hb_cmdargInit hb_cmdargIsInternal hb_cmdargProgName hb_codeblockId +hb_codeblockRefs hb_comClose hb_comDiscardChar hb_comErrorChar @@ -2702,6 +2705,7 @@ hb_hashJoin hb_hashLen hb_hashNew hb_hashPreallocate +hb_hashRefs hb_hashRemove hb_hashScan hb_hashScanSoft diff --git a/src/rtl/itemseri.c b/src/rtl/itemseri.c index e634e12ec9..7ca83467ce 100644 --- a/src/rtl/itemseri.c +++ b/src/rtl/itemseri.c @@ -296,6 +296,33 @@ static PHB_REF_ITEM hb_itemSerialOffsetFind( PHB_REF_LIST pRefList, HB_SIZE nOff return NULL; } +static PHB_REF_ITEM hb_itemSerialRefNew( PHB_REF_LIST pRefList, HB_SIZE nPos ) +{ + PHB_REF_ITEM pRef; + HB_SIZE nMove; + + if( pRefList->nCount >= pRefList->nSize ) + { + if( pRefList->nSize == 0 ) + pRefList->nSize = HB_SERIAL_REFLSTINIT; + else + pRefList->nSize += pRefList->nSize >> 1; + pRefList->pRefs = ( PHB_REF_ITEM ) + hb_xrealloc( pRefList->pRefs, + pRefList->nSize * sizeof( HB_REF_ITEM ) ); + } + + nMove = pRefList->nCount - nPos; + pRef = &pRefList->pRefs[ pRefList->nCount++ ]; + while( nMove-- > 0 ) + { + *pRef = *( pRef - 1 ); + pRef--; + } + + return pRef; +} + /* used by hb_itemSerialSize() for HB_IT_ARRAY and HB_IT_HASH */ static HB_BOOL hb_itemSerialValueRef( PHB_REF_LIST pRefList, void * value, HB_SIZE nOffset ) @@ -309,21 +336,7 @@ static HB_BOOL hb_itemSerialValueRef( PHB_REF_LIST pRefList, void * value, return HB_TRUE; } - if( pRefList->nCount >= pRefList->nSize ) - { - if( pRefList->nSize == 0 ) - pRefList->nSize = HB_SERIAL_REFLSTINIT; - else - pRefList->nSize += pRefList->nSize >> 1; - pRefList->pRefs = ( PHB_REF_ITEM ) - hb_xrealloc( pRefList->pRefs, - pRefList->nSize * sizeof( HB_REF_ITEM ) ); - } - - pRef = &pRefList->pRefs[ nPos ]; - if( nPos < pRefList->nCount ) - memmove( pRef + 1, pRef, ( pRefList->nCount - nPos ) * sizeof( HB_REF_ITEM ) ); - pRefList->nCount++; + pRef = hb_itemSerialRefNew( pRefList, nPos ); pRef->value = value; pRef->nOffset = nOffset; @@ -384,21 +397,7 @@ static HB_BOOL hb_itemSerialOffsetRef( PHB_REF_LIST pRefList, HB_SIZE nOffset ) if( hb_itemSerialOffsetFind( pRefList, nOffset, 0, &nPos ) != NULL ) return HB_TRUE; - if( pRefList->nCount >= pRefList->nSize ) - { - if( pRefList->nSize == 0 ) - pRefList->nSize = HB_SERIAL_REFLSTINIT; - else - pRefList->nSize += pRefList->nSize >> 1; - pRefList->pRefs = ( PHB_REF_ITEM ) - hb_xrealloc( pRefList->pRefs, - pRefList->nSize * sizeof( HB_REF_ITEM ) ); - } - - pRef = &pRefList->pRefs[ nPos ]; - if( nPos < pRefList->nCount ) - memmove( pRef + 1, pRef, ( pRefList->nCount - nPos ) * sizeof( HB_REF_ITEM ) ); - pRefList->nCount++; + pRef = hb_itemSerialRefNew( pRefList, nPos ); pRef->value = NULL; pRef->nOffset = nOffset; @@ -416,23 +415,7 @@ static void hb_itemSerialTypedRef( PHB_REF_LIST pRefList, int iType, if( hb_itemSerialOffsetFind( pRefList, nIndex, iType, &nPos ) == NULL ) { - PHB_REF_ITEM pRef; - - if( pRefList->nCount >= pRefList->nSize ) - { - if( pRefList->nSize == 0 ) - pRefList->nSize = HB_SERIAL_REFLSTINIT; - else - pRefList->nSize += pRefList->nSize >> 1; - pRefList->pRefs = ( PHB_REF_ITEM ) - hb_xrealloc( pRefList->pRefs, - pRefList->nSize * sizeof( HB_REF_ITEM ) ); - } - - pRef = &pRefList->pRefs[ nPos ]; - if( nPos < pRefList->nCount ) - memmove( pRef + 1, pRef, ( pRefList->nCount - nPos ) * sizeof( HB_REF_ITEM ) ); - pRefList->nCount++; + PHB_REF_ITEM pRef = hb_itemSerialRefNew( pRefList, nPos ); pRef->value = NULL; pRef->nOffset = nIndex; @@ -585,7 +568,7 @@ static HB_SIZE hb_itemSerialSize( PHB_ITEM pItem, int iFlags, if( szClass && szFunc ) nSize += strlen( szClass ) + strlen( szFunc ) + 3; } - if( ( iFlags & HB_SERIALIZE_IGNOREREF ) == 0 && + if( ( iFlags & HB_SERIALIZE_IGNOREREF ) == 0 && hb_arrayRefs( pItem ) > 1 && hb_itemSerialValueRef( pRefList, hb_arrayId( pItem ), nOffset + nSize ) ) { nSize = 5; @@ -606,7 +589,7 @@ static HB_SIZE hb_itemSerialSize( PHB_ITEM pItem, int iFlags, break; case HB_IT_HASH: - if( ( iFlags & HB_SERIALIZE_IGNOREREF ) == 0 && + if( ( iFlags & HB_SERIALIZE_IGNOREREF ) == 0 && hb_hashRefs( pItem ) > 1 && hb_itemSerialValueRef( pRefList, hb_hashId( pItem ), nOffset ) ) { nSize = 5; @@ -875,7 +858,9 @@ static HB_SIZE hb_serializeItem( PHB_ITEM pItem, HB_BOOL iFlags, break; case HB_IT_ARRAY: - if( hb_itemSerialValueOffset( pRefList, hb_arrayId( pItem ), nOffset, &nRef ) ) + nRef = HB_SERIAL_DUMMYOFFSET; + if( hb_arrayRefs( pItem ) > 1 && + hb_itemSerialValueOffset( pRefList, hb_arrayId( pItem ), nOffset, &nRef ) ) { pBuffer[ nOffset++ ] = HB_SERIAL_REF; HB_PUT_LE_UINT32( &pBuffer[ nOffset ], nRef ); @@ -927,7 +912,9 @@ static HB_SIZE hb_serializeItem( PHB_ITEM pItem, HB_BOOL iFlags, break; case HB_IT_HASH: - if( hb_itemSerialValueOffset( pRefList, hb_hashId( pItem ), nOffset, &nRef ) ) + nRef = HB_SERIAL_DUMMYOFFSET; + if( hb_hashRefs( pItem ) > 1 && + hb_itemSerialValueOffset( pRefList, hb_hashId( pItem ), nOffset, &nRef ) ) { pBuffer[ nOffset++ ] = HB_SERIAL_REF; HB_PUT_LE_UINT32( &pBuffer[ nOffset ], nRef ); diff --git a/src/vm/arrays.c b/src/vm/arrays.c index d4390a62ef..a19af5c7b9 100644 --- a/src/vm/arrays.c +++ b/src/vm/arrays.c @@ -300,6 +300,15 @@ void * hb_arrayId( PHB_ITEM pArray ) return NULL; } +/* retrieves numer of references to the array */ +HB_COUNTER hb_arrayRefs( PHB_ITEM pArray ) +{ + if( pArray && HB_IS_ARRAY( pArray ) ) + return hb_gcRefCount( pArray->item.asArray.value ); + else + return 0; +} + PHB_ITEM hb_arrayFromId( PHB_ITEM pItem, void * pArrayId ) { HB_STACK_TLS_PRELOAD diff --git a/src/vm/codebloc.c b/src/vm/codebloc.c index 10270b068f..2ac7354df8 100644 --- a/src/vm/codebloc.c +++ b/src/vm/codebloc.c @@ -293,3 +293,12 @@ void * hb_codeblockId( PHB_ITEM pItem ) else return NULL; } + +/* retrieves numer of references to the codeblock */ +HB_COUNTER hb_codeblockRefs( PHB_ITEM pItem ) +{ + if( HB_IS_BLOCK( pItem ) ) + return hb_gcRefCount( pItem->item.asBlock.value ); + else + return 0; +} diff --git a/src/vm/hashes.c b/src/vm/hashes.c index 54ac88e9e1..06f34c9523 100644 --- a/src/vm/hashes.c +++ b/src/vm/hashes.c @@ -946,6 +946,15 @@ void * hb_hashId( PHB_ITEM pHash ) return NULL; } +/* retrieves numer of references to the hash */ +HB_COUNTER hb_hashRefs( PHB_ITEM pHash ) +{ + if( HB_IS_HASH( pHash ) ) + return hb_gcRefCount( pHash->item.asHash.value ); + else + return 0; +} + void hb_hashCloneBody( PHB_ITEM pDest, PHB_ITEM pHash, PHB_NESTED_CLONED pClonedList ) { HB_SIZE nPos; diff --git a/src/vm/hvm.c b/src/vm/hvm.c index 8a4b7801f6..fcf29600e0 100644 --- a/src/vm/hvm.c +++ b/src/vm/hvm.c @@ -12421,6 +12421,27 @@ HB_FUNC( __VMITEMID ) } } +HB_FUNC( __VMITEMREFS ) +{ + HB_STACK_TLS_PRELOAD + + PHB_ITEM pItem = hb_param( 1, HB_IT_ANY ); + + if( pItem ) + { + if( HB_IS_ARRAY( pItem ) ) + hb_retnint( hb_arrayRefs( pItem ) ); + else if( HB_IS_HASH( pItem ) ) + hb_retnint( hb_hashRefs( pItem ) ); + else if( HB_IS_BLOCK( pItem ) ) + hb_retnint( hb_codeblockRefs( pItem ) ); + else if( HB_IS_POINTER( pItem ) ) + hb_retnint( hb_gcRefCount( pItem->item.asPointer.value ) ); + else if( HB_IS_STRING( pItem ) ) + hb_retnint( hb_xRefCount( pItem->item.asString.value ) ); + } +} + HB_FUNC( __VMMODULESVERIFY ) { HB_STACK_TLS_PRELOAD