home *** CD-ROM | disk | FTP | other *** search
- /*
- * File......: TEXT.C
- * Author....: Brice de Ganahl and Steve Larsen
- * CIS ID....: 76370,1532
- * Date......: $Date: 15 Dec 1992 00:20:20 $
- * Revision..: $Revision: 1.8 $
- * Log file..: $Logfile: C:/nanfor/src/fttext.c_v $
- *
- * 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:
- * ---------------------
- *
- * $Log: C:/nanfor/src/fttext.c_v $
- *
- * Rev 1.8 15 Dec 1992 00:20:20 GLENN
- * Corrected bad casts from long to ints.
- * Added return value to ft_fskip() (via Glenn Belton)
- *
- *
- * 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()).
- * 12/06/92 Corrected bad casts from long to ints, added return value
- * to ft_fSkip()
- *
- * 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
- *
- */
-
- /* Notes:
-
- The Clipper internal functions used seem to be stable across
- versions but nothing is guaranteed. These functions begin
- with _t, are used for file I/O, and are compatible with their
- ANSI counterparts (just strip the _t and you have the ANSI name).
- See text.h for the prototypes.
-
- This revision utilizes the in-line assembler feature found in MSC
- 6.0. If compiling with TurboC substitute "_asm" with "asm".
-
- I compile these functions with the following MicroSoft C parameters:
-
- cl /c /AL /Od /Zl /Zi /FPa /Gs /W3 text.c
-
- Note that the /Od defeats optimization and is necessary only for
- compatibility with Blinker, Warplink, etc. If you are not overlaying
- this code you may want to change this to /Oalt. Likewise, the
- /Zi is for symbolic debugging info which you will want to omit in
- any final compiles.
-
- 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
-
- #include "extend.h"
- #include "stdio.h"
- #include "share.h"
- #include "fcntl.h"
-
- #define b_size 1024
- #define c_size 4096
-
- #ifndef SIZE_T
- #define SIZE_T
- typedef unsigned int size_t;
- #endif
-
- void pascal ft_fseek( void );
- void pascal ft_fuse( void );
- void pascal ft_fselect( void );
- void pascal ft_fgotop( void );
- void pascal ft_frecno( void );
- void pascal ft_fgobot( void );
- void pascal ft_fskip( void );
- void pascal ft_freadln( void );
- void pascal ft_flastre( void );
- void pascal ft_feof( void );
- void pascal ft_fgoto( void );
- void pascal ft_fwritel( void );
- void pascal ft_fdelete( void );
- void pascal ft_fappend( void );
-
- int _findeol( char *buf, int buf_len ); /* in-line ASM */
- int _findbol( char *buf, int buf_len ); /* in-line ASM */
- /*void _ftwrite( char *buf, int insert ); (replaced below) */
- long _filewrite( long read1, long read2, long end1, long end2,
- char *c, char *c2 );
-
- long _ft_skip( int recs );
-
- extern int _tclose( int );
- extern int _tcreat( char*, int );
- extern int _terror;
- extern long _tlseek( int, long, int );
- extern int _topen( char*, int );
- extern int _tread( int, char*, int );
- extern int _twrite( int, char*, int );
- extern int _tcommit( int );
- /* extern int strlen( char* ); */
- extern int _vAlloc( int, int );
- extern char *_vLock( int );
- extern void _vUnLock( int );
- extern void _vFree( int );
-
- static long recno[TEXT_WORKAREAS];
- static long offset[TEXT_WORKAREAS];
- static int handles[TEXT_WORKAREAS];
- static int area = 0;
- static long last_rec[TEXT_WORKAREAS];
- static long last_off[TEXT_WORKAREAS];
- static long lastbyte[TEXT_WORKAREAS];
- static int isEof[TEXT_WORKAREAS];
-
-
- /* $DOC$
- * $FUNCNAME$
- * FT_FUSE()
- * $CATEGORY$
- * File I/O
- * $ONELINER$
- * Open or close a text file for use by the FT_F* functions
- * $SYNTAX$
- * FT_FUSE( [ <cFile> ] [, <nMode> ] ) -> nHandle | NIL
- * $ARGUMENTS$
- * <cFile> is the text file you want to open. If not specified,
- * the file currently open, if any, will be closed.
- *
- * <nMode> is the open mode for the file. Please refer to the
- * discussion of open modes under FOPEN() in the Clipper manual
- * and FILEIO.CH for a list of allowable open modes. If not
- * specified, the file will be opened with a mode of
- * FO_READ + FO_SHARED (64).
- *
- * $RETURNS$
- * If <cFile> is passed and the file is opened successfully, an
- * integer containing the file handle. If the file cannot be
- * opened, -1 will be returned.
- *
- * If FT_FUSE() is called without any arguments, it will close the
- * text file in the current "text area" and return NIL.
- * $DESCRIPTION$
- * The FT_F*() file functions are for reading text files, that is,
- * files where each line (record) is delimited by a CRLF pair.
- *
- * Each file is opened in its own "workarea", similar to the concept
- * use by dbf files. As provided, a maximum of 10 files (in 10
- * workareas) can be opened (assuming there are sufficient file
- * handles available). That number may be increased by modifying
- * the #define TEXT_WORKAREAS in the C source code and recompiling.
- * $EXAMPLES$
- * FT_FUSE( "text.c" ) // open text file
- * DO WHILE !FT_FEOF()
- * ? FT_FREADLN()
- * FT_FSKIP()
- * ENDDO
- * FT_FUSE() // close file
- * $SEEALSO$
- * FT_FUSE() FT_FSELECT()
- * $END$
- */
-
- void pascal ft_fuse()
- {
- int attr = ISNUM( 2 ) ? _parni(2) : O_RDONLY|SH_DENYNO|O_BINARY ;
-
- if ( ISCHAR(1) ) {
- handles[area] = _topen( _parc(1), attr ) ;
-
- offset[area] = 0 ;
- recno[area] = 1;
- lastbyte[area] = _tlseek( handles[area], 0L, SEEK_END );
- _retni( handles[area] );
- }
- else {
- if ( handles[area] != 0 ) {
- _tclose( handles[area] );
- _retni(1);
- recno[area] = 0L;
- offset[area] = 0L;
- handles[area] = 0;
- last_rec[area] = 0L;
- last_off[area] = 0L;
- lastbyte[area] = 0L;
- isEof[area] = 0;
- }
- }
- }
-
-
- /* $DOC$
- * $FUNCNAME$
- * FT_FSELECT()
- * $CATEGORY$
- * File I/O
- * $ONELINER$
- * Select a text file workarea
- * $SYNTAX$
- * FT_FSELECT( [ <nArea> ] ) -> nArea
- * $ARGUMENTS$
- * <nArea> is the text file workarea to select.
- * $RETURNS$
- * The current selected text file area.
- *
- * $DESCRIPTION$
- * This function selects a text file "workarea" from 1 to 10. A
- * file may or may not be open in the selected area.
- *
- * Passing 0 for <nArea> selects the next available workarea, similar
- * to Clipper's SELECT 0 command.
- *
- * Each file is opened in its own "workarea", similar to the concept
- * used by dbf files. As provided, a maximum of 10 files (in 10
- * workareas) can be opened (assuming there are sufficient file
- * handles available). That number may be increased by modifying
- * the #define TEXT_WORKAREAS in the C source code and recompiling.
- *
- * All the FT_F*() file functions operate on the file in the currently
- * selected text file workarea.
- *
- * Text file workareas are separate from and independent of Clipper's
- * database workareas.
- * $EXAMPLES$
- * FT_FSELECT(1)
- * nFile1 := FT_FUSE( "temp.c" )
- * ? FT_FLASTREC() // no. of lines in temp.c
- * FT_FSELECT(2)
- * nFile2 := FT_FUSE( "temp.h" )
- * ? FT_FLASTREC() // no. of lines in temp.h
- * $SEEALSO$
- * FT_FUSE()
- * $END$
- */
-
- void pascal ft_fselect()
- {
- if ( ISNUM(1) ) {
- area = _parni(1) - 1;
- if ( area == -1 ) {
- for ( area = 0; area < TEXT_WORKAREAS - 1; area++ ) {
- if ( handles[area] == 0 ) {
- break;
- }
- }
- }
- }
- _retni( area + 1 );
- }
-
- /* $DOC$
- * $FUNCNAME$
- * FT_FGOTOP()
- * $CATEGORY$
- * File I/O
- * $ONELINER$
- * Go to the first record in a text file
- * $SYNTAX$
- * FT_FGOTOP() -> NIL
- * $ARGUMENTS$
- * None
- * $RETURNS$
- * NIL
- * $DESCRIPTION$
- * This function moves the record pointer to the first record
- * in the currently selected text file workarea.
- *
- * A text file "record" is a line of text terminated by a CRLF pair.
- * $EXAMPLES$
- * FT_FUSE( "text.c" ) // open text file
- * DO WHILE !FT_FEOF()
- * ? FT_FREADLN() // read thru file
- * FT_FSKIP()
- * ENDDO
- * FT_FGOTOP() // go back to top
- * ? FT_FRECNO() // 1
- * $SEEALSO$
- * FT_FSELECT() FT_FUSE() FT_FRECNO() FT_FGOBOT()
- * $END$
- */
-
- void pascal ft_fgotop()
- {
-
- offset[area] = 0L;
- recno[area] = 1L;
-
- }
-
-
- /* $DOC$
- * $FUNCNAME$
- * FT_FRECNO()
- * $CATEGORY$
- * File I/O
- * $ONELINER$
- * Return the current record number of a text file
- * $SYNTAX$
- * FT_FRECNO() -> nRecNo
- * $ARGUMENTS$
- * None
- * $RETURNS$
- * The current record number of a text file or 0 if no file is open.
- * $DESCRIPTION$
- * This function returns the current record number of the file open
- * in the currently selected text file workarea.
- *
- * A text file "record" is a line of text terminated by a CRLF pair.
- * $EXAMPLES$
- * FT_FUSE( "text.c" ) // open text file
- * DO WHILE !FT_FEOF()
- * ? FT_FREADLN() // read thru file
- * FT_FSKIP()
- * ENDDO
- * FT_FGOTOP() // go back to top
- * ? FT_FRECNO() // 1
- * $SEEALSO$
- * FT_FSELECT() FT_FUSE() FT_FGOTOP() FT_FGOBOT()
- * $END$
- */
-
-
- void pascal ft_frecno()
- {
- _retnl( recno[area] );
- }
-
-
- /* $DOC$
- * $FUNCNAME$
- * FT_FGOBOT()
- * $CATEGORY$
- * File I/O
- * $ONELINER$
- * Go to the last record in a text file
- * $SYNTAX$
- * FT_FGOBOT() -> NIL
- * $ARGUMENTS$
- * None
- * $RETURNS$
- * NIL
- * $DESCRIPTION$
- * This function moves the record pointer to the last record of the
- * file in the currently selected text file workarea.
- *
- * A text file "record" is a line of text terminated by a CRLF pair.
- * $EXAMPLES$
- * // read last line
- * FT_FUSE( "text.c" )
- * FT_FGOBOT()
- * ? FT_FREADLN()
- * $SEEALSO$
- * FT_FSELECT() FT_FUSE() FT_FGOTOP() FT_FRECNO() FT_FREADLN()
- * $END$
- */
-
-
- void pascal ft_fgobot()
- {
-
- int x;
- int len, blen;
- long loc;
- int c_ptr;
- char * c, * d;
-
- if ( last_rec[area] != 0 ) {
- recno[area] = last_rec[area];
- offset[area] = last_off[area];
- }
- else {
-
- c_ptr = _vAlloc( c_size, 0 );
- d = _vLock( c_ptr );
-
-
- loc = 0L;
-
- do {
- c = d;
-
- _tlseek( handles[area], offset[area], SEEK_SET );
- len = _tread( handles[area], c, c_size );
- blen = len;
- loc = offset[area];
- do {
-
- x = _findeol( c, len );
- if ( ( x == len ) || ( ( x + 1 ) == len ) ) {
- break;
- }
- c += x + 2;
- len -= ( x + 2 );
- recno[area]++;
- loc += x + 2;
- } while ( ( len > 0 ) );
-
- offset[area] = loc;
-
- } while ( blen == c_size );
-
- offset[area] = loc;
- last_rec[area] = recno[area];
- last_off[area] = offset[area];
- _vUnLock( c_ptr );
- _vFree( c_ptr );
- }
- }
-
-
- /* $DOC$
- * $FUNCNAME$
- * FT_FSKIP()
- * $CATEGORY$
- * File I/O
- * $ONELINER$
- * Move the record pointer to a new position in a text file
- * $SYNTAX$
- * FT_FSKIP( [ <nLines> ] ) -> nLinesSkipped
- * $ARGUMENTS$
- * <nLines> is the number of lines to skip. Defaults to 1 if
- * not specified.
- * $RETURNS$
- * The number of lines actually skipped.
- * $DESCRIPTION$
- * This function moves the text file record pointer, similar to
- * the CLIPPER SKIP command.
- *
- * A text file "record" is a line of text terminated by a CRLF pair.
- * $EXAMPLES$
- * // display each record of a text file
- * FT_FUSE( "text.c" )
- * DO WHILE ! FT_FEOF()
- * ? FT_FREADLN()
- * FT_FSKIP()
- * ENDDO
- * $SEEALSO$
- * FT_FRECNO() FT_FGOTOP()
- * $END$
- */
-
- void pascal ft_fskip( void )
- {
- long recs;
-
- if ( ISNUM(1) )
- recs = _ft_skip( _parni(1) );
- else
- recs = _ft_skip(1);
-
- _retnl(recs);
- }
-
-
- static long _ft_skip( int recs )
- {
-
- int x;
- long oldpos = recno[area];
- long read_pos;
- size_t len;
- long y;
- int b_ptr = _vAlloc( b_size, 0 );
- char *b = _vLock( b_ptr );
-
- if ( recs > 0 ) {
- for (y = 0; y < recs; y++ ) {
- _tlseek( handles[area], offset[area], SEEK_SET );
- len = _tread( handles[area], b, b_size );
-
- x = _findeol( b, len );
- if (( x != (int)len ) && ( (offset[area] + (long)(x + 2)) < lastbyte[area] )) {
- isEof[area] = FALSE;
- offset[area] += (long)(x + 2);
- recno[area]++;
- }
- else
- isEof[area] = TRUE;
- }
- }
- else {
- recs = -recs;
- isEof[area] = FALSE;
-
- if ( (recno[area] - recs) >= 1 ) // <--- reversed if condition
- { // <--- added opening brace
- for (y = recs; y > 0; y-- ) {
- if ( offset[area] - b_size < 0L ) {
- read_pos = 0L;
- len = (size_t)offset[area];
- }
- else {
- read_pos = offset[area] - b_size;
- len = b_size;
- }
-
- _tlseek( handles[area], read_pos, SEEK_SET );
- len = _tread( handles[area], b, len );
-
- x = _findbol( b, len-3 ) ;
-
- if ( x < 0 ) {
- offset[area] = 0L;
- recno[area] = 1L;
- }
- else {
- offset[area] = read_pos + (long)(x + 2);
- recno[area]--;
- }
- }
- }
- else {
- offset[area] = 0L;
- recno[area] = 1L;
- }
- }
-
- _vUnLock( b_ptr );
- _vFree( b_ptr );
- return ( recno[area] - oldpos );
- }
-
-
- /* $DOC$
- * $FUNCNAME$
- * FT_FREADLN()
- * $CATEGORY$
- * File I/O
- * $ONELINER$
- * Read a line from the currently selected text file
- * $SYNTAX$
- * FT_FREADLN() -> cLine
- * $ARGUMENTS$
- * None
- * $RETURNS$
- * A string containing the current record in a text file.
- * $DESCRIPTION$
- * This function returns a line of text read from the file in the
- * currently selected text file workarea. Text lines are delimited
- * with a CRLF pair. The record pointer is not moved.
- *
- * A text file "record" is a line of text terminated by a CRLF pair.
- * $EXAMPLES$
- * // display each record of a text file
- * FT_FUSE( "text.c" )
- * DO WHILE ! FT_FEOF()
- * ? FT_FREADLN()
- * FT_FSKIP()
- * ENDDO
- * $SEEALSO$
- * FT_FUSE() FT_FWRITELN() FT_FRECNO() FT_FGOTOP()
- * $END$
- */
-
-
- void pascal ft_freadln()
- {
-
- int x;
- int read;
- int b_ptr = _vAlloc( b_size, 0 );
- char *b = _vLock( b_ptr );
-
- _tlseek( handles[area], offset[area], SEEK_SET );
- read = (int) _tread( handles[area], b, b_size );
-
- x = _findeol( b, read );
-
- _retclen( b, x );
-
- _vUnLock( b_ptr );
- _vFree( b_ptr );
- }
-
- /* $DOC$
- * $FUNCNAME$
- * FT_FDELETE()
- * $CATEGORY$
- * File I/O
- * $ONELINER$
- * Deletes a line from the currently selected text file
- * $SYNTAX$
- * FT_FDELETE( [ < nLines > ] ) -> NIL
- * $ARGUMENTS$
- * <nLines> is the number of lines to be eliminated, beginning with
- * the current record position.
- *
- * If <nLines> is omitted, the current record is deleted only.
- *
- * $RETURNS$
- * NIL
- * $DESCRIPTION$
- * This function deletes one or several lines of text from the file
- * in the currently selected text file workarea. Text lines are
- * delimited with a CRLF pair. The record pointer is not moved.
- * $EXAMPLES$
- * // delete the next 4 lines from a file
- * FT_FUSE( "test.txt" )
- *
- * FT_FDELETE( 4 )
- * $SEEALSO$
- * FT_FAPPEND() FT_FRECNO() FT_FINSERT()
- * $END$
- */
-
- void pascal ft_fdelete( )
- {
- int no_lines = ( ISNUM( 1 ) ? _parni( 1 ) : 1 );
- long read1;
- long read2;
- long end1;
- long end2;
- long cur_rec = recno[area];
- long cur_off = offset[area];
-
- int b_ptr = _vAlloc( b_size, 0 );
- int c_ptr = _vAlloc( c_size, 0 );
- int c2_ptr = _vAlloc( c_size, 0 );
- char *b = _vLock( b_ptr);
- char *c = _vLock( c_ptr);
- char *c2 = _vLock( c2_ptr);
-
- /* save address to current record ( first record to be deleted ) */
-
- end1 = offset[area] ;
-
- /* skip over deleted records, point to first 'to be retained' record */
-
- _ft_skip( no_lines ) ;
- _tlseek( handles[area], offset[area], SEEK_SET );
-
- /* save two buffers' worth of data */
-
- read1 = _tread( handles[area], c, c_size ); /* now read in a big glob */
- read2 = _tread( handles[area], c2, c_size ); /* now read in a big glob */
- end2 = offset[area] + read1 + read1;
-
- end1 = _filewrite( read1, read2, end1, end2, c, c2 ); /* loop to write */
-
- _tlseek( handles[area], end1, SEEK_SET );
- _twrite( handles[area], c, 0 );
- last_rec[area] = 0;
- lastbyte[area] = _tlseek( handles[area], 0L, SEEK_END );
- recno[area] = cur_rec;
- offset[area]= cur_off;
- _vUnLock( b_ptr );
- _vUnLock( c_ptr );
- _vUnLock( c2_ptr);
- _vFree( b_ptr );
- _vFree( c_ptr );
- _vFree( c2_ptr);
- }
-
-
- /* $DOC$
- * $FUNCNAME$
- * FT_FINSERT()
- * $CATEGORY$
- * File I/O
- * $ONELINER$
- * Inserts a line in the currently selected text file
- * $SYNTAX$
- * FT_FINSERT( [ < nLines > ] ) -> NIL
- * $ARGUMENTS$
- * <nLines> is the number of lines that should be inserted at the
- * current record position.
- *
- * If <nLines> is omitted, one record is inserted.
- *
- * $RETURNS$
- * NIL
- * $DESCRIPTION$
- * This function inserts a line of text in the file in the currently
- * selected text file workarea. Text lines are delimited with a
- * CRLF pair. The record pointer is not moved.
- *
- * An optional parameter allows multiple insertions to take place
- * with a single call to FT_FINSERT().
- *
- * A text file "record" is a line of text terminated by a CRLF pair.
- * Each line inserted with this function will be empty.
- * $EXAMPLES$
- * // add a blank line of text to a file
- * FT_FUSE( "test.txt" )
- *
- * FT_FINSERT()
- * $SEEALSO$
- * FT_FAPPEND() FT_FRECNO() FT_FDELETE() FT_FLASTREC()
- * $END$
- */
-
- void pascal ft_finsert( )
- {
- int no_lines = ( ISNUM( 1 ) ? _parni( 1 ) : 1 );
- long read1;
- long read2;
- long end1;
- long end2;
- char crlf[] = { (char)0x0D, (char)0x0A };
-
- int b_ptr = _vAlloc( b_size, 0 );
- int c_ptr = _vAlloc( c_size, 0 );
- int c2_ptr = _vAlloc( c_size, 0 );
- char *b = _vLock( b_ptr);
- char *c = _vLock( c_ptr);
- char *c2 = _vLock( c2_ptr);
-
- /* find end of first record to be replaced */
-
- end1 = _tlseek( handles[area], offset[area], SEEK_SET );
-
- /* save two buffers' worth of data from current record */
-
- read1 = _tread( handles[area], c, c_size ); /* now read in a big glob */
- read2 = _tread( handles[area], c2, c_size ); /* now read in a big glob */
- end2 = end1 + read1 + read2;
-
- /* write the new records */
-
- _tlseek( handles[area], end1, SEEK_SET );
-
-
- /* need this loop to consider that No. lines inserted may be more than
- the amount saved by the two buffers above */
-
- do {
- _twrite( handles[area], crlf, 2 );
- end1 += 2;
- } while ( --no_lines );
-
- end1 = _filewrite( read1, read2, end1, end2, c, c2 ); /* loop to write */
-
- lastbyte[area] = _tlseek( handles[area], end1, SEEK_SET );
- last_rec[area] = 0L;
- _twrite( handles[area], c, 0 );
- _vUnLock( b_ptr );
- _vUnLock( c_ptr );
- _vUnLock( c2_ptr);
- _vFree( b_ptr );
- _vFree( c_ptr );
- _vFree( c2_ptr);
- }
-
- /* $DOC$
- * $FUNCNAME$
- * FT_FAPPEND()
- * $CATEGORY$
- * File I/O
- * $ONELINER$
- * Appends a line to the currently selected text file
- * $SYNTAX$
- * FT_FAPPEND( [ < nLines > ] ) -> NIL
- * $ARGUMENTS$
- * <nLines> is the number of lines that should be appended to the
- * end of the currently selected text file.
- *
- * If <nLines> is omitted, one record is appended.
- *
- * $RETURNS$
- * NIL
- * $DESCRIPTION$
- * This function appends a line of text to the file in the currently
- * selected text file workarea. Text lines are delimited with a
- * CRLF pair. The record pointer is moved to the last appended
- * record.
- *
- * Multiple lines may be appended with one call to FT_FAPPEND().
- *
- * A text file "record" is a line of text terminated by a CRLF pair.
- * Each line appended with this function will be empty.
- *
- * NOTE: Occasionally a text file may contain a non-CRLF terminated
- * line, at the end of the file ("stragglers"). This function assumes
- * these stragglers to be the last line of the file, and begins
- * appending the new lines after this line. In other words, if the
- * last line in the text file is not terminated with a CRLF pair prior
- * to calling FT_FAPPEND(), the function will terminate that last line
- * before appending any new lines.
- *
- * $EXAMPLES$
- * // add a blank line of text to a file
- * FT_FUSE( "test.txt" )
- *
- * ?FT_FRECNO() // displays 5
- *
- * FT_FAPPEND()
- *
- * ?FT_FRECNO() // displays 6
- * $SEEALSO$
- * FT_FRECNO() FT_FDELETE() FT_FINSERT() FT_FLASTREC()
- * $END$
- */
-
- void pascal ft_fappend( )
- {
- int no_lines = ( ISNUM( 1 ) ? _parni( 1 ) : 1 );
- long read1;
- long end1;
- int x;
- char crlf[] = { (char)0x0D, (char)0x0A };
-
- int b_ptr = _vAlloc( b_size, 0 );
- char *b = _vLock( b_ptr);
-
- /* go to end of file */
-
- ft_fgobot();
-
- /* find end of record */
-
- end1 = _tlseek( handles[area], offset[area], SEEK_SET );
- read1 = _tread( handles[area], b, b_size ); /* now read in a big glob */
-
- /* determine if CRLF pair exists, if not, add one */
-
- if ( _findeol( b, (int)read1 ) == (int)read1 ) {
- _tlseek( handles[area], lastbyte[area], SEEK_SET );
- _twrite( handles[area], crlf, 2 );
- no_lines--;
- }
-
- /* loop to write new lines */
-
- for ( x = 0; x < no_lines; x ++ ) {
- _twrite( handles[area], crlf, 2 );
- }
- _vUnLock( b_ptr );
- _vFree( b_ptr );
- last_rec[area] = 0L;
- ft_fgobot();
- }
-
- /* $DOC$
- * $FUNCNAME$
- * FT_FWRITELN()
- * $CATEGORY$
- * File I/O
- * $ONELINER$
- * Write a line to the currently selected text file
- * $SYNTAX$
- * FT_FWRITELN( < cData >, [ < lInsert > ] ) -> NIL
- * $ARGUMENTS$
- * <cData> is a string of data to write to the file at the current
- * record position.
- *
- * <lInsert> is a logical indicating whether the contents
- * of the current record are to be preserved, that is, if lInsert
- * evaluates to .T., the a new record is inserted at the current
- * position. The current record then is pushed down to FT_FRECNO()+1.
- *
- * If lInsert is .F. or omitted, the current record is replaced by
- * cData.
- *
- * $RETURNS$
- * NIL
- * $DESCRIPTION$
- * This function writes a line of text to the file in the currently
- * selected text file workarea. Text lines are delimited with a
- * CRLF pair. The record pointer is not moved.
- *
- * The contents of the current record are updated to reflect the new
- * new line written, unless the Insert option is selected.
- *
- * Writing a null string has the effect of clearing the current line
- * if in overstrike mode, else inserting a new line (same as
- * FT_FINSERT()).
- *
- * A text file "record" is a line of text terminated by a CRLF pair.
- * $EXAMPLES$
- * // write a line of text to a file
- * FT_FUSE( "config.sys" )
- * DO WHILE UPPER( FT_FREADLN() ) != "FILES=" .AND. !F_FEOF()
- * FT_FSKIP()
- * ENDDO
- *
- * FT_FWRITELN( "FILES=30", FT_FEOF() )
- * $SEEALSO$
- * FT_FREADLN() FT_FRECNO() FT_FINSERT() FT_FDELETE()
- * $END$
- */
-
- void pascal ft_fwritel( )
- {
- int x;
- char *buf = _parc( 1 );
- int buf_len = _parclen( 1 );
- long read1;
- long read2;
- long end1;
- long end2;
-
- int b_ptr = _vAlloc( b_size, 0 );
- int c_ptr = _vAlloc( c_size, 0 );
- int c2_ptr = _vAlloc( c_size, 0 );
- char *b = _vLock( b_ptr);
- char *c = _vLock( c_ptr);
- char *c2 = _vLock( c2_ptr);
-
- /* find end of first record to be replaced */
-
- end1 = _tlseek( handles[area], offset[area], SEEK_SET );
- read1 = _tread ( handles[area], b, b_size );
-
- /* if insert mode, leave pointer alone and skip below */
-
- if ( ISNUM(2) && _parl( 2 ) ) {
- x = 0;
- }
- else {
-
- x = _findeol( b, (int)read1 );
- }
-
- /* save two buffers' worth of data from end of record on */
-
- _tlseek( handles[area], end1 + x, SEEK_SET );
- read1 = _tread( handles[area], c, c_size ); /* now read in a big glob */
- read2 = _tread( handles[area], c2, c_size ); /* now read in a big glob */
- end2 = end1 + read1 + read1 + x;
-
- /* write the new record */
-
- _tlseek( handles[area], end1, SEEK_SET );
- _twrite( handles[area], buf, buf_len );
- end1 += (long)buf_len;
-
- end1 = _filewrite( read1, read2, end1, end2, c, c2 ); /* loop to write */
-
- _tlseek( handles[area], end1, SEEK_SET );
- _twrite( handles[area], c, 0 );
- last_rec[area] = 0;
- lastbyte[area] = _tlseek( handles[area], 0L, SEEK_END );
- _vUnLock( b_ptr );
- _vUnLock( c_ptr );
- _vUnLock( c2_ptr);
- _vFree( b_ptr );
- _vFree( c_ptr );
- _vFree( c2_ptr);
- }
-
- /* $DOC$
- * $FUNCNAME$
- * FT_FLASTREC()
- * $CATEGORY$
- * File I/O
- * $ONELINER$
- * Determine the no. of records in the currently selected text file
- * $SYNTAX$
- * FT_FLASTREC() -> nLastRecordNum
- * $ARGUMENTS$
- * None
- * $RETURNS$
- * An integer containing the number of records in the text file in
- * the currently selected text file workarea, or zero if no file
- * is currently open in the workarea.
- * $DESCRIPTION$
- * This function returns the number of the last record in a text file.
- *
- * A text file "record" is a line of text terminated by a CRLF pair.
- * $EXAMPLES$
- * FT_FUSE( "text.c" )
- * ? FT_FLASTREC()
- * $SEEALSO$
- * FT_FUSE() FT_FRECNO()
- * $END$
- */
-
- void pascal ft_flastre( )
- {
-
- long old_rec;
- long old_offset;
-
- old_rec = recno[area];
- old_offset = offset[area];
-
- ft_fgobot();
- _retnl( last_rec[area] );
-
- recno[area] = old_rec;
- offset[area] = old_offset;
-
- }
-
- /* $DOC$
- * $FUNCNAME$
- * FT_FEOF()
- * $CATEGORY$
- * File I/O
- * $ONELINER$
- * Determine when end of text file is encountered
- * $SYNTAX$
- * FT_FEOF() -> lResult
- * $ARGUMENTS$
- * None
- * $RETURNS$
- * .T. if an attempt was made to skip past the last record of
- * the currently selected text file, otherwise .F.
- * $DESCRIPTION$
- * This function is similar to the CLIPPER Eof() function.
- *
- * A text file "record" is a line of text terminated by a CRLF pair.
- * $EXAMPLES$
- * FT_FUSE( "FTTEXT.C" )
- *
- * ? FT_FEOF() // .F.
- * FT_FSKIP()
- * ? FT_FEOF() // .T.
- * $SEEALSO$
- * FT_FUSE() FT_FSKIP()
- * $END$
- */
-
-
- void pascal ft_feof()
- {
- _retl( isEof[area] );
- }
-
-
- /* $DOC$
- * $FUNCNAME$
- * FT_FGOTO()
- * $CATEGORY$
- * File I/O
- * $ONELINER$
- * Move record pointer to specific record in a text file
- * $SYNTAX$
- * FT_FGOTO( nLine ) -> NIL
- * $ARGUMENTS$
- * <nLine> is the record number to go to.
- * $RETURNS$
- * NIL
- * $DESCRIPTION$
- * This function moves the record pointer to a specific record
- * in the file in the currently selected text file workarea. If
- * the record number requested is greater than the number of records
- * in the file, the record pointer will be positioned at the last
- * record.
- *
- * A text file "record" is a line of text terminated by a CRLF pair.
- * $EXAMPLES$
- * // read 5th line of text from file
- * FT_FUSE( "FTTEXT.C" )
- * FT_FGOTO(5)
- * cText := FT_FREADLN()
- * $SEEALSO$
- * FT_FRECNO() FT_FGOTOP() FT_FREADLN()
- * $END$
- */
-
- void pascal ft_fgoto()
- {
-
- long target;
- long last;
-
- target = _parnl(1);
- last = 0;
-
- if ( recno[area] > target ) {
- while ( recno[area] != target ) {
- last = recno[area];
- _ft_skip(-1);
- if ( recno[area] == last )
- break;
- }
- }
- else {
- while ( recno[area] != target ) {
- last = recno[area];
- _ft_skip(1);
- if ( recno[area] == last )
- break;
- }
- }
- }
-
- /*----------------------------------------------------------------------
-
- _findeol() - In-line assembler routine to parse a buffer
- for a CRLF pair
-
- ------------------------------------------------------------------------*/
- static int _findeol( char *buf, int buf_len )
- {
- _asm /* for TASM omit leading underscore */
- {
- push di ; save flags and registers
- push es
- pushf
- cld ; move forward
- les di, buf ; point to buffer
- mov bx, di ; save buffer start for offset calc later
- mov cx, buf_len ; scan entire buffer
- mov al, 13
- _feol1:repne scasb ; look for a CR
- jcxz _feolerr ; no find, return entire buffer
- cmp es:[di], 10 ; got a CRLF pair?
- jne _feol2
- dec di ; yes, point to CR and return
- jmp _feoldone
- _feol2:cmp es:[di-2], 10 ; nope, check for LFCR pair
- jne _feol1
- dec di ; yes, point to LF & return
- dec di
- jmp _feoldone ; otherwise keep looking
-
- _feolerr:
- mov di, bx ; on no find return entire length of buffer
- add di, buf_len ; but truncate any LF or EOF markers
- cmp byte ptr es:[di-1], 1Ah ; test for end of file marker
- je _feolerr1
- cmp byte ptr es:[di-1], 0Ah ; test for an errant LF
- jne _feoldone
- _feolerr1:
- dec di
- _feoldone:
- mov ax, di ; subtract current pointer pos from start to
- sub ax, bx ; learn offset within buffer
- popf
- pop es
- pop di
- }
- } /* end _findeol() */
-
-
- /*----------------------------------------------------------------------
-
- _findbol() - In-line assembler routine to parse a buffer
- for a CRLF pair
-
- ------------------------------------------------------------------------*/
- static int _findbol( char *buf, int buf_len )
- {
- _asm /* for TurboC, use "asm" */
- {
- push di ; save flags and registers
- push es
- pushf
- std ; move back'rdz
- les di, buf ; point to buffer tail
- mov bx, di ; save buffer start for offset calc later
- add di, buf_len
- mov cx, buf_len ; scan entire buffer
- mov al, 13
- _fbol1:repne scasb ; look for a CR
- jcxz _fbolerr ; no find, return entire buffer
- cmp es:[di], 10 ; got a LFCR pair?
- je _fboldone ; yup, round'm up and head'm home, boys
- cmp es:[di+2], 10 ; check for CRLF pair
- jne _fbol1
- inc di ; yes, point to CR
- jmp _fboldone ; otherwise keep looking
-
- _fbolerr:
- mov di, bx ; on no find return length of buffer
- _fboldone:
- mov ax, di ; subtract current pointer pos from start to
- sub ax, bx ; learn offset within buffer
- popf
- pop es
- pop di
- }
- } /* end _findbol() */
-
- /*----------------------------------------------------------------------
-
- _filewrite()- moves text up or down in a file after an insert or delete
-
- ------------------------------------------------------------------------*/
- static long _filewrite( long read1, long read2, long end1, long end2,
- char *c, char *c2 )
- {
- do {
- _tlseek( handles[area], end1, SEEK_SET );
- _twrite( handles[area], c, (int)read1 );
- end1 += read1 ; /* end1 should now point to eof */
-
- if ( read2 == 0L ) {
- break;
- }
-
- _tlseek( handles[area], end2, SEEK_SET );
- read1 = _tread( handles[area], c, c_size );
- end2 += read1;
-
- _tlseek( handles[area], end1, SEEK_SET );
- _twrite( handles[area], c2, (int)read2 );
- end1 += read2 ;
-
- _tlseek( handles[area], end2, SEEK_SET );
- read2 = _tread( handles[area], c2, c_size ); /* now read in a big glob */
- end2 += read2 ;
-
- } while ( read1 > 0 );
-
- return ( end1 );
-
- } /* end _filewrite() */
-
- /* fttext.c eof */