Files
harbour-core/harbour/contrib/hbnf/fttext.c
Viktor Szakats df2b7a9ebd 2012-10-31 13:25 UTC+0200 Viktor Szakats (harbour syenar.net)
* include/harbour.hbx
    * fixes/changes to some function names

  * config/hb_c.cfg
    + updated to do better vertical aligment in
      structs, var declarations and assignments
    ; TODO: move this to /bin folder and add to 'install'-ed
            file list, rename to 'harbour.ucf'

  * src/debug/*.prg
  * src/rdd/*.prg
  * src/rdd/hbsix/*.prg
  * src/rdd/usrrdd/rdds/*.prg
  * src/rtl/*.prg
  * src/vm/*.prg
  * utils/hbi18n/hbi18n.prg
  * utils/hbmk2/hbmk2.prg
  * utils/hbmk2/examples/*.hb
  * contrib/hbblat/blatcls.prg
  * contrib/gtwvg/*.prg
  * contrib/gtwvg/tests/*.prg
  * contrib/hbblink/*.prg
  * contrib/hbcairo/tests/*.prg
  * contrib/hbcomm/*.prg
  * contrib/hbcomm/tests/*.prg
  * contrib/hbcups/tests/*.prg
  * contrib/hbcurl/tests/*.prg
  * contrib/hbexpat/*.prg
  * contrib/hbexpat/tests/*.prg
  * contrib/hbfbird/*.prg
  * contrib/hbfbird/tests/*.prg
  * contrib/hbfoxpro/*.prg
  * contrib/hbfship/*.prg
  * contrib/hbgd/*.prg
  * contrib/hbgd/tests/*.prg
  * contrib/hbgs/tests/*.prg
  * contrib/hbhpdf/*.prg
  * contrib/hbhpdf/tests/*.prg
  * contrib/hbhttpd/*.prg
  * contrib/hbhttpd/tests/*.prg
  * contrib/hblzf/tests/*.prg
  * contrib/hbmagic/tests/*.prg
  * contrib/hbmisc/*.prg
  * contrib/hbmisc/tests/*.prg
  * contrib/hbct/*.prg
  * contrib/hbct/tests/*.prg
  * contrib/hbmlzo/tests/*.prg
  * contrib/hbmxml/*.prg
  * contrib/hbmxml/tests/*.prg
  * contrib/hbmysql/*.prg
  * contrib/hbmysql/tests/*.prg
  * contrib/hboslib/*.prg
  * contrib/hbsms/*.prg
  * contrib/hbtinymt/tests/*.prg
  * contrib/hbtpathy/*.prg
  * contrib/hbtpathy/tests/*.prg
  * contrib/hbunix/tests/*.prg
  * contrib/hbxdiff/tests/*.prg
  * contrib/hbzebra/tests/*.prg
  * contrib/hbziparc/*.prg
  * contrib/hbziparc/tests/*.prg
  * contrib/rddads/*.prg
  * contrib/rddads/tests/*.prg
  * contrib/hbodbc/*.prg
  * contrib/hbodbc/tests/*.prg
  * contrib/hbpgsql/*.prg
  * contrib/hbpgsql/tests/*.prg
  * contrib/hbsqlit3/*.prg
  * contrib/hbsqlit3/tests/*.prg
  * contrib/hbwin/*.prg
  * contrib/hbwin/tests/*.prg
  * contrib/hbxpp/*.prg
  * contrib/hbxpp/tests/*.prg
  * contrib/hbxhb/*.prg
  * contrib/hbxhb/tests/*.prg
  * contrib/hbnetio/*.prg
  * contrib/hbnetio/utils/hbnetio/*.hb
  * contrib/hbnetio/utils/hbnetio/*.prg
  * contrib/hbtip/*.prg
  * contrib/hbtip/tests/*.prg
  * tests/usrrdd/*.prg
  * tests/funcarr.prg
  * extras/gfspell/spell.prg
  * extras/gtwvw/tests/*.prg
  * extras/guestbk/*.prg
  * extras/hbdoc/*.prg
  * extras/rddado/*.prg
  * extras/rddado/tests/*.prg
  * extras/hbxlsxml/*.prg
  * extras/httpsrv/*.prg
  * extras/httpsrv/modules/*.prg
  * extras/hbsuper/*.prg
  * extras/hbvpdf/*.prg
  * extras/hbvpdf/tests/*.prg
  * tests/*.prg (except some which are well formatted but in different/fast-typing style)
  * tests/*.hb
  * bin/*.hb
  * contrib/*.hb
  * config/*.hb
    * some manual formatting to better be able to verify
      changes made by hbformat and be friendlier with hbformat.
    * most files reformatted with hbformat using Maurizio's
      patch, with mostly minor manual corrections and verification.
      All hbformat changes for revised one-by-one.
    ! __DIR(): fixed to be unicode compatible
    ! __hbdoc_ToSource(): make sure to not generate line ending
      spaces in output.
    + hbmk2/hbrun: HBMK_WITH_GTXWC built-time option to include
      GTXWC. Useful for hbrun.
    * hbct tests: change to not use [] as string delimiter
    + added full prototypes to Array class declaration

  ; NOTE: Only these were not or not fully formatted:
          contrib/hbnetio/tests/*.prg
          tests/hbpptest/*.prg
          tests/mt/*.prg
          tests/multifnc/*.prg
          tests/rddtest/*.prg
          utils/hbmk2/hbmk2.prg (for the most part)
          src/rtl/tbrowse.prg (for the most part)
          utils/hbtest/*.prg
          *.ch, *.c, *.h

  * src/rtl/cdpapihb.c
  * src/rtl/hbadler.c
  * src/rtl/hbsocket.c
  * src/rtl/sha1.c
  * src/vm/classes.c
  * src/vm/dynsym.c
  * src/vm/garbage.c
  * src/debug/dbgentry.c
    * do not end macros with ';' to avoid uncrustify warning
      and wrong formatting as a consequence

  * src/compiler/cmdcheck.c
    * minor changes for uncrustify-friendliness

  * contrib/hbformat/utils/hbfmtcls.prg
  * contrib/hbformat/utils/hbformat.prg
    % optimizations in hbformat.prg
    ! fixed mask/filename handling to be
      multiplatform in hbformat.prg
    + added 'HBXList=' hbformat.ini parameter allowing
      to add any .hbx file for proper function name
      casing.
    ! fixed progress bar to display correctly

  * tests/speedstr.prg
    ! fixed to run as intended in unicode code
    * hbformatted

  - contrib/hbwin/tests/dlg.xml
  * contrib/hbwin/tests/dlg.rc
  - extras/gtwvw/tests/wvwtest9.xml
  + extras/gtwvw/tests/wvwtest9.mft
  * extras/gtwvw/tests/wvwtest9.rc
    * renamed manifest to have .mft extension
    % deleted unnecessary manifest
    * "Win32 API" -> "Windows API"
    ! deleted CPU arch from manifest

  * package/harb_win.mft
    * formatting

  * src/common/hbver.c
    + added version detection for win 8 and win server 2012
    * minor formatting/code cleanup

  * tests/gfx.prg
    * updated to run in script mode.
    ; TOFIX: it doesn't draw anything with GTWVT

  * tests/gfx.prg
  * tests/gtwin.prg
  * tests/gtxfnt.prg
  * tests/wvt_fs.prg
  * tests/wvtext.prg
    + support for GTXWC when run as script

  * doc/en/*.txt
  * contrib/hbct/doc/en/*.txt
  * contrib/hbgd/doc/en/*.txt
  * contrib/hbgt/doc/en/*.txt
  * contrib/hbmisc/doc/en/*.txt
  * contrib/hbnf/doc/en/*.txt
  * contrib/hbziparc/doc/en/*.txt
  * contrib/rddads/doc/en/*.txt
    ! fixed few broken tags reported by Carlos
    % deleted line ending spaces
    * some minor formatting

  * contrib/hbnf/*.c
  * contrib/hbnf/*.h
  * extras/gfspell/spellc.c
    * uncrustified with updated hb_c.cfg

  * contrib/hbnf/*.prg
  * contrib/hbnf/tests/*.prg
    * hbformatted with Mauriozo's patch.
    * a few manual corrections (avoiding #translates, using hb_ColorIndex())
      in general and to make hbformat happy.

  + contrib/hbnf/tests/menuto.prg
    + added sample code for MENU TO (adatped from docs)

  - src/rdd/dbfntx/dbfntx0.prg
    - deleted unused file with no enabled code in it

  * contrib/hbtip/tests/dbtohtml.prg
  * contrib/hbtip/tests/loadhtml.prg
  * contrib/hbtip/tests/tipmmail.prg
    * minor cleanups

  * contrib/hbtip/thtml.prg
    ! fixed typo due to s&r
    % use hb_memowrit()

  * src/rtl/tbrowse.prg
    * conditional code sorted to be hbformat friendly
    * some formatting

  * INSTALL
  * package/harbour.rb
  * package/mpkg_src_nightly.sh
  * package/mpkg_win_nightly.bat
  * package/updt_web_nightly.sh
  * website/changelog.html
  * website/faq/harbour17.html
  * website/faq/harbour27.html
  * website/index.html
  * website/menu/harbour-menu.js
    * updated repository URL to new sf.net one

  * tests/function.cfm
  * contrib/hbhttpd/tests/tpl/_main.tpl
  * contrib/hbtip/tests/tipmmail.prg
  * website/faq/*.html
  * website/samples/*.html
    * use utf-8 in html and email

  * contrib/hbrun/hbrun.hbp
    + support for HBMK_WITH_GTXWC

  * tests/rto_get.prg
  * tests/onidle.prg
  * tests/mousetst.prg
  * tests/wcecon.prg
  * tests/vmasort.prg
  - contrib/hbnf/tests/metaph.prg
    * minor cleanups

  * contrib/hbmysql/tests/test.prg
  * contrib/hbmysql/tests/dbf2mysq.prg
    % minor optimization, deleted outdated comment/line

  * src/compiler/harbour.yyc
  * src/compiler/harbour.y
    * minor formatting
2012-10-31 13:04:01 +00:00

1085 lines
33 KiB
C

/*
* $Id$
*/
/*
* Author....: Brice de Ganahl and Steve Larsen
* CIS ID....: 76370,1532
*
* This is an original work by Brice de Ganahl and Steve Larsen
* and is placed in the public domain.
*
* Doc headers by Glenn Scott, Don Caton, and Steve Larsen
*
* Extensively revised by Steve Larsen
*
* Modification history:
* ---------------------
*
* Rev 1.8 01 May 1995 04:36:22 TED
* Major overhaul by Steve Larsen to fix several bugs/quirkiness,
* add some requested features, clean up source for readability.
*
* - Added ft_fError() test
* - Added ft_fBOF() test
* - Provided protected mode compatibility
* - Increased buffer to 4k, added logic to allow lines longer than
* the buffer size.
* - Revised seek logic
* - Changed undocumented calls to API functions wherever possible
*
*
* Rev 1.7 17 Oct 1992 16:25:16 GLENN
* Leo cleaned up the documentation, including an errant SEEALSO
* reference.
*
* Rev 1.6 03 Oct 1992 02:07:38 GLENN
* Minor adjustments to file header block.
*
* Rev 1.5 03 Oct 1992 02:03:44 GLENN
* Major modifications by Steve Larsen, as follows:
*
* Brice laid some wonderful groundwork with his initial release of
* these functions, however I needed more capability. With his per-
* mission, I have made the following additions/changes to Rev. 1.4:
*
* - Eliminated the problem of memory for buffers being re-allocated every
* time a file got used.
* - Further reduced memory impact by converting from extend system memory
* allocation techniques to virtual memory. To accomplish this, we
* use the Clipper v5.01 r1.29 variants of the "_v" undocumented
* internal functions. If these functions change in future releases, you
* will need to locate them herein and make the appropriate changes.
*
* NOTE: these functions allocate and deallocate virtual memory on an
* "as-needed" basis. If your application makes heavy and frequent use
* of those functions that perform a lot of buffering (ft_fInsert(),
* ft_fDelete() and ft_fWrite()), you might consider modifying the memory
* management scheme used herein, that is, allocate the required buffers
* only once upon the first call to these functions, then recycle them.
* - Added the ability to specify file open mode.
* - Added a function to write to a record, which through a switch can either
* over-write the current record, or insert a new one.
* - Added functions to insert, delete and append a specified number of lines.
* - Fixed the existing functions so that they properly handle "trailers",
* that is, a case where the last chars in a file are not CRLF delimited.
* - Provided checking for the possibility that the file might be terminated
* with ^Z (1Ah), if so, ignoring it (providing consistency with non-^Z
* terminated files). This only occurs on the last record of a file.
* - Eliminated a potential problem if one were to issue an ft_fUse() prior
* actually opening any files.
* - Replaced the original C parsing logic to determine the end-of-line (CRLF)
* with an optimized assembler routine. This bypassed a significant
* performance hit.
* - The original header (FTTEXT.h) file in now incorporated in this one file.
* This is not necessarily an enhancement, more like laziness.
* - Provided the (followup) author with his very first C experience!
*
* Steve Larsen, Dec. 7, 1991 CIS 76370,1532
*
* - Function changes/additions (refer to the individual doc headers for
* details):
*
* FT_FSELECT( [ <nArea > ] ) -> nArea
* FT_FUSE( [ <cFile> ][, <nMode> ] ) -> nHandle | NIL
* FT_FWRITELN( <cData> [, <lInsert> ] ) -> NIL
* FT_FINSERT( [ <nLines> ] ) -> NIL
* FT_FDELETE( [ <nLines> ] ) -> NIL
* FT_FAPPEND( [ <nLines> ] ) -> NIL
*
* Internal Steve Larsen revisions:
*
* 12/07/91 Original rework
* 02/13/92 Fixed _findeol(), FT_FREADLN() and FT_FGOBOT() to
* better handle files with CRLF, LF, ^Z or nothing
* at the EOF. Previously, under some conditions the
* last record was chopped by a character, depending
* on the last character(s).
* 05/02/92 Fixed buffering and VMM allocation problem with
* FT_FGOBOT().
* 08/26/92 Correcting problem when appending blank lines to an
* empty file (ft_fAppend() and ft_fWriteLn()).
*
*
* Rev 1.4 17 Aug 1991 15:31:08 GLENN
* Don Caton fixed some spelling errors in the doc
*
* Rev 1.3 15 Aug 1991 23:08:36 GLENN
* Forest Belt proofread/edited/cleaned up doc
*
* Rev 1.2 29 Apr 1991 08:02:12 GLENN
* Minor adjustments to documentation block
*
* Rev 1.1 29 Apr 1991 08:00:26 GLENN
* ft_flastrec() -- name was longer than 10 characters so linkers couldn't
* find the symbol. Just hacked off the last "c" so it is really
* ft_flastre(). Sorry, folks. -- Glenn
*
* Rev 1.0 01 Apr 1991 01:02:48 GLENN
* Nanforum Toolkit
*
*/
/*
* The following parts are Copyright of the individual authors.
* www - http://harbour-project.org
*
* Copyright 1999-2008 Viktor Szakats (harbour syenar.net)
* _findeol(), _findbol()
*
* See COPYING for licensing terms.
*
*/
/*
Some sample Clipper code which would use these functions is listed
below. It will print out the contents of this file.
ft_fuse( "text.c" )
DO WHILE ! ft_feof()
? ft_freadln()
ft_fskip()
ENDDO
ft_fuse()
*/
/* up this number if you need more than 10 text file areas */
#define TEXT_WORKAREAS 10
/* raise or lower this number for best performance on your system
(larger for dealing with large files or long records, smaller for
faster reads) */
#define BUFFSIZE 4096
#include "hbapi.h"
#include "hbapifs.h"
#include "hbstack.h"
/* MSC compiler switch */
#if defined( _MSC_VER )
#pragma warning( disable : 4035 )
#pragma warning( disable : 4704 )
#endif
typedef struct
{
int area;
/* arrays used by the text workareas */
long recno[ TEXT_WORKAREAS ];
HB_FOFFSET offset[ TEXT_WORKAREAS ];
HB_FHANDLE handles[ TEXT_WORKAREAS ];
long last_rec[ TEXT_WORKAREAS ];
HB_FOFFSET last_off[ TEXT_WORKAREAS ];
HB_FOFFSET lastbyte[ TEXT_WORKAREAS ];
HB_BOOL isBof[ TEXT_WORKAREAS ];
HB_BOOL isEof[ TEXT_WORKAREAS ];
HB_ERRCODE error[ TEXT_WORKAREAS ];
} FT_TEXT, * PFT_TEXT;
static void s_fttext_init_init( void * cargo )
{
PFT_TEXT ft_text = ( PFT_TEXT ) cargo;
ft_text->area = 0;
}
static HB_TSD_NEW( s_fttext, sizeof( FT_TEXT ), s_fttext_init_init, NULL );
/* routines internal to this module */
static HB_ISIZ _findeol( char * buf, HB_ISIZ buf_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_fttext );
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_fttext );
int attr = hb_parnidef( 2, FO_READWRITE | FO_DENYNONE );
ft_text->error[ ft_text->area ] = 0;
if( HB_ISCHAR( 1 ) )
{
ft_text->handles[ ft_text->area ] = hb_fsOpen( hb_parc( 1 ), ( HB_USHORT ) attr );
if( ft_text->handles[ ft_text->area ] <= 0 )
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_fttext );
int oldarea = ft_text->area + 1;
int newArea;
if( HB_ISNUM( 1 ) )
{
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_fttext );
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_fttext );
hb_retni( ft_text->error[ ft_text->area ] );
}
HB_FUNC( FT_FRECNO )
{
PFT_TEXT ft_text = ( PFT_TEXT ) hb_stackGetTSD( &s_fttext );
hb_retnl( ft_text->recno[ ft_text->area ] );
}
HB_FUNC( FT_FGOBOT )
{
PFT_TEXT ft_text = ( PFT_TEXT ) hb_stackGetTSD( &s_fttext );
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_fttext );
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 );
if( iByteCount > 0 && iByteCount != iBytesRemaining )
{
/* found a CRLF, 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 CRLFs in this buffer, or CRLF 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
CRLF 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 a CRLF, 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 CRLFs 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_fttext );
HB_ISIZ iByteCount;
HB_ISIZ iBytesRead;
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 );
if( iByteCount )
hb_retclen( cPtr, iByteCount - 2 );
else
hb_retclen( cPtr, iBytesRead );
hb_xfree( cPtr );
}
HB_FUNC( FT_FDELETE )
{
PFT_TEXT ft_text = ( PFT_TEXT ) hb_stackGetTSD( &s_fttext );
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_fttext );
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_fttext );
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 CRLF pair exists, if not, add one */
/* get count of chars in this line */
iByteCount = _findeol( buff, iRead );
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 );
/* no_lines--; !Harbour FIX! */
}
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_fttext );
const char * theData = hb_parc( 1 );
HB_ISIZ iDataLen = hb_parclen( 1 );
HB_BOOL bInsert = hb_parl( 2 );
int err;
HB_ISIZ iLineLen = 0;
HB_ISIZ iRead, iEOL;
char * buffer;
/* 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 + crlf */
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 */
buffer = ( char * ) hb_xgrab( BUFFSIZE );
/* 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 );
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_fttext );
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_fttext );
hb_retl( ft_text->isEof[ ft_text->area ] );
}
HB_FUNC( FT_FBOF )
{
PFT_TEXT ft_text = ( PFT_TEXT ) hb_stackGetTSD( &s_fttext );
hb_retl( ft_text->isBof[ ft_text->area ] );
}
HB_FUNC( FT_FGOTO )
{
PFT_TEXT ft_text = ( PFT_TEXT ) hb_stackGetTSD( &s_fttext );
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 a CRLF pair
Returns count to first character _after_ next
CRLF pair (beginning of next line). Current line
will contain the trailing CRLF. 1Ah and trailing
LFs will be ignored (included in count).
If no CRLF found return is zero. (could mean EOF or
line is longer than buffer end)
*/
static HB_ISIZ _findeol( char * buf, HB_ISIZ buf_len )
{
HB_ISIZ tmp;
for( tmp = 0; tmp < buf_len; tmp++ )
{
if( buf[ tmp ] == FT_CHR_CR && buf[ tmp + 1 ] == FT_CHR_LF )
return tmp + 2;
else if( buf[ tmp ] == FT_CHR_LF )
return tmp + 1;
}
return 0;
}
/*----------------------------------------------------------------------
In-line assembler routine to parse a buffer
for a CRLF pair
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 CRLF pair (beginning of line).
*/
static HB_ISIZ _findbol( char * buf, HB_ISIZ buf_len )
{
HB_ISIZ tmp = buf_len - 1;
if( tmp != 0 )
{
char * p = buf - 1;
char b = *p;
if( b == FT_CHR_EOF )
{
p--;
tmp--;
if( tmp == 0 )
return buf_len;
}
if( b == FT_CHR_LF )
{
p--;
tmp--;
if( tmp == 0 )
return buf_len;
if( *p == FT_CHR_CR )
{
p--;
tmp--;
if( tmp == 0 )
return buf_len;
}
}
for(; tmp > 0; tmp--, p-- )
{
if( *p == FT_CHR_LF && *( p - 1 ) == FT_CHR_CR )
return buf_len - ( tmp + 2 ) + 1;
else if( *p == FT_CHR_LF )
return buf_len - ( tmp + 1 ) + 1;
}
}
return buf_len;
}
/*--------------------------------------------------------------------------*/
/* 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 */
static int _ins_buff( PFT_TEXT ft_text, HB_ISIZ iLen )
{
char * ReadBuff = ( char * ) hb_xgrab( BUFFSIZE );
char * WriteBuff = ( char * ) hb_xgrab( BUFFSIZE );
char * SaveBuff;
HB_FOFFSET fpRead, fpWrite;
HB_ISIZ WriteLen, ReadLen;
HB_ISIZ SaveLen;
HB_ISIZ iLenRemaining = iLen;
/* set target move distance, this allows iLen to be greater than
BUFFSIZE */
iLen = HB_MIN( iLenRemaining, BUFFSIZE );
iLenRemaining -= iLen;
/* initialize file pointers */
fpRead = ft_text->offset[ ft_text->area ];
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 );
fpRead += WriteLen;
ReadLen = hb_fsRead( ft_text->handles[ ft_text->area ], ReadBuff, BUFFSIZE );
fpRead += ReadLen;
ft_text->error[ ft_text->area ] = 0;
while( ! ft_text->error[ ft_text->area ] && iLen > 0 )
{
while( WriteLen > 0 )
{
/* position to beginning of write area */
if( hb_fsSeekLarge( 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 )
{
ft_text->error[ ft_text->area ] = hb_fsError();
break;
}
/* move write pointer */
fpWrite += SaveLen;
if( SaveLen != WriteLen )
{
/* error, fetch errcode and quit */
ft_text->error[ ft_text->area ] = hb_fsError();
break;
}
/* WriteLen = SaveLen; */
/* swap buffers */
SaveBuff = WriteBuff;
WriteBuff = ReadBuff;
ReadBuff = SaveBuff;
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 );
fpRead += ReadLen;
}
iLen = HB_MIN( iLenRemaining, BUFFSIZE );
iLenRemaining -= 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 );
/* 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 );
hb_xfree( ReadBuff );
hb_xfree( WriteBuff );
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 );
fpRead += WriteLen;
ft_text->error[ ft_text->area ] = 0;
while( WriteLen > 0 )
{
/* 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 );
/* move write pointer */
fpWrite += SaveLen;
if( SaveLen != WriteLen )
{
/* error, fetch errcode and quit */
ft_text->error[ ft_text->area ] = hb_fsError();
break;
}
/* 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 );
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 );
/* 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 );
hb_xfree( WriteBuff );
return ft_text->error[ ft_text->area ];
}
/*--------------------------------------------------------------------------*/
/* writes a line of data to the file, including the terminating CRLF */
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 )
{
const char * crlf = hb_conNewLine();
HB_SIZE len = strlen( crlf );
return hb_fsWriteLarge( fhnd, crlf, len ) == len;
}