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